1 /* resres.c: read_res_file and write_res_file implementation for windres.
2 Copyright 1998, 1999, 2001, 2002, 2007 Free Software Foundation, Inc.
3 Written by Anders Norlander <anorland@hem2.passagen.se>.
5 This file is part of GNU Binutils.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 /* FIXME: This file does not work correctly in a cross configuration.
23 It assumes that it can use fread and fwrite to read and write
24 integers. It does no swapping. */
28 #include "libiberty.h"
37 unsigned long data_size;
38 unsigned long header_size;
41 static void write_res_directory
42 PARAMS ((const struct res_directory *,
43 const struct res_id *, const struct res_id *,
45 static void write_res_resource
46 PARAMS ((const struct res_id *, const struct res_id *,
47 const struct res_resource *, int *));
48 static void write_res_bin
49 PARAMS ((const struct res_resource *, const struct res_id *,
50 const struct res_id *, const struct res_res_info *));
52 static void write_res_id PARAMS ((const struct res_id *));
53 static void write_res_info PARAMS ((const struct res_res_info *));
54 static void write_res_data PARAMS ((const void *, size_t, int));
55 static void write_res_header
56 PARAMS ((unsigned long, const struct res_id *, const struct res_id *,
57 const struct res_res_info *));
59 static int read_resource_entry PARAMS ((void));
60 static void read_res_data PARAMS ((void *, size_t, int));
61 static void read_res_id PARAMS ((struct res_id *));
62 static unichar *read_unistring PARAMS ((int *));
63 static void skip_null_resource PARAMS ((void));
65 static unsigned long get_id_size PARAMS ((const struct res_id *));
66 static void res_align_file PARAMS ((void));
70 PARAMS ((struct res_resource *, const struct res_id *,
71 const struct res_id *, int, int));
75 PARAMS ((struct res_directory **, struct res_resource *,
76 int, const struct res_id *, int));
78 static struct res_directory *resources = NULL;
81 static const char *filename;
83 extern char *program_name;
85 /* Read resource file */
86 struct res_directory *
91 fres = fopen (filename, "rb");
93 fatal ("can't open `%s' for output: %s", filename, strerror (errno));
95 skip_null_resource ();
97 while (read_resource_entry ())
105 /* Write resource file */
107 write_res_file (fn, resdir)
109 const struct res_directory *resdir;
112 static const unsigned char sign[] =
113 {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
114 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
121 fres = fopen (filename, "wb");
123 fatal ("can't open `%s' for output: %s", filename, strerror (errno));
125 /* Write 32 bit resource signature */
126 write_res_data (sign, sizeof (sign), 1);
128 /* write resources */
131 write_res_directory (resdir, (const struct res_id *) NULL,
132 (const struct res_id *) NULL, &language, 1);
134 /* end file on DWORD boundary */
137 write_res_data (sign, fpos % 4, 1);
142 /* Read a resource entry, returns 0 when all resources are read */
144 read_resource_entry (void)
148 struct res_res_info resinfo;
149 struct res_hdr reshdr;
153 struct res_resource *r;
158 if (fread (&reshdr, sizeof (reshdr), 1, fres) != 1)
161 /* read resource type */
163 /* read resource id */
168 /* Read additional resource header */
169 read_res_data (&resinfo.version, sizeof (resinfo.version), 1);
170 read_res_data (&resinfo.memflags, sizeof (resinfo.memflags), 1);
171 read_res_data (&resinfo.language, sizeof (resinfo.language), 1);
172 read_res_data (&version, sizeof (version), 1);
173 read_res_data (&resinfo.characteristics, sizeof (resinfo.characteristics), 1);
177 /* Allocate buffer for data */
178 buff = res_alloc (reshdr.data_size);
180 read_res_data (buff, reshdr.data_size, 1);
181 /* Convert binary data to resource */
182 r = bin_to_res (type, buff, reshdr.data_size, 0);
183 r->res_info = resinfo;
184 /* Add resource to resource directory */
185 res_add_resource (r, &type, &name, resinfo.language, 0);
190 /* write resource directory to binary resource file */
192 write_res_directory (rd, type, name, language, level)
193 const struct res_directory *rd;
194 const struct res_id *type;
195 const struct res_id *name;
199 const struct res_entry *re;
201 for (re = rd->entries; re != NULL; re = re->next)
206 /* If we're at level 1, the key of this resource is the
207 type. This normally duplicates the information we have
208 stored with the resource itself, but we need to remember
209 the type if this is a user define resource type. */
214 /* If we're at level 2, the key of this resource is the name
215 we are going to use in the rc printout. */
220 /* If we're at level 3, then this key represents a language.
221 Use it to update the current language. */
223 && re->id.u.id != (unsigned long) *language
224 && (re->id.u.id & 0xffff) == re->id.u.id)
226 *language = re->id.u.id;
235 write_res_directory (re->u.dir, type, name, language, level + 1);
240 /* This is the normal case: the three levels are
241 TYPE/NAME/LANGUAGE. NAME will have been set at level
242 2, and represents the name to use. We probably just
243 set LANGUAGE, and it will probably match what the
244 resource itself records if anything. */
245 write_res_resource (type, name, re->u.res, language);
249 fprintf (stderr, "// Resource at unexpected level %d\n", level);
250 write_res_resource (type, (struct res_id *) NULL, re->u.res,
259 write_res_resource (type, name, res, language)
260 const struct res_id *type;
261 const struct res_id *name;
262 const struct res_resource *res;
263 int *language ATTRIBUTE_UNUSED;
272 case RES_TYPE_ACCELERATOR:
276 case RES_TYPE_BITMAP:
280 case RES_TYPE_CURSOR:
284 case RES_TYPE_GROUP_CURSOR:
285 rt = RT_GROUP_CURSOR;
288 case RES_TYPE_DIALOG:
296 case RES_TYPE_FONTDIR:
304 case RES_TYPE_GROUP_ICON:
312 case RES_TYPE_MESSAGETABLE:
313 rt = RT_MESSAGETABLE;
316 case RES_TYPE_RCDATA:
320 case RES_TYPE_STRINGTABLE:
324 case RES_TYPE_USERDATA:
328 case RES_TYPE_VERSIONINFO:
335 && (type->named || type->u.id != (unsigned long) rt))
337 fprintf (stderr, "// Unexpected resource type mismatch: ");
338 res_id_print (stderr, *type, 1);
339 fprintf (stderr, " != %d", rt);
343 write_res_bin (res, type, name, &res->res_info);
347 /* Write a resource in binary resource format */
349 write_res_bin (res, type, name, resinfo)
350 const struct res_resource *res;
351 const struct res_id *type;
352 const struct res_id *name;
353 const struct res_res_info *resinfo;
355 unsigned long datasize = 0;
356 const struct bindata *bin_rep, *data;
358 bin_rep = res_to_bin (res, 0);
359 for (data = bin_rep; data != NULL; data = data->next)
360 datasize += data->length;
362 write_res_header (datasize, type, name, resinfo);
364 for (data = bin_rep; data != NULL; data = data->next)
365 write_res_data (data->data, data->length, 1);
368 /* Get number of bytes needed to store an id in binary format */
371 const struct res_id *id;
374 return sizeof (unichar) * (id->u.n.length + 1);
376 return sizeof (unichar) * 2;
379 /* Write a resource header */
381 write_res_header (datasize, type, name, resinfo)
382 unsigned long datasize;
383 const struct res_id *type;
384 const struct res_id *name;
385 const struct res_res_info *resinfo;
387 struct res_hdr reshdr;
388 reshdr.data_size = datasize;
389 reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
391 reshdr.header_size = (reshdr.header_size + 3) & ~3;
394 write_res_data (&reshdr, sizeof (reshdr), 1);
400 write_res_info (resinfo);
405 /* Write data to file, abort on failure */
407 write_res_data (data, size, count)
412 if ((size_t) fwrite (data, size, count, fres) != (size_t) count)
413 fatal ("%s: could not write to file", filename);
416 /* Read data from file, abort on failure */
418 read_res_data (data, size, count)
423 if (fread (data, size, count, fres) != (size_t) count)
424 fatal ("%s: unexpected end of file", filename);
427 /* Write a resource id */
430 const struct res_id *id;
434 unsigned long len = id->u.n.length;
435 unichar null_term = 0;
436 write_res_data (id->u.n.name, len * sizeof (unichar), 1);
437 write_res_data (&null_term, sizeof (null_term), 1);
441 unsigned short i = 0xFFFF;
442 write_res_data (&i, sizeof (i), 1);
444 write_res_data (&i, sizeof (i), 1);
448 /* Write resource info */
450 write_res_info (info)
451 const struct res_res_info *info;
453 write_res_data (&info->version, sizeof (info->version), 1);
454 write_res_data (&info->memflags, sizeof (info->memflags), 1);
455 write_res_data (&info->language, sizeof (info->language), 1);
456 write_res_data (&info->version, sizeof (info->version), 1);
457 write_res_data (&info->characteristics, sizeof (info->characteristics), 1);
460 /* read a resource identifier */
466 unichar *id_s = NULL;
469 read_res_data (&ord, sizeof (ord), 1);
470 if (ord == 0xFFFF) /* an ordinal id */
472 read_res_data (&ord, sizeof (ord), 1);
479 if (fseek (fres, -sizeof (ord), SEEK_CUR) != 0)
480 fatal ("%s: %s: could not seek in file", program_name, filename);
481 id_s = read_unistring (&len);
483 id->u.n.length = len;
488 /* Read a null terminated UNICODE string */
501 /* there are hardly any names longer than 256 characters */
502 p = s = (unichar *) xmalloc (sizeof (unichar) * 256);
505 read_res_data (&c, sizeof (c), 1);
515 /* align file on DWORD boundary */
517 res_align_file (void)
519 int pos = ftell (fres);
520 int skip = ((pos + 3) & ~3) - pos;
521 if (fseek (fres, skip, SEEK_CUR) != 0)
522 fatal ("%s: %s: unable to align file", program_name, filename);
525 /* Check if file is a win32 binary resource file, if so
526 skip past the null resource. Returns 0 if successful, -1 on
530 skip_null_resource (void)
532 struct res_hdr reshdr =
534 read_res_data (&reshdr, sizeof (reshdr), 1);
535 if ((reshdr.data_size != 0) || (reshdr.header_size != 0x20))
538 /* Subtract size of HeaderSize and DataSize */
539 if (fseek (fres, reshdr.header_size - 8, SEEK_CUR) != 0)
545 fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
550 /* Add a resource to resource directory */
552 res_add_resource (r, type, id, language, dupok)
553 struct res_resource *r;
554 const struct res_id *type;
555 const struct res_id *id;
564 a[2].u.id = language;
565 res_append_resource (&resources, r, 3, a, dupok);
568 /* Append a resource to resource directory.
569 This is just copied from define_resource
570 and modified to add an existing resource.
573 res_append_resource (resources, resource, cids, ids, dupok)
574 struct res_directory **resources;
575 struct res_resource *resource;
577 const struct res_id *ids;
580 struct res_entry *re = NULL;
584 for (i = 0; i < cids; i++)
586 struct res_entry **pp;
588 if (*resources == NULL)
590 static unsigned long timeval;
592 /* Use the same timestamp for every resource created in a
595 timeval = time (NULL);
597 *resources = ((struct res_directory *)
598 res_alloc (sizeof **resources));
599 (*resources)->characteristics = 0;
600 (*resources)->time = timeval;
601 (*resources)->major = 0;
602 (*resources)->minor = 0;
603 (*resources)->entries = NULL;
606 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
607 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
614 re = (struct res_entry *) res_alloc (sizeof *re);
635 fprintf (stderr, "%s: ", program_name);
636 res_ids_print (stderr, i, ids);
637 fprintf (stderr, ": expected to be a directory\n");
641 resources = &re->u.dir;
647 fprintf (stderr, "%s: ", program_name);
648 res_ids_print (stderr, cids, ids);
649 fprintf (stderr, ": expected to be a leaf\n");
653 if (re->u.res != NULL)
658 fprintf (stderr, "%s: warning: ", program_name);
659 res_ids_print (stderr, cids, ids);
660 fprintf (stderr, ": duplicate value\n");
663 re->u.res = resource;