]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/resres.c
Make use of the frame stash to detect wider stack cycles.
[thirdparty/binutils-gdb.git] / binutils / resres.c
CommitLineData
252b5132 1/* resres.c: read_res_file and write_res_file implementation for windres.
cc643b88 2 Copyright 1998, 1999, 2001, 2002, 2005, 2007, 2008, 2011
4a594fce 3 Free Software Foundation, Inc.
252b5132 4 Written by Anders Norlander <anorland@hem2.passagen.se>.
4a594fce 5 Rewritten by Kai Tietz, Onevision.
252b5132
RH
6
7 This file is part of GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
32866df7 11 the Free Software Foundation; either version 3 of the License, or
252b5132
RH
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
b43b5d5f
NC
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
252b5132 23
34ca6cf8
ILT
24/* FIXME: This file does not work correctly in a cross configuration.
25 It assumes that it can use fread and fwrite to read and write
26 integers. It does no swapping. */
27
3db64b00 28#include "sysdep.h"
252b5132 29#include "bfd.h"
3db64b00 30#include "bucomm.h"
4a594fce 31#include "libiberty.h"
252b5132
RH
32#include "windres.h"
33
34#include <assert.h>
35#include <time.h>
36
4a594fce
NC
37static rc_uint_type write_res_directory (windres_bfd *, rc_uint_type,
38 const rc_res_directory *, const rc_res_id *,
39 const rc_res_id *, rc_uint_type *, int);
40static rc_uint_type write_res_resource (windres_bfd *, rc_uint_type,const rc_res_id *,
41 const rc_res_id *, const rc_res_resource *,
42 rc_uint_type *);
43static rc_uint_type write_res_bin (windres_bfd *, rc_uint_type, const rc_res_resource *,
44 const rc_res_id *, const rc_res_id *,
45 const rc_res_res_info *);
252b5132 46
4a594fce
NC
47static rc_uint_type write_res_id (windres_bfd *, rc_uint_type, const rc_res_id *);
48static rc_uint_type write_res_info (windres_bfd *, rc_uint_type, const rc_res_res_info *);
49static rc_uint_type write_res_data_hdr (windres_bfd *, rc_uint_type, res_hdr *);
252b5132 50
4a594fce
NC
51static rc_uint_type write_res_header (windres_bfd *, rc_uint_type, rc_uint_type,
52 const rc_res_id *, const rc_res_id *,
53 const rc_res_res_info *);
54
55static int read_resource_entry (windres_bfd *, rc_uint_type *, rc_uint_type);
56static void read_res_data (windres_bfd *, rc_uint_type *, rc_uint_type, void *,
57 rc_uint_type);
58static void read_res_data_hdr (windres_bfd *, rc_uint_type *, rc_uint_type, res_hdr *);
59static void read_res_id (windres_bfd *, rc_uint_type *, rc_uint_type, rc_res_id *);
60static unichar *read_unistring (windres_bfd *, rc_uint_type *, rc_uint_type, rc_uint_type *);
61static void skip_null_resource (windres_bfd *, rc_uint_type *, rc_uint_type);
62static int probe_binary (windres_bfd *wrbfd, rc_uint_type);
63
64static unsigned long get_id_size (const rc_res_id *);
65
66static void res_add_resource (rc_res_resource *, const rc_res_id *,
67 const rc_res_id *, rc_uint_type, int);
252b5132 68
4a594fce
NC
69static void res_append_resource (rc_res_directory **, rc_res_resource *,
70 int, const rc_res_id *, int);
71
72static rc_res_directory *resources = NULL;
252b5132 73
252b5132
RH
74static const char *filename;
75
76extern char *program_name;
77
78/* Read resource file */
4a594fce
NC
79rc_res_directory *
80read_res_file (const char *fn)
252b5132 81{
4a594fce
NC
82 rc_uint_type off, flen;
83 windres_bfd wrbfd;
84 bfd *abfd;
85 asection *sec;
252b5132 86 filename = fn;
252b5132 87
4a594fce
NC
88 flen = (rc_uint_type) get_file_size (filename);
89 if (! flen)
90 fatal ("can't open '%s' for input.", filename);
91 abfd = windres_open_as_binary (filename, 1);
92 sec = bfd_get_section_by_name (abfd, ".data");
93 if (sec == NULL)
94 bfd_fatal ("bfd_get_section_by_name");
95 set_windres_bfd (&wrbfd, abfd, sec,
96 (target_is_bigendian ? WR_KIND_BFD_BIN_B
97 : WR_KIND_BFD_BIN_L));
98 off = 0;
99
100 if (! probe_binary (&wrbfd, flen))
cc643b88 101 set_windres_bfd_endianness (&wrbfd, ! target_is_bigendian);
4a594fce
NC
102
103 skip_null_resource (&wrbfd, &off, flen);
252b5132 104
4a594fce 105 while (read_resource_entry (&wrbfd, &off, flen))
252b5132
RH
106 ;
107
4a594fce 108 bfd_close (abfd);
252b5132
RH
109
110 return resources;
111}
112
113/* Write resource file */
114void
4a594fce 115write_res_file (const char *fn,const rc_res_directory *resdir)
252b5132 116{
4a594fce
NC
117 asection *sec;
118 rc_uint_type language;
119 bfd *abfd;
120 windres_bfd wrbfd;
121 unsigned long sec_length = 0,sec_length_wrote;
122 static const bfd_byte sign[] =
252b5132
RH
123 {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
124 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
252b5132
RH
127
128 filename = fn;
129
4a594fce 130 abfd = windres_open_as_binary (filename, 0);
0eb80fd3
AM
131 sec = bfd_make_section_with_flags (abfd, ".data",
132 (SEC_HAS_CONTENTS | SEC_ALLOC
133 | SEC_LOAD | SEC_DATA));
4a594fce
NC
134 if (sec == NULL)
135 bfd_fatal ("bfd_make_section");
4a594fce
NC
136 /* Requiring this is probably a bug in BFD. */
137 sec->output_section = sec;
138
139 set_windres_bfd (&wrbfd, abfd, sec,
140 (target_is_bigendian ? WR_KIND_BFD_BIN_B
141 : WR_KIND_BFD_BIN_L));
252b5132
RH
142
143 language = -1;
4a594fce
NC
144 sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir,
145 (const rc_res_id *) NULL,
146 (const rc_res_id *) NULL, &language, 1);
147 if (! bfd_set_section_size (abfd, sec, (sec_length + 3) & ~3))
148 bfd_fatal ("bfd_set_section_size");
149 if ((sec_length & 3) != 0)
150 set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3));
151 set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign));
152 language = -1;
153 sec_length_wrote = write_res_directory (&wrbfd, 0x20UL, resdir,
154 (const rc_res_id *) NULL,
155 (const rc_res_id *) NULL,
156 &language, 1);
157 if (sec_length != sec_length_wrote)
0af1713e
AM
158 fatal ("res write failed with different sizes (%lu/%lu).",
159 (unsigned long) sec_length, (unsigned long) sec_length_wrote);
4a594fce
NC
160
161 bfd_close (abfd);
162 return;
252b5132
RH
163}
164
165/* Read a resource entry, returns 0 when all resources are read */
166static int
4a594fce 167read_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
252b5132 168{
4a594fce
NC
169 rc_res_id type;
170 rc_res_id name;
171 rc_res_res_info resinfo;
172 res_hdr reshdr;
252b5132
RH
173 void *buff;
174
4a594fce
NC
175 rc_res_resource *r;
176 struct bin_res_info l;
252b5132 177
4a594fce 178 off[0] = (off[0] + 3) & ~3;
252b5132
RH
179
180 /* Read header */
4a594fce 181 if ((off[0] + 8) > omax)
252b5132 182 return 0;
4a594fce 183 read_res_data_hdr (wrbfd, off, omax, &reshdr);
252b5132
RH
184
185 /* read resource type */
4a594fce 186 read_res_id (wrbfd, off, omax, &type);
252b5132 187 /* read resource id */
4a594fce 188 read_res_id (wrbfd, off, omax, &name);
252b5132 189
4a594fce 190 off[0] = (off[0] + 3) & ~3;
252b5132
RH
191
192 /* Read additional resource header */
4a594fce
NC
193 read_res_data (wrbfd, off, omax, &l, BIN_RES_INFO_SIZE);
194 resinfo.version = windres_get_32 (wrbfd, l.version, 4);
195 resinfo.memflags = windres_get_16 (wrbfd, l.memflags, 2);
196 resinfo.language = windres_get_16 (wrbfd, l.language, 2);
197 /* resinfo.version2 = windres_get_32 (wrbfd, l.version2, 4); */
198 resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4);
252b5132 199
4a594fce 200 off[0] = (off[0] + 3) & ~3;
252b5132
RH
201
202 /* Allocate buffer for data */
203 buff = res_alloc (reshdr.data_size);
204 /* Read data */
4a594fce 205 read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
252b5132 206 /* Convert binary data to resource */
4a594fce 207 r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
252b5132
RH
208 r->res_info = resinfo;
209 /* Add resource to resource directory */
210 res_add_resource (r, &type, &name, resinfo.language, 0);
211
212 return 1;
213}
214
215/* write resource directory to binary resource file */
4a594fce
NC
216static rc_uint_type
217write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_directory *rd,
218 const rc_res_id *type, const rc_res_id *name, rc_uint_type *language,
219 int level)
252b5132 220{
4a594fce 221 const rc_res_entry *re;
252b5132
RH
222
223 for (re = rd->entries; re != NULL; re = re->next)
224 {
225 switch (level)
226 {
227 case 1:
228 /* If we're at level 1, the key of this resource is the
229 type. This normally duplicates the information we have
230 stored with the resource itself, but we need to remember
231 the type if this is a user define resource type. */
232 type = &re->id;
233 break;
234
235 case 2:
236 /* If we're at level 2, the key of this resource is the name
53c7db4b 237 we are going to use in the rc printout. */
252b5132
RH
238 name = &re->id;
239 break;
240
241 case 3:
242 /* If we're at level 3, then this key represents a language.
243 Use it to update the current language. */
4a594fce 244 if (! re->id.named
34ca6cf8 245 && re->id.u.id != (unsigned long) *language
252b5132
RH
246 && (re->id.u.id & 0xffff) == re->id.u.id)
247 {
248 *language = re->id.u.id;
249 }
250 break;
251
252 default:
253 break;
254 }
255
256 if (re->subdir)
4a594fce
NC
257 off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
258 level + 1);
252b5132
RH
259 else
260 {
261 if (level == 3)
262 {
263 /* This is the normal case: the three levels are
264 TYPE/NAME/LANGUAGE. NAME will have been set at level
265 2, and represents the name to use. We probably just
266 set LANGUAGE, and it will probably match what the
267 resource itself records if anything. */
4a594fce
NC
268 off = write_res_resource (wrbfd, off, type, name, re->u.res,
269 language);
252b5132
RH
270 }
271 else
272 {
273 fprintf (stderr, "// Resource at unexpected level %d\n", level);
4a594fce
NC
274 off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
275 re->u.res, language);
252b5132
RH
276 }
277 }
278 }
279
4a594fce 280 return off;
252b5132
RH
281}
282
4a594fce
NC
283static rc_uint_type
284write_res_resource (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *type,
285 const rc_res_id *name, const rc_res_resource *res,
286 rc_uint_type *language ATTRIBUTE_UNUSED)
252b5132
RH
287{
288 int rt;
289
290 switch (res->type)
291 {
292 default:
293 abort ();
294
295 case RES_TYPE_ACCELERATOR:
296 rt = RT_ACCELERATOR;
297 break;
298
299 case RES_TYPE_BITMAP:
300 rt = RT_BITMAP;
301 break;
302
303 case RES_TYPE_CURSOR:
304 rt = RT_CURSOR;
305 break;
306
307 case RES_TYPE_GROUP_CURSOR:
308 rt = RT_GROUP_CURSOR;
309 break;
310
311 case RES_TYPE_DIALOG:
312 rt = RT_DIALOG;
313 break;
314
315 case RES_TYPE_FONT:
316 rt = RT_FONT;
317 break;
318
319 case RES_TYPE_FONTDIR:
320 rt = RT_FONTDIR;
321 break;
322
323 case RES_TYPE_ICON:
324 rt = RT_ICON;
325 break;
326
327 case RES_TYPE_GROUP_ICON:
328 rt = RT_GROUP_ICON;
329 break;
330
331 case RES_TYPE_MENU:
332 rt = RT_MENU;
333 break;
334
335 case RES_TYPE_MESSAGETABLE:
336 rt = RT_MESSAGETABLE;
337 break;
338
339 case RES_TYPE_RCDATA:
340 rt = RT_RCDATA;
341 break;
342
343 case RES_TYPE_STRINGTABLE:
344 rt = RT_STRING;
345 break;
346
347 case RES_TYPE_USERDATA:
348 rt = 0;
349 break;
350
351 case RES_TYPE_VERSIONINFO:
352 rt = RT_VERSION;
353 break;
4a594fce
NC
354
355 case RES_TYPE_TOOLBAR:
356 rt = RT_TOOLBAR;
357 break;
252b5132
RH
358 }
359
360 if (rt != 0
361 && type != NULL
34ca6cf8 362 && (type->named || type->u.id != (unsigned long) rt))
252b5132
RH
363 {
364 fprintf (stderr, "// Unexpected resource type mismatch: ");
365 res_id_print (stderr, *type, 1);
366 fprintf (stderr, " != %d", rt);
367 abort ();
368 }
369
4a594fce 370 return write_res_bin (wrbfd, off, res, type, name, &res->res_info);
252b5132
RH
371}
372
373/* Write a resource in binary resource format */
4a594fce
NC
374static rc_uint_type
375write_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res,
376 const rc_res_id *type, const rc_res_id *name,
377 const rc_res_res_info *resinfo)
252b5132 378{
4a594fce
NC
379 rc_uint_type noff;
380 rc_uint_type datasize = 0;
252b5132 381
4a594fce
NC
382 noff = res_to_bin ((windres_bfd *) NULL, off, res);
383 datasize = noff - off;
252b5132 384
4a594fce
NC
385 off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
386 return res_to_bin (wrbfd, off, res);
252b5132
RH
387}
388
389/* Get number of bytes needed to store an id in binary format */
390static unsigned long
391get_id_size (id)
4a594fce 392 const rc_res_id *id;
252b5132
RH
393{
394 if (id->named)
395 return sizeof (unichar) * (id->u.n.length + 1);
396 else
397 return sizeof (unichar) * 2;
398}
399
400/* Write a resource header */
4a594fce
NC
401static rc_uint_type
402write_res_header (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type datasize,
403 const rc_res_id *type, const rc_res_id *name,
404 const rc_res_res_info *resinfo)
252b5132 405{
4a594fce 406 res_hdr reshdr;
252b5132
RH
407 reshdr.data_size = datasize;
408 reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
409
5f16d855
DD
410 reshdr.header_size = (reshdr.header_size + 3) & ~3;
411
4a594fce
NC
412 off = (off + 3) & ~3;
413
414 off = write_res_data_hdr (wrbfd, off, &reshdr);
415 off = write_res_id (wrbfd, off, type);
416 off = write_res_id (wrbfd, off, name);
252b5132 417
4a594fce 418 off = (off + 3) & ~3;
252b5132 419
4a594fce
NC
420 off = write_res_info (wrbfd, off, resinfo);
421 off = (off + 3) & ~3;
422 return off;
252b5132
RH
423}
424
4a594fce
NC
425static rc_uint_type
426write_res_data_hdr (windres_bfd *wrbfd, rc_uint_type off, res_hdr *hdr)
427{
428 if (wrbfd)
429 {
430 struct bin_res_hdr brh;
431 windres_put_32 (wrbfd, brh.data_size, hdr->data_size);
432 windres_put_32 (wrbfd, brh.header_size, hdr->header_size);
433 set_windres_bfd_content (wrbfd, &brh, off, BIN_RES_HDR_SIZE);
434 }
435 return off + BIN_RES_HDR_SIZE;
436}
252b5132 437
252b5132 438static void
4a594fce
NC
439read_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
440 res_hdr *reshdr)
252b5132 441{
4a594fce
NC
442 struct bin_res_hdr brh;
443
444 if ((off[0] + BIN_RES_HDR_SIZE) > omax)
445 fatal ("%s: unexpected end of file %ld/%ld", filename,(long) off[0], (long) omax);
446
447 get_windres_bfd_content (wrbfd, &brh, off[0], BIN_RES_HDR_SIZE);
448 reshdr->data_size = windres_get_32 (wrbfd, brh.data_size, 4);
449 reshdr->header_size = windres_get_32 (wrbfd, brh.header_size, 4);
450 off[0] += BIN_RES_HDR_SIZE;
252b5132
RH
451}
452
453/* Read data from file, abort on failure */
454static void
4a594fce
NC
455read_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data,
456 rc_uint_type size)
252b5132 457{
4a594fce
NC
458 if ((off[0] + size) > omax)
459 fatal ("%s: unexpected end of file %ld/%ld %ld", filename,(long) off[0],
460 (long) omax, (long) size);
461 get_windres_bfd_content (wrbfd, data, off[0], size);
462 off[0] += size;
252b5132
RH
463}
464
465/* Write a resource id */
4a594fce
NC
466static rc_uint_type
467write_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id)
252b5132
RH
468{
469 if (id->named)
470 {
4a594fce
NC
471 rc_uint_type len = (((bfd_signed_vma) id->u.n.length < 0 ? 0 : id->u.n.length) + 1);
472 if (wrbfd)
473 {
474 rc_uint_type i;
475 bfd_byte *d = (bfd_byte *) xmalloc (len * sizeof (unichar));
476 for (i = 0; i < (len - 1); i++)
477 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id->u.n.name[i]);
478 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), 0);
479 set_windres_bfd_content (wrbfd, d, off, (len * sizeof (unichar)));
480 }
481 off += (len * sizeof (unichar));
252b5132
RH
482 }
483 else
484 {
4a594fce
NC
485 if (wrbfd)
486 {
487 struct bin_res_id bid;
488 windres_put_16 (wrbfd, bid.sig, 0xffff);
489 windres_put_16 (wrbfd, bid.id, id->u.id);
490 set_windres_bfd_content (wrbfd, &bid, off, BIN_RES_ID);
491 }
492 off += BIN_RES_ID;
252b5132 493 }
4a594fce 494 return off;
252b5132
RH
495}
496
497/* Write resource info */
4a594fce
NC
498static rc_uint_type
499write_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info)
252b5132 500{
4a594fce
NC
501 if (wrbfd)
502 {
503 struct bin_res_info l;
504
505 windres_put_32 (wrbfd, l.version, info->version);
506 windres_put_16 (wrbfd, l.memflags, info->memflags);
507 windres_put_16 (wrbfd, l.language, info->language);
508 windres_put_32 (wrbfd, l.version2, info->version);
509 windres_put_32 (wrbfd, l.characteristics, info->characteristics);
510 set_windres_bfd_content (wrbfd, &l, off, BIN_RES_INFO_SIZE);
511 }
512 return off + BIN_RES_INFO_SIZE;
252b5132
RH
513}
514
515/* read a resource identifier */
4a594fce
NC
516static void
517read_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id)
252b5132 518{
4a594fce 519 struct bin_res_id bid;
252b5132
RH
520 unsigned short ord;
521 unichar *id_s = NULL;
4a594fce 522 rc_uint_type len;
252b5132 523
4a594fce
NC
524 read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2);
525 ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2);
252b5132
RH
526 if (ord == 0xFFFF) /* an ordinal id */
527 {
4a594fce 528 read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2);
252b5132 529 id->named = 0;
4a594fce 530 id->u.id = windres_get_16 (wrbfd, bid.id, 2);
252b5132
RH
531 }
532 else
533 /* named id */
534 {
4a594fce
NC
535 off[0] -= 2;
536 id_s = read_unistring (wrbfd, off, omax, &len);
252b5132
RH
537 id->named = 1;
538 id->u.n.length = len;
539 id->u.n.name = id_s;
540 }
541}
542
543/* Read a null terminated UNICODE string */
544static unichar *
4a594fce
NC
545read_unistring (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
546 rc_uint_type *len)
252b5132
RH
547{
548 unichar *s;
4a594fce 549 bfd_byte d[2];
252b5132
RH
550 unichar c;
551 unichar *p;
4a594fce
NC
552 rc_uint_type l;
553 rc_uint_type soff = off[0];
252b5132 554
03997556
NC
555 do
556 {
557 read_res_data (wrbfd, &soff, omax, d, sizeof (unichar));
558 c = windres_get_16 (wrbfd, d, 2);
559 }
560 while (c != 0);
4a594fce 561 l = ((soff - off[0]) / sizeof (unichar));
252b5132 562
4a594fce
NC
563 /* there are hardly any names longer than 256 characters, but anyway. */
564 p = s = (unichar *) xmalloc (sizeof (unichar) * l);
252b5132
RH
565 do
566 {
4a594fce
NC
567 read_res_data (wrbfd, off, omax, d, sizeof (unichar));
568 c = windres_get_16 (wrbfd, d, 2);
252b5132 569 *p++ = c;
252b5132
RH
570 }
571 while (c != 0);
4a594fce 572 *len = l - 1;
252b5132
RH
573 return s;
574}
575
4a594fce
NC
576static int
577probe_binary (windres_bfd *wrbfd, rc_uint_type omax)
252b5132 578{
4a594fce
NC
579 rc_uint_type off;
580 res_hdr reshdr;
581
582 off = 0;
583 read_res_data_hdr (wrbfd, &off, omax, &reshdr);
584 if (reshdr.data_size != 0)
585 return 1;
586 if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
587 || (reshdr.header_size != 0x20000000 && target_is_bigendian))
588 return 1;
589
590 /* Subtract size of HeaderSize. DataSize has to be zero. */
591 off += 0x20 - BIN_RES_HDR_SIZE;
592 if ((off + BIN_RES_HDR_SIZE) >= omax)
593 return 1;
594 read_res_data_hdr (wrbfd, &off, omax, &reshdr);
03997556
NC
595 /* off is advanced by BIN_RES_HDR_SIZE in read_res_data_hdr()
596 which is part of reshdr.header_size. We shouldn't take it
597 into account twice. */
598 if ((off - BIN_RES_HDR_SIZE + reshdr.data_size + reshdr.header_size) > omax)
599 return 0;
4a594fce 600 return 1;
252b5132
RH
601}
602
603/* Check if file is a win32 binary resource file, if so
604 skip past the null resource. Returns 0 if successful, -1 on
605 error.
606 */
607static void
4a594fce 608skip_null_resource (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
252b5132 609{
4a594fce
NC
610 res_hdr reshdr;
611 read_res_data_hdr (wrbfd, off, omax, &reshdr);
612 if (reshdr.data_size != 0)
613 goto skip_err;
614 if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
615 || (reshdr.header_size != 0x20000000 && target_is_bigendian))
252b5132
RH
616 goto skip_err;
617
4a594fce
NC
618 /* Subtract size of HeaderSize. DataSize has to be zero. */
619 off[0] += 0x20 - BIN_RES_HDR_SIZE;
620 if (off[0] >= omax)
252b5132
RH
621 goto skip_err;
622
623 return;
624
625skip_err:
626 fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
627 filename);
628 xexit (1);
629}
630
631/* Add a resource to resource directory */
4a594fce
NC
632static void
633res_add_resource (rc_res_resource *r, const rc_res_id *type, const rc_res_id *id,
634 rc_uint_type language, int dupok)
252b5132 635{
4a594fce 636 rc_res_id a[3];
252b5132
RH
637
638 a[0] = *type;
639 a[1] = *id;
640 a[2].named = 0;
641 a[2].u.id = language;
642 res_append_resource (&resources, r, 3, a, dupok);
643}
644
645/* Append a resource to resource directory.
646 This is just copied from define_resource
647 and modified to add an existing resource.
648 */
4a594fce 649static void
91d6fa6a 650res_append_resource (rc_res_directory **res_dirs, rc_res_resource *resource,
4a594fce 651 int cids, const rc_res_id *ids, int dupok)
252b5132 652{
4a594fce 653 rc_res_entry *re = NULL;
252b5132
RH
654 int i;
655
656 assert (cids > 0);
657 for (i = 0; i < cids; i++)
658 {
4a594fce 659 rc_res_entry **pp;
252b5132 660
91d6fa6a 661 if (*res_dirs == NULL)
252b5132
RH
662 {
663 static unsigned long timeval;
664
665 /* Use the same timestamp for every resource created in a
666 single run. */
667 if (timeval == 0)
668 timeval = time (NULL);
669
91d6fa6a 670 *res_dirs = ((rc_res_directory *)
4a594fce 671 res_alloc (sizeof (rc_res_directory)));
91d6fa6a
NC
672 (*res_dirs)->characteristics = 0;
673 (*res_dirs)->time = timeval;
674 (*res_dirs)->major = 0;
675 (*res_dirs)->minor = 0;
676 (*res_dirs)->entries = NULL;
252b5132
RH
677 }
678
91d6fa6a 679 for (pp = &(*res_dirs)->entries; *pp != NULL; pp = &(*pp)->next)
252b5132
RH
680 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
681 break;
682
683 if (*pp != NULL)
684 re = *pp;
685 else
686 {
4a594fce 687 re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
252b5132
RH
688 re->next = NULL;
689 re->id = ids[i];
690 if ((i + 1) < cids)
691 {
692 re->subdir = 1;
693 re->u.dir = NULL;
694 }
695 else
696 {
697 re->subdir = 0;
698 re->u.res = NULL;
699 }
700
701 *pp = re;
702 }
703
704 if ((i + 1) < cids)
705 {
4a594fce 706 if (! re->subdir)
252b5132
RH
707 {
708 fprintf (stderr, "%s: ", program_name);
709 res_ids_print (stderr, i, ids);
710 fprintf (stderr, ": expected to be a directory\n");
711 xexit (1);
712 }
713
91d6fa6a 714 res_dirs = &re->u.dir;
252b5132
RH
715 }
716 }
717
718 if (re->subdir)
719 {
720 fprintf (stderr, "%s: ", program_name);
721 res_ids_print (stderr, cids, ids);
722 fprintf (stderr, ": expected to be a leaf\n");
723 xexit (1);
724 }
725
726 if (re->u.res != NULL)
727 {
728 if (dupok)
729 return;
730
731 fprintf (stderr, "%s: warning: ", program_name);
732 res_ids_print (stderr, cids, ids);
733 fprintf (stderr, ": duplicate value\n");
734 }
735
736 re->u.res = resource;
737}