Initial revision
[binutils.git] / binutils / resres.c
blob39264f445a22749999ffaa1ed29bdfc5edb1ba21
1 /* resres.c: read_res_file and write_res_file implementation for windres.
3 Copyright 1998, 1999 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
21 02111-1307, USA. */
23 #include "bfd.h"
24 #include "bucomm.h"
25 #include "libiberty.h"
26 #include "windres.h"
28 #include <assert.h>
29 #include <time.h>
31 struct res_hdr
33 unsigned long data_size;
34 unsigned long header_size;
37 static void write_res_directory
38 PARAMS ((const struct res_directory *,
39 const struct res_id *, const struct res_id *,
40 int *, int));
41 static void write_res_resource
42 PARAMS ((const struct res_id *, const struct res_id *,
43 const struct res_resource *, int *));
44 static void write_res_bin
45 PARAMS ((const struct res_resource *, const struct res_id *,
46 const struct res_id *, const struct res_res_info *));
48 static void write_res_id PARAMS ((const struct res_id *));
49 static void write_res_info PARAMS ((const struct res_res_info *));
50 static void write_res_data PARAMS ((const void *, size_t, int));
51 static void write_res_header
52 PARAMS ((unsigned long, const struct res_id *, const struct res_id *,
53 const struct res_res_info *));
55 static int read_resource_entry PARAMS ((void));
56 static void read_res_data PARAMS ((void *, size_t, int));
57 static void read_res_id PARAMS ((struct res_id *));
58 static unichar *read_unistring PARAMS ((int *));
59 static void skip_null_resource PARAMS ((void));
61 static unsigned long get_id_size PARAMS ((const struct res_id *));
62 static void res_align_file PARAMS ((void));
64 static void
65 res_add_resource
66 PARAMS ((struct res_resource *, const struct res_id *,
67 const struct res_id *, int, int));
69 void
70 res_append_resource
71 PARAMS ((struct res_directory **, struct res_resource *,
72 int, const struct res_id *, int));
74 static struct res_directory *resources = NULL;
76 static FILE *fres;
77 static const char *filename;
79 extern char *program_name;
81 /* Read resource file */
82 struct res_directory *
83 read_res_file (fn)
84 const char *fn;
86 filename = fn;
87 fres = fopen (filename, "rb");
88 if (fres == NULL)
89 fatal ("can't open `%s' for output: %s", filename, strerror (errno));
91 skip_null_resource ();
93 while (read_resource_entry ())
96 fclose (fres);
98 return resources;
101 /* Write resource file */
102 void
103 write_res_file (fn, resdir)
104 const char *fn;
105 const struct res_directory *resdir;
107 int language;
108 static const unsigned char sign[] =
109 {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
110 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
113 long fpos;
115 filename = fn;
117 fres = fopen (filename, "wb");
118 if (fres == NULL)
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 */
126 language = -1;
127 write_res_directory (resdir, (const struct res_id *) NULL,
128 (const struct res_id *) NULL, &language, 1);
130 /* end file on DWORD boundary */
131 fpos = ftell (fres);
132 if (fpos % 4)
133 write_res_data (sign, fpos % 4, 1);
135 fclose (fres);
138 /* Read a resource entry, returns 0 when all resources are read */
139 static int
140 read_resource_entry (void)
142 struct res_id type;
143 struct res_id name;
144 struct res_res_info resinfo;
145 struct res_hdr reshdr;
146 long version;
147 void *buff;
149 struct res_resource *r;
151 res_align_file ();
153 /* Read header */
154 if (fread (&reshdr, sizeof (reshdr), 1, fres) != 1)
155 return 0;
157 /* read resource type */
158 read_res_id (&type);
159 /* read resource id */
160 read_res_id (&name);
162 res_align_file ();
164 /* Read additional resource header */
165 read_res_data (&resinfo.version, sizeof (resinfo.version), 1);
166 read_res_data (&resinfo.memflags, sizeof (resinfo.memflags), 1);
167 read_res_data (&resinfo.language, sizeof (resinfo.language), 1);
168 read_res_data (&version, sizeof (version), 1);
169 read_res_data (&resinfo.characteristics, sizeof (resinfo.characteristics), 1);
171 res_align_file ();
173 /* Allocate buffer for data */
174 buff = res_alloc (reshdr.data_size);
175 /* Read data */
176 read_res_data (buff, reshdr.data_size, 1);
177 /* Convert binary data to resource */
178 r = bin_to_res (type, buff, reshdr.data_size, 0);
179 r->res_info = resinfo;
180 /* Add resource to resource directory */
181 res_add_resource (r, &type, &name, resinfo.language, 0);
183 return 1;
186 /* write resource directory to binary resource file */
187 static void
188 write_res_directory (rd, type, name, language, level)
189 const struct res_directory *rd;
190 const struct res_id *type;
191 const struct res_id *name;
192 int *language;
193 int level;
195 const struct res_entry *re;
197 for (re = rd->entries; re != NULL; re = re->next)
199 switch (level)
201 case 1:
202 /* If we're at level 1, the key of this resource is the
203 type. This normally duplicates the information we have
204 stored with the resource itself, but we need to remember
205 the type if this is a user define resource type. */
206 type = &re->id;
207 break;
209 case 2:
210 /* If we're at level 2, the key of this resource is the name
211 we are going to use in the rc printout. */
212 name = &re->id;
213 break;
215 case 3:
216 /* If we're at level 3, then this key represents a language.
217 Use it to update the current language. */
218 if (!re->id.named
219 && re->id.u.id != *language
220 && (re->id.u.id & 0xffff) == re->id.u.id)
222 *language = re->id.u.id;
224 break;
226 default:
227 break;
230 if (re->subdir)
231 write_res_directory (re->u.dir, type, name, language, level + 1);
232 else
234 if (level == 3)
236 /* This is the normal case: the three levels are
237 TYPE/NAME/LANGUAGE. NAME will have been set at level
238 2, and represents the name to use. We probably just
239 set LANGUAGE, and it will probably match what the
240 resource itself records if anything. */
241 write_res_resource (type, name, re->u.res, language);
243 else
245 fprintf (stderr, "// Resource at unexpected level %d\n", level);
246 write_res_resource (type, (struct res_id *) NULL, re->u.res,
247 language);
254 static void
255 write_res_resource (type, name, res, language)
256 const struct res_id *type;
257 const struct res_id *name;
258 const struct res_resource *res;
259 int *language;
261 int rt;
263 switch (res->type)
265 default:
266 abort ();
268 case RES_TYPE_ACCELERATOR:
269 rt = RT_ACCELERATOR;
270 break;
272 case RES_TYPE_BITMAP:
273 rt = RT_BITMAP;
274 break;
276 case RES_TYPE_CURSOR:
277 rt = RT_CURSOR;
278 break;
280 case RES_TYPE_GROUP_CURSOR:
281 rt = RT_GROUP_CURSOR;
282 break;
284 case RES_TYPE_DIALOG:
285 rt = RT_DIALOG;
286 break;
288 case RES_TYPE_FONT:
289 rt = RT_FONT;
290 break;
292 case RES_TYPE_FONTDIR:
293 rt = RT_FONTDIR;
294 break;
296 case RES_TYPE_ICON:
297 rt = RT_ICON;
298 break;
300 case RES_TYPE_GROUP_ICON:
301 rt = RT_GROUP_ICON;
302 break;
304 case RES_TYPE_MENU:
305 rt = RT_MENU;
306 break;
308 case RES_TYPE_MESSAGETABLE:
309 rt = RT_MESSAGETABLE;
310 break;
312 case RES_TYPE_RCDATA:
313 rt = RT_RCDATA;
314 break;
316 case RES_TYPE_STRINGTABLE:
317 rt = RT_STRING;
318 break;
320 case RES_TYPE_USERDATA:
321 rt = 0;
322 break;
324 case RES_TYPE_VERSIONINFO:
325 rt = RT_VERSION;
326 break;
329 if (rt != 0
330 && type != NULL
331 && (type->named || type->u.id != rt))
333 fprintf (stderr, "// Unexpected resource type mismatch: ");
334 res_id_print (stderr, *type, 1);
335 fprintf (stderr, " != %d", rt);
336 abort ();
339 write_res_bin (res, type, name, &res->res_info);
340 return;
343 /* Write a resource in binary resource format */
344 static void
345 write_res_bin (res, type, name, resinfo)
346 const struct res_resource *res;
347 const struct res_id *type;
348 const struct res_id *name;
349 const struct res_res_info *resinfo;
351 unsigned long datasize = 0;
352 const struct bindata *bin_rep, *data;
354 bin_rep = res_to_bin (res, 0);
355 for (data = bin_rep; data != NULL; data = data->next)
356 datasize += data->length;
358 write_res_header (datasize, type, name, resinfo);
360 for (data = bin_rep; data != NULL; data = data->next)
361 write_res_data (data->data, data->length, 1);
364 /* Get number of bytes needed to store an id in binary format */
365 static unsigned long
366 get_id_size (id)
367 const struct res_id *id;
369 if (id->named)
370 return sizeof (unichar) * (id->u.n.length + 1);
371 else
372 return sizeof (unichar) * 2;
375 /* Write a resource header */
376 static void
377 write_res_header (datasize, type, name, resinfo)
378 unsigned long datasize;
379 const struct res_id *type;
380 const struct res_id *name;
381 const struct res_res_info *resinfo;
383 struct res_hdr reshdr;
384 reshdr.data_size = datasize;
385 reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
387 res_align_file ();
388 write_res_data (&reshdr, sizeof (reshdr), 1);
389 write_res_id (type);
390 write_res_id (name);
392 res_align_file ();
394 write_res_info (resinfo);
395 res_align_file ();
399 /* Write data to file, abort on failure */
400 static void
401 write_res_data (data, size, count)
402 const void *data;
403 size_t size;
404 int count;
406 if (fwrite (data, size, count, fres) != count)
407 fatal ("%s: %s: could not write to file", program_name, filename);
410 /* Read data from file, abort on failure */
411 static void
412 read_res_data (data, size, count)
413 void *data;
414 size_t size;
415 int count;
417 if (fread (data, size, count, fres) != count)
418 fatal ("%s: %s: unexpected end of file", program_name, filename);
421 /* Write a resource id */
422 static void
423 write_res_id (id)
424 const struct res_id *id;
426 if (id->named)
428 unsigned long len = id->u.n.length;
429 unichar null_term = 0;
430 write_res_data (id->u.n.name, len * sizeof (unichar), 1);
431 write_res_data (&null_term, sizeof (null_term), 1);
433 else
435 unsigned short i = 0xFFFF;
436 write_res_data (&i, sizeof (i), 1);
437 i = id->u.id;
438 write_res_data (&i, sizeof (i), 1);
442 /* Write resource info */
443 static void
444 write_res_info (info)
445 const struct res_res_info *info;
447 write_res_data (&info->version, sizeof (info->version), 1);
448 write_res_data (&info->memflags, sizeof (info->memflags), 1);
449 write_res_data (&info->language, sizeof (info->language), 1);
450 write_res_data (&info->version, sizeof (info->version), 1);
451 write_res_data (&info->characteristics, sizeof (info->characteristics), 1);
454 /* read a resource identifier */
455 void
456 read_res_id (id)
457 struct res_id *id;
459 unsigned short ord;
460 unichar *id_s = NULL;
461 int len;
463 read_res_data (&ord, sizeof (ord), 1);
464 if (ord == 0xFFFF) /* an ordinal id */
466 read_res_data (&ord, sizeof (ord), 1);
467 id->named = 0;
468 id->u.id = ord;
470 else
471 /* named id */
473 if (fseek (fres, -sizeof (ord), SEEK_CUR) != 0)
474 fatal ("%s: %s: could not seek in file", program_name, filename);
475 id_s = read_unistring (&len);
476 id->named = 1;
477 id->u.n.length = len;
478 id->u.n.name = id_s;
482 /* Read a null terminated UNICODE string */
483 static unichar *
484 read_unistring (len)
485 int *len;
487 unichar *s;
488 unichar c;
489 unichar *p;
490 int l;
492 *len = 0;
493 l = 0;
495 /* there are hardly any names longer than 256 characters */
496 p = s = (unichar *) xmalloc (sizeof (unichar) * 256);
499 read_res_data (&c, sizeof (c), 1);
500 *p++ = c;
501 if (c != 0)
502 l++;
504 while (c != 0);
505 *len = l;
506 return s;
509 /* align file on DWORD boundary */
510 static void
511 res_align_file (void)
513 if (fseek (fres, ftell (fres) % 4, SEEK_CUR) != 0)
514 fatal ("%s: %s: unable to align file", program_name, filename);
517 /* Check if file is a win32 binary resource file, if so
518 skip past the null resource. Returns 0 if successful, -1 on
519 error.
521 static void
522 skip_null_resource (void)
524 struct res_hdr reshdr =
525 {0, 0};
526 read_res_data (&reshdr, sizeof (reshdr), 1);
527 if ((reshdr.data_size != 0) || (reshdr.header_size != 0x20))
528 goto skip_err;
530 /* Subtract size of HeaderSize and DataSize */
531 if (fseek (fres, reshdr.header_size - 8, SEEK_CUR) != 0)
532 goto skip_err;
534 return;
536 skip_err:
537 fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
538 filename);
539 xexit (1);
542 /* Add a resource to resource directory */
543 void
544 res_add_resource (r, type, id, language, dupok)
545 struct res_resource *r;
546 const struct res_id *type;
547 const struct res_id *id;
548 int language;
549 int dupok;
551 struct res_id a[3];
553 a[0] = *type;
554 a[1] = *id;
555 a[2].named = 0;
556 a[2].u.id = language;
557 res_append_resource (&resources, r, 3, a, dupok);
560 /* Append a resource to resource directory.
561 This is just copied from define_resource
562 and modified to add an existing resource.
564 void
565 res_append_resource (resources, resource, cids, ids, dupok)
566 struct res_directory **resources;
567 struct res_resource *resource;
568 int cids;
569 const struct res_id *ids;
570 int dupok;
572 struct res_entry *re = NULL;
573 int i;
575 assert (cids > 0);
576 for (i = 0; i < cids; i++)
578 struct res_entry **pp;
580 if (*resources == NULL)
582 static unsigned long timeval;
584 /* Use the same timestamp for every resource created in a
585 single run. */
586 if (timeval == 0)
587 timeval = time (NULL);
589 *resources = ((struct res_directory *)
590 res_alloc (sizeof **resources));
591 (*resources)->characteristics = 0;
592 (*resources)->time = timeval;
593 (*resources)->major = 0;
594 (*resources)->minor = 0;
595 (*resources)->entries = NULL;
598 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
599 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
600 break;
602 if (*pp != NULL)
603 re = *pp;
604 else
606 re = (struct res_entry *) res_alloc (sizeof *re);
607 re->next = NULL;
608 re->id = ids[i];
609 if ((i + 1) < cids)
611 re->subdir = 1;
612 re->u.dir = NULL;
614 else
616 re->subdir = 0;
617 re->u.res = NULL;
620 *pp = re;
623 if ((i + 1) < cids)
625 if (!re->subdir)
627 fprintf (stderr, "%s: ", program_name);
628 res_ids_print (stderr, i, ids);
629 fprintf (stderr, ": expected to be a directory\n");
630 xexit (1);
633 resources = &re->u.dir;
637 if (re->subdir)
639 fprintf (stderr, "%s: ", program_name);
640 res_ids_print (stderr, cids, ids);
641 fprintf (stderr, ": expected to be a leaf\n");
642 xexit (1);
645 if (re->u.res != NULL)
647 if (dupok)
648 return;
650 fprintf (stderr, "%s: warning: ", program_name);
651 res_ids_print (stderr, cids, ids);
652 fprintf (stderr, ": duplicate value\n");
655 re->u.res = resource;