* doc/c-xtensa.texi (Xtensa Automatic Alignment): Remove statements
[binutils.git] / binutils / resres.c
blobb5677d2bec50a1ec73ea0b1cb1cf4ad20f1adffb
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
20 02110-1301, USA. */
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. */
26 #include "sysdep.h"
27 #include "bfd.h"
28 #include "libiberty.h"
29 #include "bucomm.h"
30 #include "windres.h"
32 #include <assert.h>
33 #include <time.h>
35 struct res_hdr
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 *,
44 int *, int));
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));
68 static void
69 res_add_resource
70 PARAMS ((struct res_resource *, const struct res_id *,
71 const struct res_id *, int, int));
73 void
74 res_append_resource
75 PARAMS ((struct res_directory **, struct res_resource *,
76 int, const struct res_id *, int));
78 static struct res_directory *resources = NULL;
80 static FILE *fres;
81 static const char *filename;
83 extern char *program_name;
85 /* Read resource file */
86 struct res_directory *
87 read_res_file (fn)
88 const char *fn;
90 filename = fn;
91 fres = fopen (filename, "rb");
92 if (fres == NULL)
93 fatal ("can't open `%s' for output: %s", filename, strerror (errno));
95 skip_null_resource ();
97 while (read_resource_entry ())
100 fclose (fres);
102 return resources;
105 /* Write resource file */
106 void
107 write_res_file (fn, resdir)
108 const char *fn;
109 const struct res_directory *resdir;
111 int language;
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};
117 long fpos;
119 filename = fn;
121 fres = fopen (filename, "wb");
122 if (fres == NULL)
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 */
130 language = -1;
131 write_res_directory (resdir, (const struct res_id *) NULL,
132 (const struct res_id *) NULL, &language, 1);
134 /* end file on DWORD boundary */
135 fpos = ftell (fres);
136 if (fpos % 4)
137 write_res_data (sign, fpos % 4, 1);
139 fclose (fres);
142 /* Read a resource entry, returns 0 when all resources are read */
143 static int
144 read_resource_entry (void)
146 struct res_id type;
147 struct res_id name;
148 struct res_res_info resinfo;
149 struct res_hdr reshdr;
150 long version;
151 void *buff;
153 struct res_resource *r;
155 res_align_file ();
157 /* Read header */
158 if (fread (&reshdr, sizeof (reshdr), 1, fres) != 1)
159 return 0;
161 /* read resource type */
162 read_res_id (&type);
163 /* read resource id */
164 read_res_id (&name);
166 res_align_file ();
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);
175 res_align_file ();
177 /* Allocate buffer for data */
178 buff = res_alloc (reshdr.data_size);
179 /* Read data */
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);
187 return 1;
190 /* write resource directory to binary resource file */
191 static void
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;
196 int *language;
197 int level;
199 const struct res_entry *re;
201 for (re = rd->entries; re != NULL; re = re->next)
203 switch (level)
205 case 1:
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. */
210 type = &re->id;
211 break;
213 case 2:
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. */
216 name = &re->id;
217 break;
219 case 3:
220 /* If we're at level 3, then this key represents a language.
221 Use it to update the current language. */
222 if (!re->id.named
223 && re->id.u.id != (unsigned long) *language
224 && (re->id.u.id & 0xffff) == re->id.u.id)
226 *language = re->id.u.id;
228 break;
230 default:
231 break;
234 if (re->subdir)
235 write_res_directory (re->u.dir, type, name, language, level + 1);
236 else
238 if (level == 3)
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);
247 else
249 fprintf (stderr, "// Resource at unexpected level %d\n", level);
250 write_res_resource (type, (struct res_id *) NULL, re->u.res,
251 language);
258 static void
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;
265 int rt;
267 switch (res->type)
269 default:
270 abort ();
272 case RES_TYPE_ACCELERATOR:
273 rt = RT_ACCELERATOR;
274 break;
276 case RES_TYPE_BITMAP:
277 rt = RT_BITMAP;
278 break;
280 case RES_TYPE_CURSOR:
281 rt = RT_CURSOR;
282 break;
284 case RES_TYPE_GROUP_CURSOR:
285 rt = RT_GROUP_CURSOR;
286 break;
288 case RES_TYPE_DIALOG:
289 rt = RT_DIALOG;
290 break;
292 case RES_TYPE_FONT:
293 rt = RT_FONT;
294 break;
296 case RES_TYPE_FONTDIR:
297 rt = RT_FONTDIR;
298 break;
300 case RES_TYPE_ICON:
301 rt = RT_ICON;
302 break;
304 case RES_TYPE_GROUP_ICON:
305 rt = RT_GROUP_ICON;
306 break;
308 case RES_TYPE_MENU:
309 rt = RT_MENU;
310 break;
312 case RES_TYPE_MESSAGETABLE:
313 rt = RT_MESSAGETABLE;
314 break;
316 case RES_TYPE_RCDATA:
317 rt = RT_RCDATA;
318 break;
320 case RES_TYPE_STRINGTABLE:
321 rt = RT_STRING;
322 break;
324 case RES_TYPE_USERDATA:
325 rt = 0;
326 break;
328 case RES_TYPE_VERSIONINFO:
329 rt = RT_VERSION;
330 break;
333 if (rt != 0
334 && type != NULL
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);
340 abort ();
343 write_res_bin (res, type, name, &res->res_info);
344 return;
347 /* Write a resource in binary resource format */
348 static void
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 */
369 static unsigned long
370 get_id_size (id)
371 const struct res_id *id;
373 if (id->named)
374 return sizeof (unichar) * (id->u.n.length + 1);
375 else
376 return sizeof (unichar) * 2;
379 /* Write a resource header */
380 static void
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;
393 res_align_file ();
394 write_res_data (&reshdr, sizeof (reshdr), 1);
395 write_res_id (type);
396 write_res_id (name);
398 res_align_file ();
400 write_res_info (resinfo);
401 res_align_file ();
405 /* Write data to file, abort on failure */
406 static void
407 write_res_data (data, size, count)
408 const void *data;
409 size_t size;
410 int 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 */
417 static void
418 read_res_data (data, size, count)
419 void *data;
420 size_t size;
421 int count;
423 if (fread (data, size, count, fres) != (size_t) count)
424 fatal ("%s: unexpected end of file", filename);
427 /* Write a resource id */
428 static void
429 write_res_id (id)
430 const struct res_id *id;
432 if (id->named)
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);
439 else
441 unsigned short i = 0xFFFF;
442 write_res_data (&i, sizeof (i), 1);
443 i = id->u.id;
444 write_res_data (&i, sizeof (i), 1);
448 /* Write resource info */
449 static void
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 */
461 void
462 read_res_id (id)
463 struct res_id *id;
465 unsigned short ord;
466 unichar *id_s = NULL;
467 int len;
469 read_res_data (&ord, sizeof (ord), 1);
470 if (ord == 0xFFFF) /* an ordinal id */
472 read_res_data (&ord, sizeof (ord), 1);
473 id->named = 0;
474 id->u.id = ord;
476 else
477 /* named id */
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);
482 id->named = 1;
483 id->u.n.length = len;
484 id->u.n.name = id_s;
488 /* Read a null terminated UNICODE string */
489 static unichar *
490 read_unistring (len)
491 int *len;
493 unichar *s;
494 unichar c;
495 unichar *p;
496 int l;
498 *len = 0;
499 l = 0;
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);
506 *p++ = c;
507 if (c != 0)
508 l++;
510 while (c != 0);
511 *len = l;
512 return s;
515 /* align file on DWORD boundary */
516 static void
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
527 error.
529 static void
530 skip_null_resource (void)
532 struct res_hdr reshdr =
533 {0, 0};
534 read_res_data (&reshdr, sizeof (reshdr), 1);
535 if ((reshdr.data_size != 0) || (reshdr.header_size != 0x20))
536 goto skip_err;
538 /* Subtract size of HeaderSize and DataSize */
539 if (fseek (fres, reshdr.header_size - 8, SEEK_CUR) != 0)
540 goto skip_err;
542 return;
544 skip_err:
545 fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
546 filename);
547 xexit (1);
550 /* Add a resource to resource directory */
551 void
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;
556 int language;
557 int dupok;
559 struct res_id a[3];
561 a[0] = *type;
562 a[1] = *id;
563 a[2].named = 0;
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.
572 void
573 res_append_resource (resources, resource, cids, ids, dupok)
574 struct res_directory **resources;
575 struct res_resource *resource;
576 int cids;
577 const struct res_id *ids;
578 int dupok;
580 struct res_entry *re = NULL;
581 int i;
583 assert (cids > 0);
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
593 single run. */
594 if (timeval == 0)
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)
608 break;
610 if (*pp != NULL)
611 re = *pp;
612 else
614 re = (struct res_entry *) res_alloc (sizeof *re);
615 re->next = NULL;
616 re->id = ids[i];
617 if ((i + 1) < cids)
619 re->subdir = 1;
620 re->u.dir = NULL;
622 else
624 re->subdir = 0;
625 re->u.res = NULL;
628 *pp = re;
631 if ((i + 1) < cids)
633 if (!re->subdir)
635 fprintf (stderr, "%s: ", program_name);
636 res_ids_print (stderr, i, ids);
637 fprintf (stderr, ": expected to be a directory\n");
638 xexit (1);
641 resources = &re->u.dir;
645 if (re->subdir)
647 fprintf (stderr, "%s: ", program_name);
648 res_ids_print (stderr, cids, ids);
649 fprintf (stderr, ": expected to be a leaf\n");
650 xexit (1);
653 if (re->u.res != NULL)
655 if (dupok)
656 return;
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;