Coverage Report

Created: 2025-07-08 11:15

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