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