1 /* resres.c: read_res_file and write_res_file implementation for windres.
2    Copyright (C) 1998-2016 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 *
read_res_file(const char * fn)78 read_res_file (const char *fn)
79 {
80   rc_uint_type off, flen;
81   windres_bfd wrbfd;
82   bfd *abfd;
83   asection *sec;
84   filename = fn;
85 
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))
99     set_windres_bfd_endianness (&wrbfd, ! target_is_bigendian);
100 
101   skip_null_resource (&wrbfd, &off, flen);
102 
103   while (read_resource_entry (&wrbfd, &off, flen))
104     ;
105 
106   bfd_close (abfd);
107 
108   return resources;
109 }
110 
111 /* Write resource file */
112 void
write_res_file(const char * fn,const rc_res_directory * resdir)113 write_res_file (const char *fn,const rc_res_directory *resdir)
114 {
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[] =
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};
125 
126   filename = fn;
127 
128   abfd = windres_open_as_binary (filename, 0);
129   sec = bfd_make_section_with_flags (abfd, ".data",
130 				     (SEC_HAS_CONTENTS | SEC_ALLOC
131 				      | SEC_LOAD | SEC_DATA));
132   if (sec == NULL)
133     bfd_fatal ("bfd_make_section");
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));
140 
141   language = -1;
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);
145   if (! bfd_set_section_size (abfd, sec, (sec_length + 3) & ~3))
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)
156     fatal ("res write failed with different sizes (%lu/%lu).",
157 	   (unsigned long) sec_length, (unsigned long) sec_length_wrote);
158 
159   bfd_close (abfd);
160   return;
161 }
162 
163 /* Read a resource entry, returns 0 when all resources are read */
164 static int
read_resource_entry(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax)165 read_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
166 {
167   rc_res_id type;
168   rc_res_id name;
169   rc_res_res_info resinfo;
170   res_hdr reshdr;
171   void *buff;
172 
173   rc_res_resource *r;
174   struct bin_res_info l;
175 
176   off[0] = (off[0] + 3) & ~3;
177 
178   /* Read header */
179   if ((off[0] + 8) > omax)
180     return 0;
181   read_res_data_hdr (wrbfd, off, omax, &reshdr);
182 
183   /* read resource type */
184   read_res_id (wrbfd, off, omax, &type);
185   /* read resource id */
186   read_res_id (wrbfd, off, omax, &name);
187 
188   off[0] = (off[0] + 3) & ~3;
189 
190   /* Read additional resource header */
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);
197 
198   off[0] = (off[0] + 3) & ~3;
199 
200   /* Allocate buffer for data */
201   buff = res_alloc (reshdr.data_size);
202   /* Read data */
203   read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
204   /* Convert binary data to resource */
205   r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
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 */
214 static rc_uint_type
write_res_directory(windres_bfd * wrbfd,rc_uint_type off,const rc_res_directory * rd,const rc_res_id * type,const rc_res_id * name,rc_uint_type * language,int level)215 write_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)
218 {
219   const rc_res_entry *re;
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
235 	     we are going to use in the rc printout.  */
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.  */
242 	  if (! re->id.named
243 	      && re->id.u.id != (unsigned long) *language
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)
255 	off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
256 				   level + 1);
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.  */
266 	      off = write_res_resource (wrbfd, off, type, name, re->u.res,
267 	      				language);
268 	    }
269 	  else
270 	    {
271 	      fprintf (stderr, "// Resource at unexpected level %d\n", level);
272 	      off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
273 	      				re->u.res, language);
274 	    }
275 	}
276     }
277 
278   return off;
279 }
280 
281 static rc_uint_type
write_res_resource(windres_bfd * wrbfd,rc_uint_type off,const rc_res_id * type,const rc_res_id * name,const rc_res_resource * res,rc_uint_type * language ATTRIBUTE_UNUSED)282 write_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)
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;
352 
353     case RES_TYPE_TOOLBAR:
354       rt = RT_TOOLBAR;
355       break;
356     }
357 
358   if (rt != 0
359       && type != NULL
360       && (type->named || type->u.id != (unsigned long) rt))
361     {
362       fprintf (stderr, "// Unexpected resource type mismatch: ");
363       res_id_print (stderr, *type, 1);
364       fprintf (stderr, " != %d", rt);
365       abort ();
366     }
367 
368   return write_res_bin (wrbfd, off, res, type, name, &res->res_info);
369 }
370 
371 /* Write a resource in binary resource format */
372 static rc_uint_type
write_res_bin(windres_bfd * wrbfd,rc_uint_type off,const rc_res_resource * res,const rc_res_id * type,const rc_res_id * name,const rc_res_res_info * resinfo)373 write_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)
376 {
377   rc_uint_type noff;
378   rc_uint_type datasize = 0;
379 
380   noff = res_to_bin ((windres_bfd *) NULL, off, res);
381   datasize = noff - off;
382 
383   off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
384   return res_to_bin (wrbfd, off, res);
385 }
386 
387 /* Get number of bytes needed to store an id in binary format */
388 static unsigned long
get_id_size(const rc_res_id * id)389 get_id_size (const rc_res_id *id)
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 */
398 static rc_uint_type
write_res_header(windres_bfd * wrbfd,rc_uint_type off,rc_uint_type datasize,const rc_res_id * type,const rc_res_id * name,const rc_res_res_info * resinfo)399 write_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)
402 {
403   res_hdr reshdr;
404   reshdr.data_size = datasize;
405   reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
406 
407   reshdr.header_size = (reshdr.header_size + 3) & ~3;
408 
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);
414 
415   off = (off + 3) & ~3;
416 
417   off = write_res_info (wrbfd, off, resinfo);
418   off = (off + 3) & ~3;
419   return off;
420 }
421 
422 static rc_uint_type
write_res_data_hdr(windres_bfd * wrbfd,rc_uint_type off,res_hdr * hdr)423 write_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 }
434 
435 static void
read_res_data_hdr(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,res_hdr * reshdr)436 read_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
437 		   res_hdr *reshdr)
438 {
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;
448 }
449 
450 /* Read data from file, abort on failure */
451 static void
read_res_data(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,void * data,rc_uint_type size)452 read_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data,
453 	       rc_uint_type size)
454 {
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;
460 }
461 
462 /* Write a resource id */
463 static rc_uint_type
write_res_id(windres_bfd * wrbfd,rc_uint_type off,const rc_res_id * id)464 write_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id)
465 {
466   if (id->named)
467     {
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));
479     }
480   else
481     {
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;
490     }
491   return off;
492 }
493 
494 /* Write resource info */
495 static rc_uint_type
write_res_info(windres_bfd * wrbfd,rc_uint_type off,const rc_res_res_info * info)496 write_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info)
497 {
498   if (wrbfd)
499     {
500       struct bin_res_info l;
501 
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;
510 }
511 
512 /* read a resource identifier */
513 static void
read_res_id(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,rc_res_id * id)514 read_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id)
515 {
516   struct bin_res_id bid;
517   unsigned short ord;
518   unichar *id_s = NULL;
519   rc_uint_type len;
520 
521   read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2);
522   ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2);
523   if (ord == 0xFFFF)		/* an ordinal id */
524     {
525       read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2);
526       id->named = 0;
527       id->u.id = windres_get_16 (wrbfd, bid.id, 2);
528     }
529   else
530     /* named id */
531     {
532       off[0] -= 2;
533       id_s = read_unistring (wrbfd, off, omax, &len);
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 */
541 static unichar *
read_unistring(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,rc_uint_type * len)542 read_unistring (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
543 		rc_uint_type *len)
544 {
545   unichar *s;
546   bfd_byte d[2];
547   unichar c;
548   unichar *p;
549   rc_uint_type l;
550   rc_uint_type soff = off[0];
551 
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);
558   l = ((soff - off[0]) / sizeof (unichar));
559 
560   /* there are hardly any names longer than 256 characters, but anyway. */
561   p = s = (unichar *) xmalloc (sizeof (unichar) * l);
562   do
563     {
564       read_res_data (wrbfd, off, omax, d, sizeof (unichar));
565       c = windres_get_16 (wrbfd, d, 2);
566       *p++ = c;
567     }
568   while (c != 0);
569   *len = l - 1;
570   return s;
571 }
572 
573 static int
probe_binary(windres_bfd * wrbfd,rc_uint_type omax)574 probe_binary (windres_bfd *wrbfd, rc_uint_type omax)
575 {
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);
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;
597   return 1;
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  */
604 static void
skip_null_resource(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax)605 skip_null_resource (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
606 {
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))
613     goto skip_err;
614 
615   /* Subtract size of HeaderSize. DataSize has to be zero. */
616   off[0] += 0x20 - BIN_RES_HDR_SIZE;
617   if (off[0] >= omax)
618     goto skip_err;
619 
620   return;
621 
622 skip_err:
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 */
629 static void
res_add_resource(rc_res_resource * r,const rc_res_id * type,const rc_res_id * id,rc_uint_type language,int dupok)630 res_add_resource (rc_res_resource *r, const rc_res_id *type, const rc_res_id *id,
631 		  rc_uint_type language, int dupok)
632 {
633   rc_res_id a[3];
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  */
646 static void
res_append_resource(rc_res_directory ** res_dirs,rc_res_resource * resource,int cids,const rc_res_id * ids,int dupok)647 res_append_resource (rc_res_directory **res_dirs, rc_res_resource *resource,
648 		     int cids, const rc_res_id *ids, int dupok)
649 {
650   rc_res_entry *re = NULL;
651   int i;
652 
653   assert (cids > 0);
654   for (i = 0; i < cids; i++)
655     {
656       rc_res_entry **pp;
657 
658       if (*res_dirs == NULL)
659 	{
660 	  *res_dirs = ((rc_res_directory *)
661 			res_alloc (sizeof (rc_res_directory)));
662 
663 	  (*res_dirs)->characteristics = 0;
664 	  /* Using a real timestamp only serves to create non-deterministic
665 	     results.  Use zero instead.  */
666 	  (*res_dirs)->time = 0;
667 	  (*res_dirs)->major = 0;
668 	  (*res_dirs)->minor = 0;
669 	  (*res_dirs)->entries = NULL;
670 	}
671 
672       for (pp = &(*res_dirs)->entries; *pp != NULL; pp = &(*pp)->next)
673 	if (res_id_cmp ((*pp)->id, ids[i]) == 0)
674 	  break;
675 
676       if (*pp != NULL)
677 	re = *pp;
678       else
679 	{
680 	  re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
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 	{
699 	  if (! re->subdir)
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 
707 	  res_dirs = &re->u.dir;
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 }
731