1 /* resres.c: read_res_file and write_res_file implementation for windres.
3 Copyright 1997, 1998 Free Software Foundation, Inc.
4 Written by Anders Norlander <anorland@hem2.passagen.se>.
6 This file is part of GNU Binutils.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31 unsigned long data_size;
32 unsigned long header_size;
35 static void write_res_directory
36 PARAMS ((const struct res_directory *,
37 const struct res_id *, const struct res_id *,
39 static void write_res_resource
40 PARAMS ((const struct res_id *, const struct res_id *,
41 const struct res_resource *, int *));
42 static void write_res_bin
43 PARAMS ((const struct res_resource *, const struct res_id *,
44 const struct res_id *, const struct res_res_info *));
46 static void write_res_id PARAMS ((const struct res_id *));
47 static void write_res_info PARAMS ((const struct res_res_info *));
48 static void write_res_data PARAMS ((const void *, size_t, int));
49 static void write_res_header
50 PARAMS ((unsigned long, const struct res_id *, const struct res_id *,
51 const struct res_res_info *));
53 static int read_resource_entry PARAMS ((void));
54 static void read_res_data PARAMS ((void *, size_t, int));
55 static void read_res_id PARAMS ((struct res_id *));
56 static unichar *read_unistring PARAMS ((int *));
57 static void skip_null_resource PARAMS ((void));
59 static unsigned long get_id_size PARAMS ((const struct res_id *));
60 static void res_align_file PARAMS ((void));
64 PARAMS ((struct res_resource *, const struct res_id *,
65 const struct res_id *, int, int));
69 PARAMS ((struct res_directory **, struct res_resource *,
70 int, const struct res_id *, int));
72 static struct res_directory *resources = NULL;
75 static const char *filename;
77 extern char *program_name;
79 /* Read resource file */
80 struct res_directory *
85 fres = fopen (filename, "rb");
87 fatal ("can't open `%s' for output: %s", filename, strerror (errno));
89 skip_null_resource ();
91 while (read_resource_entry ())
99 /* Write resource file */
101 write_res_file (fn, resdir)
103 const struct res_directory *resdir;
106 static const unsigned char sign[] =
107 {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
108 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
117 fres = fopen (filename, "wb");
119 fatal ("can't open `%s' for output: %s", filename, strerror (errno));
121 /* Write 32 bit resource signature */
122 write_res_data (sign, sizeof (sign), 1);
124 /* write resources */
127 write_res_directory (resdir, (const struct res_id *) NULL,
128 (const struct res_id *) NULL, &language, 1);
130 /* end file on DWORD boundary */
133 write_res_data (sign, fpos % 4, 1);
138 /* Read a resource entry, returns 0 when all resources are read */
140 read_resource_entry (void)
144 struct res_res_info resinfo;
145 struct res_hdr reshdr;
151 struct res_resource *r;
156 if (fread (&reshdr, sizeof (reshdr), 1, fres) != 1)
159 /* read resource type */
161 /* read resource id */
166 /* Read additional resource header */
167 read_res_data (&resinfo.version, sizeof (resinfo.version), 1);
168 read_res_data (&resinfo.memflags, sizeof (resinfo.memflags), 1);
169 read_res_data (&resinfo.language, sizeof (resinfo.language), 1);
170 read_res_data (&version, sizeof (version), 1);
171 read_res_data (&resinfo.characteristics, sizeof (resinfo.characteristics), 1);
175 /* Allocate buffer for data */
176 buff = res_alloc (reshdr.data_size);
178 read_res_data (buff, reshdr.data_size, 1);
179 /* Convert binary data to resource */
180 r = bin_to_res (type, buff, reshdr.data_size, 0);
181 r->res_info = resinfo;
182 /* Add resource to resource directory */
183 res_add_resource (r, &type, &name, resinfo.language, 0);
188 /* write resource directory to binary resource file */
190 write_res_directory (rd, type, name, language, level)
191 const struct res_directory *rd;
192 const struct res_id *type;
193 const struct res_id *name;
197 const struct res_entry *re;
199 for (re = rd->entries; re != NULL; re = re->next)
204 /* If we're at level 1, the key of this resource is the
205 type. This normally duplicates the information we have
206 stored with the resource itself, but we need to remember
207 the type if this is a user define resource type. */
212 /* If we're at level 2, the key of this resource is the name
213 we are going to use in the rc printout. */
218 /* If we're at level 3, then this key represents a language.
219 Use it to update the current language. */
221 && re->id.u.id != *language
222 && (re->id.u.id & 0xffff) == re->id.u.id)
224 *language = re->id.u.id;
233 write_res_directory (re->u.dir, type, name, language, level + 1);
238 /* This is the normal case: the three levels are
239 TYPE/NAME/LANGUAGE. NAME will have been set at level
240 2, and represents the name to use. We probably just
241 set LANGUAGE, and it will probably match what the
242 resource itself records if anything. */
243 write_res_resource (type, name, re->u.res, language);
247 fprintf (stderr, "// Resource at unexpected level %d\n", level);
248 write_res_resource (type, (struct res_id *) NULL, re->u.res,
257 write_res_resource (type, name, res, language)
258 const struct res_id *type;
259 const struct res_id *name;
260 const struct res_resource *res;
270 case RES_TYPE_ACCELERATOR:
274 case RES_TYPE_BITMAP:
278 case RES_TYPE_CURSOR:
282 case RES_TYPE_GROUP_CURSOR:
283 rt = RT_GROUP_CURSOR;
286 case RES_TYPE_DIALOG:
294 case RES_TYPE_FONTDIR:
302 case RES_TYPE_GROUP_ICON:
310 case RES_TYPE_MESSAGETABLE:
311 rt = RT_MESSAGETABLE;
314 case RES_TYPE_RCDATA:
318 case RES_TYPE_STRINGTABLE:
322 case RES_TYPE_USERDATA:
326 case RES_TYPE_VERSIONINFO:
333 && (type->named || type->u.id != rt))
335 fprintf (stderr, "// Unexpected resource type mismatch: ");
336 res_id_print (stderr, *type, 1);
337 fprintf (stderr, " != %d", rt);
341 write_res_bin (res, type, name, &res->res_info);
345 /* Write a resource in binary resource format */
347 write_res_bin (res, type, name, resinfo)
348 const struct res_resource *res;
349 const struct res_id *type;
350 const struct res_id *name;
351 const struct res_res_info *resinfo;
353 unsigned long datasize = 0;
354 const struct bindata *bin_rep, *data;
356 bin_rep = res_to_bin (res, 0);
357 for (data = bin_rep; data != NULL; data = data->next)
358 datasize += data->length;
360 write_res_header (datasize, type, name, resinfo);
362 for (data = bin_rep; data != NULL; data = data->next)
363 write_res_data (data->data, data->length, 1);
366 /* Get number of bytes needed to store an id in binary format */
369 const struct res_id *id;
372 return sizeof (unichar) * (id->u.n.length + 1);
374 return sizeof (unichar) * 2;
377 /* Write a resource header */
379 write_res_header (datasize, type, name, resinfo)
380 unsigned long datasize;
381 const struct res_id *type;
382 const struct res_id *name;
383 const struct res_res_info *resinfo;
385 struct res_hdr reshdr;
386 reshdr.data_size = datasize;
387 reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
390 write_res_data (&reshdr, sizeof (reshdr), 1);
396 write_res_info (resinfo);
401 /* Write data to file, abort on failure */
403 write_res_data (data, size, count)
408 if (fwrite (data, size, count, fres) != count)
409 fatal ("%s: %s: could not write to file", program_name, filename);
412 /* Read data from file, abort on failure */
414 read_res_data (data, size, count)
419 if (fread (data, size, count, fres) != count)
420 fatal ("%s: %s: unexpected end of file", program_name, filename);
423 /* Write a resource id */
426 const struct res_id *id;
430 unsigned long len = id->u.n.length;
431 unichar null_term = 0;
432 write_res_data (id->u.n.name, len * sizeof (unichar), 1);
433 write_res_data (&null_term, sizeof (null_term), 1);
437 unsigned short i = 0xFFFF;
438 write_res_data (&i, sizeof (i), 1);
440 write_res_data (&i, sizeof (i), 1);
444 /* Write resource info */
446 write_res_info (info)
447 const struct res_res_info *info;
449 write_res_data (&info->version, sizeof (info->version), 1);
450 write_res_data (&info->memflags, sizeof (info->memflags), 1);
451 write_res_data (&info->language, sizeof (info->language), 1);
452 write_res_data (&info->version, sizeof (info->version), 1);
453 write_res_data (&info->characteristics, sizeof (info->characteristics), 1);
456 /* read a resource identifier */
462 unichar *id_s = NULL;
465 read_res_data (&ord, sizeof (ord), 1);
466 if (ord == 0xFFFF) /* an ordinal id */
468 read_res_data (&ord, sizeof (ord), 1);
475 if (fseek (fres, -sizeof (ord), SEEK_CUR) != 0)
476 fatal ("%s: %s: could not seek in file", program_name, filename);
477 id_s = read_unistring (&len);
479 id->u.n.length = len;
484 /* Read a null terminated UNICODE string */
498 /* there are hardly any names longer than 256 characters */
499 p = s = (unichar *) xmalloc (sizeof (unichar) * 256);
502 read_res_data (&c, sizeof (c), 1);
512 /* align file on DWORD boundary */
514 res_align_file (void)
516 if (fseek (fres, ftell (fres) % 4, SEEK_CUR) != 0)
517 fatal ("%s: %s: unable to align file", program_name, filename);
520 /* Check if file is a win32 binary resource file, if so
521 skip past the null resource. Returns 0 if successful, -1 on
525 skip_null_resource (void)
527 struct res_hdr reshdr =
529 read_res_data (&reshdr, sizeof (reshdr), 1);
530 if ((reshdr.data_size != 0) || (reshdr.header_size != 0x20))
533 /* Subtract size of HeaderSize and DataSize */
534 if (fseek (fres, reshdr.header_size - 8, SEEK_CUR) != 0)
540 fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
545 /* Add a resource to resource directory */
547 res_add_resource (r, type, id, language, dupok)
548 struct res_resource *r;
549 const struct res_id *type;
550 const struct res_id *id;
559 a[2].u.id = language;
560 res_append_resource (&resources, r, 3, a, dupok);
563 /* Append a resource to resource directory.
564 This is just copied from define_resource
565 and modified to add an existing resource.
568 res_append_resource (resources, resource, cids, ids, dupok)
569 struct res_directory **resources;
570 struct res_resource *resource;
572 const struct res_id *ids;
575 struct res_entry *re = NULL;
579 for (i = 0; i < cids; i++)
581 struct res_entry **pp;
583 if (*resources == NULL)
585 static unsigned long timeval;
587 /* Use the same timestamp for every resource created in a
590 timeval = time (NULL);
592 *resources = ((struct res_directory *)
593 res_alloc (sizeof **resources));
594 (*resources)->characteristics = 0;
595 (*resources)->time = timeval;
596 (*resources)->major = 0;
597 (*resources)->minor = 0;
598 (*resources)->entries = NULL;
601 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
602 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
609 re = (struct res_entry *) res_alloc (sizeof *re);
630 fprintf (stderr, "%s: ", program_name);
631 res_ids_print (stderr, i, ids);
632 fprintf (stderr, ": expected to be a directory\n");
636 resources = &re->u.dir;
642 fprintf (stderr, "%s: ", program_name);
643 res_ids_print (stderr, cids, ids);
644 fprintf (stderr, ": expected to be a leaf\n");
648 if (re->u.res != NULL)
653 fprintf (stderr, "%s: warning: ", program_name);
654 res_ids_print (stderr, cids, ids);
655 fprintf (stderr, ": duplicate value\n");
658 re->u.res = resource;