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>.
5 This file is part of GNU Binutils.
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.
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.
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
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. */
28 #include "libiberty.h"
36 unsigned long data_size
;
37 unsigned long header_size
;
40 static void write_res_directory
41 PARAMS ((const struct res_directory
*,
42 const struct res_id
*, const struct res_id
*,
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
*));
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
*));
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));
64 static unsigned long get_id_size
PARAMS ((const struct res_id
*));
65 static void res_align_file
PARAMS ((void));
69 PARAMS ((struct res_resource
*, const struct res_id
*,
70 const struct res_id
*, int, int));
74 PARAMS ((struct res_directory
**, struct res_resource
*,
75 int, const struct res_id
*, int));
77 static struct res_directory
*resources
= NULL
;
80 static const char *filename
;
82 extern char *program_name
;
84 /* Read resource file */
85 struct res_directory
*
90 fres
= fopen (filename
, "rb");
92 fatal ("can't open `%s' for output: %s", filename
, strerror (errno
));
94 skip_null_resource ();
96 while (read_resource_entry ())
104 /* Write resource file */
106 write_res_file (fn
, resdir
)
108 const struct res_directory
*resdir
;
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};
120 fres
= fopen (filename
, "wb");
122 fatal ("can't open `%s' for output: %s", filename
, strerror (errno
));
124 /* Write 32 bit resource signature */
125 write_res_data (sign
, sizeof (sign
), 1);
127 /* write resources */
130 write_res_directory (resdir
, (const struct res_id
*) NULL
,
131 (const struct res_id
*) NULL
, &language
, 1);
133 /* end file on DWORD boundary */
136 write_res_data (sign
, fpos
% 4, 1);
141 /* Read a resource entry, returns 0 when all resources are read */
143 read_resource_entry (void)
147 struct res_res_info resinfo
;
148 struct res_hdr reshdr
;
152 struct res_resource
*r
;
157 if (fread (&reshdr
, sizeof (reshdr
), 1, fres
) != 1)
160 /* read resource type */
162 /* read resource id */
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);
176 /* Allocate buffer for data */
177 buff
= res_alloc (reshdr
.data_size
);
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);
189 /* write resource directory to binary resource file */
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
;
198 const struct res_entry
*re
;
200 for (re
= rd
->entries
; re
!= NULL
; re
= re
->next
)
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. */
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. */
219 /* If we're at level 3, then this key represents a language.
220 Use it to update the current language. */
222 && re
->id
.u
.id
!= (unsigned long) *language
223 && (re
->id
.u
.id
& 0xffff) == re
->id
.u
.id
)
225 *language
= re
->id
.u
.id
;
234 write_res_directory (re
->u
.dir
, type
, name
, language
, level
+ 1);
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
);
248 fprintf (stderr
, "// Resource at unexpected level %d\n", level
);
249 write_res_resource (type
, (struct res_id
*) NULL
, re
->u
.res
,
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
;
271 case RES_TYPE_ACCELERATOR
:
275 case RES_TYPE_BITMAP
:
279 case RES_TYPE_CURSOR
:
283 case RES_TYPE_GROUP_CURSOR
:
284 rt
= RT_GROUP_CURSOR
;
287 case RES_TYPE_DIALOG
:
295 case RES_TYPE_FONTDIR
:
303 case RES_TYPE_GROUP_ICON
:
311 case RES_TYPE_MESSAGETABLE
:
312 rt
= RT_MESSAGETABLE
;
315 case RES_TYPE_RCDATA
:
319 case RES_TYPE_STRINGTABLE
:
323 case RES_TYPE_USERDATA
:
327 case RES_TYPE_VERSIONINFO
:
334 && (type
->named
|| type
->u
.id
!= (unsigned long) rt
))
336 fprintf (stderr
, "// Unexpected resource type mismatch: ");
337 res_id_print (stderr
, *type
, 1);
338 fprintf (stderr
, " != %d", rt
);
342 write_res_bin (res
, type
, name
, &res
->res_info
);
346 /* Write a resource in binary resource format */
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
;
354 unsigned long datasize
= 0;
355 const struct bindata
*bin_rep
, *data
;
357 bin_rep
= res_to_bin (res
, 0);
358 for (data
= bin_rep
; data
!= NULL
; data
= data
->next
)
359 datasize
+= data
->length
;
361 write_res_header (datasize
, type
, name
, resinfo
);
363 for (data
= bin_rep
; data
!= NULL
; data
= data
->next
)
364 write_res_data (data
->data
, data
->length
, 1);
367 /* Get number of bytes needed to store an id in binary format */
370 const struct res_id
*id
;
373 return sizeof (unichar
) * (id
->u
.n
.length
+ 1);
375 return sizeof (unichar
) * 2;
378 /* Write a resource header */
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
;
386 struct res_hdr reshdr
;
387 reshdr
.data_size
= datasize
;
388 reshdr
.header_size
= 24 + get_id_size (type
) + get_id_size (name
);
390 reshdr
.header_size
= (reshdr
.header_size
+ 3) & ~3;
393 write_res_data (&reshdr
, sizeof (reshdr
), 1);
399 write_res_info (resinfo
);
404 /* Write data to file, abort on failure */
406 write_res_data (data
, size
, count
)
411 if ((size_t) fwrite (data
, size
, count
, fres
) != (size_t) count
)
412 fatal ("%s: could not write to file", filename
);
415 /* Read data from file, abort on failure */
417 read_res_data (data
, size
, count
)
422 if (fread (data
, size
, count
, fres
) != (size_t) count
)
423 fatal ("%s: unexpected end of file", filename
);
426 /* Write a resource id */
429 const struct res_id
*id
;
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);
440 unsigned short i
= 0xFFFF;
441 write_res_data (&i
, sizeof (i
), 1);
443 write_res_data (&i
, sizeof (i
), 1);
447 /* Write resource info */
449 write_res_info (info
)
450 const struct res_res_info
*info
;
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);
459 /* read a resource identifier */
465 unichar
*id_s
= NULL
;
468 read_res_data (&ord
, sizeof (ord
), 1);
469 if (ord
== 0xFFFF) /* an ordinal id */
471 read_res_data (&ord
, sizeof (ord
), 1);
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
);
482 id
->u
.n
.length
= len
;
487 /* Read a null terminated UNICODE string */
500 /* there are hardly any names longer than 256 characters */
501 p
= s
= (unichar
*) xmalloc (sizeof (unichar
) * 256);
504 read_res_data (&c
, sizeof (c
), 1);
514 /* align file on DWORD boundary */
516 res_align_file (void)
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
);
524 /* Check if file is a win32 binary resource file, if so
525 skip past the null resource. Returns 0 if successful, -1 on
529 skip_null_resource (void)
531 struct res_hdr reshdr
=
533 read_res_data (&reshdr
, sizeof (reshdr
), 1);
534 if ((reshdr
.data_size
!= 0) || (reshdr
.header_size
!= 0x20))
537 /* Subtract size of HeaderSize and DataSize */
538 if (fseek (fres
, reshdr
.header_size
- 8, SEEK_CUR
) != 0)
544 fprintf (stderr
, "%s: %s: Not a valid WIN32 resource file\n", program_name
,
549 /* Add a resource to resource directory */
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
;
563 a
[2].u
.id
= language
;
564 res_append_resource (&resources
, r
, 3, a
, dupok
);
567 /* Append a resource to resource directory.
568 This is just copied from define_resource
569 and modified to add an existing resource.
572 res_append_resource (resources
, resource
, cids
, ids
, dupok
)
573 struct res_directory
**resources
;
574 struct res_resource
*resource
;
576 const struct res_id
*ids
;
579 struct res_entry
*re
= NULL
;
583 for (i
= 0; i
< cids
; i
++)
585 struct res_entry
**pp
;
587 if (*resources
== NULL
)
589 static unsigned long timeval
;
591 /* Use the same timestamp for every resource created in a
594 timeval
= time (NULL
);
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
;
605 for (pp
= &(*resources
)->entries
; *pp
!= NULL
; pp
= &(*pp
)->next
)
606 if (res_id_cmp ((*pp
)->id
, ids
[i
]) == 0)
613 re
= (struct res_entry
*) res_alloc (sizeof *re
);
634 fprintf (stderr
, "%s: ", program_name
);
635 res_ids_print (stderr
, i
, ids
);
636 fprintf (stderr
, ": expected to be a directory\n");
640 resources
= &re
->u
.dir
;
646 fprintf (stderr
, "%s: ", program_name
);
647 res_ids_print (stderr
, cids
, ids
);
648 fprintf (stderr
, ": expected to be a leaf\n");
652 if (re
->u
.res
!= NULL
)
657 fprintf (stderr
, "%s: warning: ", program_name
);
658 res_ids_print (stderr
, cids
, ids
);
659 fprintf (stderr
, ": duplicate value\n");
662 re
->u
.res
= resource
;