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