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