1 /* resres.c: read_res_file and write_res_file implementation for windres.
3 Copyright 1998, 1999 Free Software Foundation, Inc.
4 Written by Anders Norlander <anorland@hem2.passagen.se>.
6 This file is part of GNU Binutils.
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 2 of the License, or
11 (at your option) any later version.
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.
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., 59 Temple Place - Suite 330, Boston, MA
25 #include "libiberty.h"
33 unsigned long data_size
;
34 unsigned long header_size
;
37 static void write_res_directory
38 PARAMS ((const struct res_directory
*,
39 const struct res_id
*, const struct res_id
*,
41 static void write_res_resource
42 PARAMS ((const struct res_id
*, const struct res_id
*,
43 const struct res_resource
*, int *));
44 static void write_res_bin
45 PARAMS ((const struct res_resource
*, const struct res_id
*,
46 const struct res_id
*, const struct res_res_info
*));
48 static void write_res_id
PARAMS ((const struct res_id
*));
49 static void write_res_info
PARAMS ((const struct res_res_info
*));
50 static void write_res_data
PARAMS ((const void *, size_t, int));
51 static void write_res_header
52 PARAMS ((unsigned long, const struct res_id
*, const struct res_id
*,
53 const struct res_res_info
*));
55 static int read_resource_entry
PARAMS ((void));
56 static void read_res_data
PARAMS ((void *, size_t, int));
57 static void read_res_id
PARAMS ((struct res_id
*));
58 static unichar
*read_unistring
PARAMS ((int *));
59 static void skip_null_resource
PARAMS ((void));
61 static unsigned long get_id_size
PARAMS ((const struct res_id
*));
62 static void res_align_file
PARAMS ((void));
66 PARAMS ((struct res_resource
*, const struct res_id
*,
67 const struct res_id
*, int, int));
71 PARAMS ((struct res_directory
**, struct res_resource
*,
72 int, const struct res_id
*, int));
74 static struct res_directory
*resources
= NULL
;
77 static const char *filename
;
79 extern char *program_name
;
81 /* Read resource file */
82 struct res_directory
*
87 fres
= fopen (filename
, "rb");
89 fatal ("can't open `%s' for output: %s", filename
, strerror (errno
));
91 skip_null_resource ();
93 while (read_resource_entry ())
101 /* Write resource file */
103 write_res_file (fn
, resdir
)
105 const struct res_directory
*resdir
;
108 static const unsigned char sign
[] =
109 {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
110 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
117 fres
= fopen (filename
, "wb");
119 fatal ("can't open `%s' for output: %s", filename
, strerror (errno
));
121 /* Write 32 bit resource signature */
122 write_res_data (sign
, sizeof (sign
), 1);
124 /* write resources */
127 write_res_directory (resdir
, (const struct res_id
*) NULL
,
128 (const struct res_id
*) NULL
, &language
, 1);
130 /* end file on DWORD boundary */
133 write_res_data (sign
, fpos
% 4, 1);
138 /* Read a resource entry, returns 0 when all resources are read */
140 read_resource_entry (void)
144 struct res_res_info resinfo
;
145 struct res_hdr reshdr
;
149 struct res_resource
*r
;
154 if (fread (&reshdr
, sizeof (reshdr
), 1, fres
) != 1)
157 /* read resource type */
159 /* read resource id */
164 /* Read additional resource header */
165 read_res_data (&resinfo
.version
, sizeof (resinfo
.version
), 1);
166 read_res_data (&resinfo
.memflags
, sizeof (resinfo
.memflags
), 1);
167 read_res_data (&resinfo
.language
, sizeof (resinfo
.language
), 1);
168 read_res_data (&version
, sizeof (version
), 1);
169 read_res_data (&resinfo
.characteristics
, sizeof (resinfo
.characteristics
), 1);
173 /* Allocate buffer for data */
174 buff
= res_alloc (reshdr
.data_size
);
176 read_res_data (buff
, reshdr
.data_size
, 1);
177 /* Convert binary data to resource */
178 r
= bin_to_res (type
, buff
, reshdr
.data_size
, 0);
179 r
->res_info
= resinfo
;
180 /* Add resource to resource directory */
181 res_add_resource (r
, &type
, &name
, resinfo
.language
, 0);
186 /* write resource directory to binary resource file */
188 write_res_directory (rd
, type
, name
, language
, level
)
189 const struct res_directory
*rd
;
190 const struct res_id
*type
;
191 const struct res_id
*name
;
195 const struct res_entry
*re
;
197 for (re
= rd
->entries
; re
!= NULL
; re
= re
->next
)
202 /* If we're at level 1, the key of this resource is the
203 type. This normally duplicates the information we have
204 stored with the resource itself, but we need to remember
205 the type if this is a user define resource type. */
210 /* If we're at level 2, the key of this resource is the name
211 we are going to use in the rc printout. */
216 /* If we're at level 3, then this key represents a language.
217 Use it to update the current language. */
219 && re
->id
.u
.id
!= *language
220 && (re
->id
.u
.id
& 0xffff) == re
->id
.u
.id
)
222 *language
= re
->id
.u
.id
;
231 write_res_directory (re
->u
.dir
, type
, name
, language
, level
+ 1);
236 /* This is the normal case: the three levels are
237 TYPE/NAME/LANGUAGE. NAME will have been set at level
238 2, and represents the name to use. We probably just
239 set LANGUAGE, and it will probably match what the
240 resource itself records if anything. */
241 write_res_resource (type
, name
, re
->u
.res
, language
);
245 fprintf (stderr
, "// Resource at unexpected level %d\n", level
);
246 write_res_resource (type
, (struct res_id
*) NULL
, re
->u
.res
,
255 write_res_resource (type
, name
, res
, language
)
256 const struct res_id
*type
;
257 const struct res_id
*name
;
258 const struct res_resource
*res
;
268 case RES_TYPE_ACCELERATOR
:
272 case RES_TYPE_BITMAP
:
276 case RES_TYPE_CURSOR
:
280 case RES_TYPE_GROUP_CURSOR
:
281 rt
= RT_GROUP_CURSOR
;
284 case RES_TYPE_DIALOG
:
292 case RES_TYPE_FONTDIR
:
300 case RES_TYPE_GROUP_ICON
:
308 case RES_TYPE_MESSAGETABLE
:
309 rt
= RT_MESSAGETABLE
;
312 case RES_TYPE_RCDATA
:
316 case RES_TYPE_STRINGTABLE
:
320 case RES_TYPE_USERDATA
:
324 case RES_TYPE_VERSIONINFO
:
331 && (type
->named
|| type
->u
.id
!= rt
))
333 fprintf (stderr
, "// Unexpected resource type mismatch: ");
334 res_id_print (stderr
, *type
, 1);
335 fprintf (stderr
, " != %d", rt
);
339 write_res_bin (res
, type
, name
, &res
->res_info
);
343 /* Write a resource in binary resource format */
345 write_res_bin (res
, type
, name
, resinfo
)
346 const struct res_resource
*res
;
347 const struct res_id
*type
;
348 const struct res_id
*name
;
349 const struct res_res_info
*resinfo
;
351 unsigned long datasize
= 0;
352 const struct bindata
*bin_rep
, *data
;
354 bin_rep
= res_to_bin (res
, 0);
355 for (data
= bin_rep
; data
!= NULL
; data
= data
->next
)
356 datasize
+= data
->length
;
358 write_res_header (datasize
, type
, name
, resinfo
);
360 for (data
= bin_rep
; data
!= NULL
; data
= data
->next
)
361 write_res_data (data
->data
, data
->length
, 1);
364 /* Get number of bytes needed to store an id in binary format */
367 const struct res_id
*id
;
370 return sizeof (unichar
) * (id
->u
.n
.length
+ 1);
372 return sizeof (unichar
) * 2;
375 /* Write a resource header */
377 write_res_header (datasize
, type
, name
, resinfo
)
378 unsigned long datasize
;
379 const struct res_id
*type
;
380 const struct res_id
*name
;
381 const struct res_res_info
*resinfo
;
383 struct res_hdr reshdr
;
384 reshdr
.data_size
= datasize
;
385 reshdr
.header_size
= 24 + get_id_size (type
) + get_id_size (name
);
388 write_res_data (&reshdr
, sizeof (reshdr
), 1);
394 write_res_info (resinfo
);
399 /* Write data to file, abort on failure */
401 write_res_data (data
, size
, count
)
406 if (fwrite (data
, size
, count
, fres
) != count
)
407 fatal ("%s: %s: could not write to file", program_name
, filename
);
410 /* Read data from file, abort on failure */
412 read_res_data (data
, size
, count
)
417 if (fread (data
, size
, count
, fres
) != count
)
418 fatal ("%s: %s: unexpected end of file", program_name
, filename
);
421 /* Write a resource id */
424 const struct res_id
*id
;
428 unsigned long len
= id
->u
.n
.length
;
429 unichar null_term
= 0;
430 write_res_data (id
->u
.n
.name
, len
* sizeof (unichar
), 1);
431 write_res_data (&null_term
, sizeof (null_term
), 1);
435 unsigned short i
= 0xFFFF;
436 write_res_data (&i
, sizeof (i
), 1);
438 write_res_data (&i
, sizeof (i
), 1);
442 /* Write resource info */
444 write_res_info (info
)
445 const struct res_res_info
*info
;
447 write_res_data (&info
->version
, sizeof (info
->version
), 1);
448 write_res_data (&info
->memflags
, sizeof (info
->memflags
), 1);
449 write_res_data (&info
->language
, sizeof (info
->language
), 1);
450 write_res_data (&info
->version
, sizeof (info
->version
), 1);
451 write_res_data (&info
->characteristics
, sizeof (info
->characteristics
), 1);
454 /* read a resource identifier */
460 unichar
*id_s
= NULL
;
463 read_res_data (&ord
, sizeof (ord
), 1);
464 if (ord
== 0xFFFF) /* an ordinal id */
466 read_res_data (&ord
, sizeof (ord
), 1);
473 if (fseek (fres
, -sizeof (ord
), SEEK_CUR
) != 0)
474 fatal ("%s: %s: could not seek in file", program_name
, filename
);
475 id_s
= read_unistring (&len
);
477 id
->u
.n
.length
= len
;
482 /* Read a null terminated UNICODE string */
495 /* there are hardly any names longer than 256 characters */
496 p
= s
= (unichar
*) xmalloc (sizeof (unichar
) * 256);
499 read_res_data (&c
, sizeof (c
), 1);
509 /* align file on DWORD boundary */
511 res_align_file (void)
513 if (fseek (fres
, ftell (fres
) % 4, SEEK_CUR
) != 0)
514 fatal ("%s: %s: unable to align file", program_name
, filename
);
517 /* Check if file is a win32 binary resource file, if so
518 skip past the null resource. Returns 0 if successful, -1 on
522 skip_null_resource (void)
524 struct res_hdr reshdr
=
526 read_res_data (&reshdr
, sizeof (reshdr
), 1);
527 if ((reshdr
.data_size
!= 0) || (reshdr
.header_size
!= 0x20))
530 /* Subtract size of HeaderSize and DataSize */
531 if (fseek (fres
, reshdr
.header_size
- 8, SEEK_CUR
) != 0)
537 fprintf (stderr
, "%s: %s: Not a valid WIN32 resource file\n", program_name
,
542 /* Add a resource to resource directory */
544 res_add_resource (r
, type
, id
, language
, dupok
)
545 struct res_resource
*r
;
546 const struct res_id
*type
;
547 const struct res_id
*id
;
556 a
[2].u
.id
= language
;
557 res_append_resource (&resources
, r
, 3, a
, dupok
);
560 /* Append a resource to resource directory.
561 This is just copied from define_resource
562 and modified to add an existing resource.
565 res_append_resource (resources
, resource
, cids
, ids
, dupok
)
566 struct res_directory
**resources
;
567 struct res_resource
*resource
;
569 const struct res_id
*ids
;
572 struct res_entry
*re
= NULL
;
576 for (i
= 0; i
< cids
; i
++)
578 struct res_entry
**pp
;
580 if (*resources
== NULL
)
582 static unsigned long timeval
;
584 /* Use the same timestamp for every resource created in a
587 timeval
= time (NULL
);
589 *resources
= ((struct res_directory
*)
590 res_alloc (sizeof **resources
));
591 (*resources
)->characteristics
= 0;
592 (*resources
)->time
= timeval
;
593 (*resources
)->major
= 0;
594 (*resources
)->minor
= 0;
595 (*resources
)->entries
= NULL
;
598 for (pp
= &(*resources
)->entries
; *pp
!= NULL
; pp
= &(*pp
)->next
)
599 if (res_id_cmp ((*pp
)->id
, ids
[i
]) == 0)
606 re
= (struct res_entry
*) res_alloc (sizeof *re
);
627 fprintf (stderr
, "%s: ", program_name
);
628 res_ids_print (stderr
, i
, ids
);
629 fprintf (stderr
, ": expected to be a directory\n");
633 resources
= &re
->u
.dir
;
639 fprintf (stderr
, "%s: ", program_name
);
640 res_ids_print (stderr
, cids
, ids
);
641 fprintf (stderr
, ": expected to be a leaf\n");
645 if (re
->u
.res
!= NULL
)
650 fprintf (stderr
, "%s: warning: ", program_name
);
651 res_ids_print (stderr
, cids
, ids
);
652 fprintf (stderr
, ": duplicate value\n");
655 re
->u
.res
= resource
;