/src/binutils-gdb/binutils/fuzz_windres.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* windres.c -- a program to manipulate Windows resources |
2 | | Copyright (C) 1997-2023 Free Software Foundation, Inc. |
3 | | Written by Ian Lance Taylor, Cygnus Support. |
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 | | /* This program can read and write Windows resources in various |
24 | | formats. In particular, it can act like the rc resource compiler |
25 | | program, and it can act like the cvtres res to COFF conversion |
26 | | program. |
27 | | |
28 | | It is based on information taken from the following sources: |
29 | | |
30 | | * Microsoft documentation. |
31 | | |
32 | | * The rcl program, written by Gunther Ebert |
33 | | <gunther.ebert@ixos-leipzig.de>. |
34 | | |
35 | | * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */ |
36 | | |
37 | | #include "sysdep.h" |
38 | | #include <assert.h> |
39 | | #include "bfd.h" |
40 | | #include "getopt.h" |
41 | | #include "bucomm.h" |
42 | | #include "libiberty.h" |
43 | | #include "safe-ctype.h" |
44 | | #include "obstack.h" |
45 | | #include "windres.h" |
46 | | |
47 | | /* Used by resrc.c at least. */ |
48 | | |
49 | | int verbose = 0; |
50 | | |
51 | | bool target_is_bigendian = 0; |
52 | | const char *def_target_arch; |
53 | | |
54 | | static void set_endianness (bfd *, const char *); |
55 | | |
56 | | /* An enumeration of format types. */ |
57 | | |
58 | | enum res_format |
59 | | { |
60 | | /* Unknown format. */ |
61 | | RES_FORMAT_UNKNOWN, |
62 | | /* Textual RC file. */ |
63 | | RES_FORMAT_RC, |
64 | | /* Binary RES file. */ |
65 | | RES_FORMAT_RES, |
66 | | /* COFF file. */ |
67 | | RES_FORMAT_COFF |
68 | | }; |
69 | | |
70 | | /* A structure used to map between format types and strings. */ |
71 | | |
72 | | struct format_map |
73 | | { |
74 | | const char *name; |
75 | | enum res_format format; |
76 | | }; |
77 | | |
78 | | /* A mapping between names and format types. */ |
79 | | |
80 | | static const struct format_map format_names[] = |
81 | | { |
82 | | { "rc", RES_FORMAT_RC }, |
83 | | { "res", RES_FORMAT_RES }, |
84 | | { "coff", RES_FORMAT_COFF }, |
85 | | { NULL, RES_FORMAT_UNKNOWN } |
86 | | }; |
87 | | |
88 | | /* A mapping from file extensions to format types. */ |
89 | | |
90 | | static const struct format_map format_fileexts[] = |
91 | | { |
92 | | { "rc", RES_FORMAT_RC }, |
93 | | { "res", RES_FORMAT_RES }, |
94 | | { "exe", RES_FORMAT_COFF }, |
95 | | { "obj", RES_FORMAT_COFF }, |
96 | | { "o", RES_FORMAT_COFF }, |
97 | | { NULL, RES_FORMAT_UNKNOWN } |
98 | | }; |
99 | | |
100 | | /* A list of include directories. */ |
101 | | |
102 | | struct include_dir |
103 | | { |
104 | | struct include_dir *next; |
105 | | char *dir; |
106 | | }; |
107 | | |
108 | | static struct include_dir *include_dirs; |
109 | | |
110 | | /* Static functions. */ |
111 | | |
112 | | static void res_init (void); |
113 | | static int extended_menuitems (const rc_menuitem *); |
114 | | static enum res_format format_from_name (const char *, int); |
115 | | static enum res_format format_from_filename (const char *, int); |
116 | | static void usage (FILE *, int); |
117 | | static int cmp_res_entry (const void *, const void *); |
118 | | static rc_res_directory *sort_resources (rc_res_directory *); |
119 | | static void reswr_init (void); |
120 | | static const char * quot (const char *); |
121 | | |
122 | | static rc_uint_type target_get_8 (const void *, rc_uint_type); |
123 | | static void target_put_8 (void *, rc_uint_type); |
124 | | static rc_uint_type target_get_16 (const void *, rc_uint_type); |
125 | | static void target_put_16 (void *, rc_uint_type); |
126 | | static rc_uint_type target_get_32 (const void *, rc_uint_type); |
127 | | static void target_put_32 (void *, rc_uint_type); |
128 | | |
129 | | |
130 | | /* When we are building a resource tree, we allocate everything onto |
131 | | an obstack, so that we can free it all at once if we want. */ |
132 | | |
133 | | #define obstack_chunk_alloc xmalloc |
134 | | #define obstack_chunk_free free |
135 | | |
136 | | /* The resource building obstack. */ |
137 | | |
138 | | static struct obstack res_obstack; |
139 | | |
140 | | /* Initialize the resource building obstack. */ |
141 | | |
142 | | static void |
143 | | res_init (void) |
144 | 0 | { |
145 | 0 | obstack_init (&res_obstack); |
146 | 0 | } |
147 | | |
148 | | /* Allocate space on the resource building obstack. */ |
149 | | |
150 | | void * |
151 | | res_alloc (rc_uint_type bytes) |
152 | 0 | { |
153 | 0 | return obstack_alloc (&res_obstack, (size_t) bytes); |
154 | 0 | } |
155 | | |
156 | | /* We also use an obstack to save memory used while writing out a set |
157 | | of resources. */ |
158 | | |
159 | | static struct obstack reswr_obstack; |
160 | | |
161 | | /* Initialize the resource writing obstack. */ |
162 | | |
163 | | static void |
164 | | reswr_init (void) |
165 | 0 | { |
166 | 0 | obstack_init (&reswr_obstack); |
167 | 0 | } |
168 | | |
169 | | /* Allocate space on the resource writing obstack. */ |
170 | | |
171 | | void * |
172 | | reswr_alloc (rc_uint_type bytes) |
173 | 0 | { |
174 | 0 | return obstack_alloc (&reswr_obstack, (size_t) bytes); |
175 | 0 | } |
176 | | |
177 | | /* Open a file using the include directory search list. */ |
178 | | |
179 | | FILE * |
180 | | open_file_search (const char *filename, const char *mode, const char *errmsg, |
181 | | char **real_filename) |
182 | 0 | { |
183 | 0 | FILE *e; |
184 | 0 | struct include_dir *d; |
185 | |
|
186 | 0 | e = fopen (filename, mode); |
187 | 0 | if (e != NULL) |
188 | 0 | { |
189 | 0 | *real_filename = xstrdup (filename); |
190 | 0 | return e; |
191 | 0 | } |
192 | | |
193 | 0 | if (errno == ENOENT) |
194 | 0 | { |
195 | 0 | for (d = include_dirs; d != NULL; d = d->next) |
196 | 0 | { |
197 | 0 | char *n; |
198 | |
|
199 | 0 | n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2); |
200 | 0 | sprintf (n, "%s/%s", d->dir, filename); |
201 | 0 | e = fopen (n, mode); |
202 | 0 | if (e != NULL) |
203 | 0 | { |
204 | 0 | *real_filename = n; |
205 | 0 | return e; |
206 | 0 | } |
207 | 0 | free (n); |
208 | |
|
209 | 0 | if (errno != ENOENT) |
210 | 0 | break; |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | 0 | fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno)); |
215 | | |
216 | | /* Return a value to avoid a compiler warning. */ |
217 | 0 | return NULL; |
218 | 0 | } |
219 | | |
220 | | /* Compare two resource ID's. We consider name entries to come before |
221 | | numeric entries, because that is how they appear in the COFF .rsrc |
222 | | section. */ |
223 | | |
224 | | int |
225 | | res_id_cmp (rc_res_id a, rc_res_id b) |
226 | 0 | { |
227 | 0 | if (! a.named) |
228 | 0 | { |
229 | 0 | if (b.named) |
230 | 0 | return 1; |
231 | 0 | if (a.u.id > b.u.id) |
232 | 0 | return 1; |
233 | 0 | else if (a.u.id < b.u.id) |
234 | 0 | return -1; |
235 | 0 | else |
236 | 0 | return 0; |
237 | 0 | } |
238 | 0 | else |
239 | 0 | { |
240 | 0 | unichar *as, *ase, *bs, *bse; |
241 | |
|
242 | 0 | if (! b.named) |
243 | 0 | return -1; |
244 | | |
245 | 0 | as = a.u.n.name; |
246 | 0 | ase = as + a.u.n.length; |
247 | 0 | bs = b.u.n.name; |
248 | 0 | bse = bs + b.u.n.length; |
249 | |
|
250 | 0 | while (as < ase) |
251 | 0 | { |
252 | 0 | int i; |
253 | |
|
254 | 0 | if (bs >= bse) |
255 | 0 | return 1; |
256 | 0 | i = (int) *as - (int) *bs; |
257 | 0 | if (i != 0) |
258 | 0 | return i; |
259 | 0 | ++as; |
260 | 0 | ++bs; |
261 | 0 | } |
262 | | |
263 | 0 | if (bs < bse) |
264 | 0 | return -1; |
265 | | |
266 | 0 | return 0; |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | | /* Print a resource ID. */ |
271 | | |
272 | | void |
273 | | res_id_print (FILE *stream, rc_res_id id, int quote) |
274 | 0 | { |
275 | 0 | if (! id.named) |
276 | 0 | fprintf (stream, "%u", (int) id.u.id); |
277 | 0 | else |
278 | 0 | { |
279 | 0 | if (quote) |
280 | 0 | unicode_print_quoted (stream, id.u.n.name, id.u.n.length); |
281 | 0 | else |
282 | 0 | unicode_print (stream, id.u.n.name, id.u.n.length); |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | /* Print a list of resource ID's. */ |
287 | | |
288 | | void |
289 | | res_ids_print (FILE *stream, int cids, const rc_res_id *ids) |
290 | 0 | { |
291 | 0 | int i; |
292 | |
|
293 | 0 | for (i = 0; i < cids; i++) |
294 | 0 | { |
295 | 0 | res_id_print (stream, ids[i], 1); |
296 | 0 | if (i + 1 < cids) |
297 | 0 | fprintf (stream, ": "); |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | | /* Convert an ASCII string to a resource ID. */ |
302 | | |
303 | | void |
304 | | res_string_to_id (rc_res_id *res_id, const char *string) |
305 | 0 | { |
306 | 0 | res_id->named = 1; |
307 | 0 | unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string); |
308 | 0 | } |
309 | | |
310 | | /* Convert an unicode string to a resource ID. */ |
311 | | void |
312 | | res_unistring_to_id (rc_res_id *res_id, const unichar *u) |
313 | 0 | { |
314 | 0 | res_id->named = 1; |
315 | 0 | res_id->u.n.length = unichar_len (u); |
316 | 0 | res_id->u.n.name = unichar_dup_uppercase (u); |
317 | 0 | } |
318 | | |
319 | | /* Define a resource. The arguments are the resource tree, RESOURCES, |
320 | | and the location at which to put it in the tree, CIDS and IDS. |
321 | | This returns a newly allocated rc_res_resource structure, which the |
322 | | caller is expected to initialize. If DUPOK is non-zero, then if a |
323 | | resource with this ID exists, it is returned. Otherwise, a warning |
324 | | is issued, and a new resource is created replacing the existing |
325 | | one. */ |
326 | | |
327 | | rc_res_resource * |
328 | | define_resource (rc_res_directory **resources, int cids, |
329 | | const rc_res_id *ids, int dupok) |
330 | 0 | { |
331 | 0 | rc_res_entry *re = NULL; |
332 | 0 | int i; |
333 | |
|
334 | 0 | assert (cids > 0); |
335 | 0 | for (i = 0; i < cids; i++) |
336 | 0 | { |
337 | 0 | rc_res_entry **pp; |
338 | |
|
339 | 0 | if (*resources == NULL) |
340 | 0 | { |
341 | 0 | *resources = ((rc_res_directory *) |
342 | 0 | res_alloc (sizeof (rc_res_directory))); |
343 | 0 | (*resources)->characteristics = 0; |
344 | | /* Using a real timestamp only serves to create non-deterministic |
345 | | results. Use zero instead. */ |
346 | 0 | (*resources)->time = 0; |
347 | 0 | (*resources)->major = 0; |
348 | 0 | (*resources)->minor = 0; |
349 | 0 | (*resources)->entries = NULL; |
350 | 0 | } |
351 | |
|
352 | 0 | for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next) |
353 | 0 | if (res_id_cmp ((*pp)->id, ids[i]) == 0) |
354 | 0 | break; |
355 | |
|
356 | 0 | if (*pp != NULL) |
357 | 0 | re = *pp; |
358 | 0 | else |
359 | 0 | { |
360 | 0 | re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry)); |
361 | 0 | re->next = NULL; |
362 | 0 | re->id = ids[i]; |
363 | 0 | if ((i + 1) < cids) |
364 | 0 | { |
365 | 0 | re->subdir = 1; |
366 | 0 | re->u.dir = NULL; |
367 | 0 | } |
368 | 0 | else |
369 | 0 | { |
370 | 0 | re->subdir = 0; |
371 | 0 | re->u.res = NULL; |
372 | 0 | } |
373 | |
|
374 | 0 | *pp = re; |
375 | 0 | } |
376 | |
|
377 | 0 | if ((i + 1) < cids) |
378 | 0 | { |
379 | 0 | if (! re->subdir) |
380 | 0 | { |
381 | 0 | fprintf (stderr, "%s: ", program_name); |
382 | 0 | res_ids_print (stderr, i, ids); |
383 | 0 | fprintf (stderr, _(": expected to be a directory\n")); |
384 | 0 | xexit (1); |
385 | 0 | } |
386 | | |
387 | 0 | resources = &re->u.dir; |
388 | 0 | } |
389 | 0 | } |
390 | | |
391 | 0 | if (re->subdir) |
392 | 0 | { |
393 | 0 | fprintf (stderr, "%s: ", program_name); |
394 | 0 | res_ids_print (stderr, cids, ids); |
395 | 0 | fprintf (stderr, _(": expected to be a leaf\n")); |
396 | 0 | xexit (1); |
397 | 0 | } |
398 | | |
399 | 0 | if (re->u.res != NULL) |
400 | 0 | { |
401 | 0 | if (dupok) |
402 | 0 | return re->u.res; |
403 | | |
404 | 0 | fprintf (stderr, _("%s: warning: "), program_name); |
405 | 0 | res_ids_print (stderr, cids, ids); |
406 | 0 | fprintf (stderr, _(": duplicate value\n")); |
407 | 0 | } |
408 | | |
409 | 0 | re->u.res = ((rc_res_resource *) |
410 | 0 | res_alloc (sizeof (rc_res_resource))); |
411 | 0 | memset (re->u.res, 0, sizeof (rc_res_resource)); |
412 | |
|
413 | 0 | re->u.res->type = RES_TYPE_UNINITIALIZED; |
414 | 0 | return re->u.res; |
415 | 0 | } |
416 | | |
417 | | /* Define a standard resource. This is a version of define_resource |
418 | | that just takes type, name, and language arguments. */ |
419 | | |
420 | | rc_res_resource * |
421 | | define_standard_resource (rc_res_directory **resources, int type, |
422 | | rc_res_id name, rc_uint_type language, int dupok) |
423 | 0 | { |
424 | 0 | rc_res_id a[3]; |
425 | |
|
426 | 0 | a[0].named = 0; |
427 | 0 | a[0].u.id = type; |
428 | 0 | a[1] = name; |
429 | 0 | a[2].named = 0; |
430 | 0 | a[2].u.id = language; |
431 | 0 | return define_resource (resources, 3, a, dupok); |
432 | 0 | } |
433 | | |
434 | | /* Comparison routine for resource sorting. */ |
435 | | |
436 | | static int |
437 | | cmp_res_entry (const void *p1, const void *p2) |
438 | 0 | { |
439 | 0 | const rc_res_entry **re1, **re2; |
440 | |
|
441 | 0 | re1 = (const rc_res_entry **) p1; |
442 | 0 | re2 = (const rc_res_entry **) p2; |
443 | 0 | return res_id_cmp ((*re1)->id, (*re2)->id); |
444 | 0 | } |
445 | | |
446 | | /* Sort the resources. */ |
447 | | |
448 | | static rc_res_directory * |
449 | | sort_resources (rc_res_directory *resdir) |
450 | 0 | { |
451 | 0 | int c, i; |
452 | 0 | rc_res_entry *re; |
453 | 0 | rc_res_entry **a; |
454 | |
|
455 | 0 | if (resdir->entries == NULL) |
456 | 0 | return resdir; |
457 | | |
458 | 0 | c = 0; |
459 | 0 | for (re = resdir->entries; re != NULL; re = re->next) |
460 | 0 | ++c; |
461 | | |
462 | | /* This is a recursive routine, so using xmalloc is probably better |
463 | | than alloca. */ |
464 | 0 | a = (rc_res_entry **) xmalloc (c * sizeof (rc_res_entry *)); |
465 | |
|
466 | 0 | for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++) |
467 | 0 | a[i] = re; |
468 | |
|
469 | 0 | qsort (a, c, sizeof (rc_res_entry *), cmp_res_entry); |
470 | |
|
471 | 0 | resdir->entries = a[0]; |
472 | 0 | for (i = 0; i < c - 1; i++) |
473 | 0 | a[i]->next = a[i + 1]; |
474 | 0 | a[i]->next = NULL; |
475 | |
|
476 | 0 | free (a); |
477 | | |
478 | | /* Now sort the subdirectories. */ |
479 | |
|
480 | 0 | for (re = resdir->entries; re != NULL; re = re->next) |
481 | 0 | if (re->subdir) |
482 | 0 | re->u.dir = sort_resources (re->u.dir); |
483 | |
|
484 | 0 | return resdir; |
485 | 0 | } |
486 | | |
487 | | /* Return whether the dialog resource DIALOG is a DIALOG or a |
488 | | DIALOGEX. */ |
489 | | |
490 | | int |
491 | | extended_dialog (const rc_dialog *dialog) |
492 | 0 | { |
493 | 0 | const rc_dialog_control *c; |
494 | |
|
495 | 0 | if (dialog->ex != NULL) |
496 | 0 | return 1; |
497 | | |
498 | 0 | for (c = dialog->controls; c != NULL; c = c->next) |
499 | 0 | if (c->data != NULL || c->help != 0) |
500 | 0 | return 1; |
501 | | |
502 | 0 | return 0; |
503 | 0 | } |
504 | | |
505 | | /* Return whether MENUITEMS are a MENU or a MENUEX. */ |
506 | | |
507 | | int |
508 | | extended_menu (const rc_menu *menu) |
509 | 0 | { |
510 | 0 | return extended_menuitems (menu->items); |
511 | 0 | } |
512 | | |
513 | | static int |
514 | | extended_menuitems (const rc_menuitem *menuitems) |
515 | 0 | { |
516 | 0 | const rc_menuitem *mi; |
517 | |
|
518 | 0 | for (mi = menuitems; mi != NULL; mi = mi->next) |
519 | 0 | { |
520 | 0 | if (mi->help != 0 || mi->state != 0) |
521 | 0 | return 1; |
522 | 0 | if (mi->popup != NULL && mi->id != 0) |
523 | 0 | return 1; |
524 | 0 | if ((mi->type |
525 | 0 | & ~ (MENUITEM_CHECKED |
526 | 0 | | MENUITEM_GRAYED |
527 | 0 | | MENUITEM_HELP |
528 | 0 | | MENUITEM_INACTIVE |
529 | 0 | | MENUITEM_MENUBARBREAK |
530 | 0 | | MENUITEM_BITMAP |
531 | 0 | | MENUITEM_OWNERDRAW |
532 | 0 | | MENUITEM_MENUBREAK)) |
533 | 0 | != 0) |
534 | 0 | return 1; |
535 | 0 | if (mi->popup != NULL) |
536 | 0 | { |
537 | 0 | if (extended_menuitems (mi->popup)) |
538 | 0 | return 1; |
539 | 0 | } |
540 | 0 | } |
541 | | |
542 | 0 | return 0; |
543 | 0 | } |
544 | | |
545 | | /* Convert a string to a format type, or exit if it can't be done. */ |
546 | | |
547 | | static enum res_format |
548 | | format_from_name (const char *name, int exit_on_error) |
549 | 0 | { |
550 | 0 | const struct format_map *m; |
551 | |
|
552 | 0 | for (m = format_names; m->name != NULL; m++) |
553 | 0 | if (strcasecmp (m->name, name) == 0) |
554 | 0 | break; |
555 | |
|
556 | 0 | if (m->name == NULL && exit_on_error) |
557 | 0 | { |
558 | 0 | non_fatal (_("unknown format type `%s'"), name); |
559 | 0 | fprintf (stderr, _("%s: supported formats:"), program_name); |
560 | 0 | for (m = format_names; m->name != NULL; m++) |
561 | 0 | fprintf (stderr, " %s", m->name); |
562 | 0 | fprintf (stderr, "\n"); |
563 | 0 | xexit (1); |
564 | 0 | } |
565 | | |
566 | 0 | return m->format; |
567 | 0 | } |
568 | | |
569 | | /* Work out a format type given a file name. If INPUT is non-zero, |
570 | | it's OK to look at the file itself. */ |
571 | | |
572 | | static enum res_format |
573 | | format_from_filename (const char *filename, int input) |
574 | 0 | { |
575 | 0 | const char *ext; |
576 | 0 | FILE *e; |
577 | 0 | bfd_byte b1, b2, b3, b4, b5; |
578 | 0 | int magic; |
579 | | |
580 | | /* If we have an extension, see if we recognize it as implying a |
581 | | particular format. */ |
582 | 0 | ext = strrchr (filename, '.'); |
583 | 0 | if (ext != NULL) |
584 | 0 | { |
585 | 0 | const struct format_map *m; |
586 | |
|
587 | 0 | ++ext; |
588 | 0 | for (m = format_fileexts; m->name != NULL; m++) |
589 | 0 | if (strcasecmp (m->name, ext) == 0) |
590 | 0 | return m->format; |
591 | 0 | } |
592 | | |
593 | | /* If we don't recognize the name of an output file, assume it's a |
594 | | COFF file. */ |
595 | 0 | if (! input) |
596 | 0 | return RES_FORMAT_COFF; |
597 | | |
598 | | /* Read the first few bytes of the file to see if we can guess what |
599 | | it is. */ |
600 | 0 | e = fopen (filename, FOPEN_RB); |
601 | 0 | if (e == NULL) |
602 | 0 | fatal ("%s: %s", filename, strerror (errno)); |
603 | | |
604 | 0 | b1 = getc (e); |
605 | 0 | b2 = getc (e); |
606 | 0 | b3 = getc (e); |
607 | 0 | b4 = getc (e); |
608 | 0 | b5 = getc (e); |
609 | |
|
610 | 0 | fclose (e); |
611 | | |
612 | | /* A PE executable starts with 0x4d 0x5a. */ |
613 | 0 | if (b1 == 0x4d && b2 == 0x5a) |
614 | 0 | return RES_FORMAT_COFF; |
615 | | |
616 | | /* A COFF .o file starts with a COFF magic number. */ |
617 | 0 | magic = (b2 << 8) | b1; |
618 | 0 | switch (magic) |
619 | 0 | { |
620 | 0 | case 0x14c: /* i386 */ |
621 | 0 | case 0x166: /* MIPS */ |
622 | 0 | case 0x184: /* Alpha */ |
623 | 0 | case 0x268: /* 68k */ |
624 | 0 | case 0x1f0: /* PowerPC */ |
625 | 0 | case 0x290: /* PA */ |
626 | 0 | return RES_FORMAT_COFF; |
627 | 0 | } |
628 | | |
629 | | /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */ |
630 | 0 | if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20) |
631 | 0 | return RES_FORMAT_RES; |
632 | | |
633 | | /* If every character is printable or space, assume it's an RC file. */ |
634 | 0 | if ((ISPRINT (b1) || ISSPACE (b1)) |
635 | 0 | && (ISPRINT (b2) || ISSPACE (b2)) |
636 | 0 | && (ISPRINT (b3) || ISSPACE (b3)) |
637 | 0 | && (ISPRINT (b4) || ISSPACE (b4)) |
638 | 0 | && (ISPRINT (b5) || ISSPACE (b5))) |
639 | 0 | return RES_FORMAT_RC; |
640 | | |
641 | | /* Otherwise, we give up. */ |
642 | 0 | fatal (_("can not determine type of file `%s'; use the -J option"), |
643 | 0 | filename); |
644 | | |
645 | | /* Return something to silence the compiler warning. */ |
646 | 0 | return RES_FORMAT_UNKNOWN; |
647 | 0 | } |
648 | | |
649 | | /* Print a usage message and exit. */ |
650 | | |
651 | | static void |
652 | | usage (FILE *stream, int status) |
653 | 0 | { |
654 | 0 | fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"), |
655 | 0 | program_name); |
656 | 0 | fprintf (stream, _(" The options are:\n\ |
657 | 0 | -i --input=<file> Name input file\n\ |
658 | 0 | -o --output=<file> Name output file\n\ |
659 | 0 | -J --input-format=<format> Specify input format\n\ |
660 | 0 | -O --output-format=<format> Specify output format\n\ |
661 | 0 | -F --target=<target> Specify COFF target\n\ |
662 | 0 | --preprocessor=<program> Program to use to preprocess rc file\n\ |
663 | 0 | --preprocessor-arg=<arg> Additional preprocessor argument\n\ |
664 | 0 | -I --include-dir=<dir> Include directory when preprocessing rc file\n\ |
665 | 0 | -D --define <sym>[=<val>] Define SYM when preprocessing rc file\n\ |
666 | 0 | -U --undefine <sym> Undefine SYM when preprocessing rc file\n\ |
667 | 0 | -v --verbose Verbose - tells you what it's doing\n\ |
668 | 0 | -c --codepage=<codepage> Specify default codepage\n\ |
669 | 0 | -l --language=<val> Set language when reading rc file\n\ |
670 | 0 | --use-temp-file Use a temporary file instead of popen to read\n\ |
671 | 0 | the preprocessor output\n\ |
672 | 0 | --no-use-temp-file Use popen (default)\n")); |
673 | | #ifdef YYDEBUG |
674 | | fprintf (stream, _("\ |
675 | | --yydebug Turn on parser debugging\n")); |
676 | | #endif |
677 | 0 | fprintf (stream, _("\ |
678 | 0 | -r Ignored for compatibility with rc\n\ |
679 | 0 | @<file> Read options from <file>\n\ |
680 | 0 | -h --help Print this help message\n\ |
681 | 0 | -V --version Print version information\n")); |
682 | 0 | fprintf (stream, _("\ |
683 | 0 | FORMAT is one of rc, res, or coff, and is deduced from the file name\n\ |
684 | 0 | extension if not specified. A single file name is an input file.\n\ |
685 | 0 | No input-file is stdin, default rc. No output-file is stdout, default rc.\n")); |
686 | |
|
687 | 0 | list_supported_targets (program_name, stream); |
688 | |
|
689 | 0 | if (REPORT_BUGS_TO[0] && status == 0) |
690 | 0 | fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); |
691 | |
|
692 | 0 | exit (status); |
693 | 0 | } |
694 | | |
695 | | /* Quote characters that will confuse the shell when we run the preprocessor. */ |
696 | | |
697 | | static const char * |
698 | | quot (const char *string) |
699 | 0 | { |
700 | 0 | static char *buf = 0; |
701 | 0 | static int buflen = 0; |
702 | 0 | int slen = strlen (string); |
703 | 0 | const char *src; |
704 | 0 | char *dest; |
705 | |
|
706 | 0 | if ((buflen < slen * 2 + 3) || ! buf) |
707 | 0 | { |
708 | 0 | buflen = slen * 2 + 3; |
709 | 0 | free (buf); |
710 | 0 | buf = (char *) xmalloc (buflen); |
711 | 0 | } |
712 | |
|
713 | 0 | for (src = string, dest = buf; *src; src++, dest++) |
714 | 0 | { |
715 | 0 | if (*src == '(' || *src == ')' || *src == ' ') |
716 | 0 | *dest++ = '\\'; |
717 | 0 | *dest = *src; |
718 | 0 | } |
719 | |
|
720 | 0 | *dest = 0; |
721 | 0 | return buf; |
722 | 0 | } |
723 | | |
724 | | /* Long options. */ |
725 | | |
726 | | enum option_values |
727 | | { |
728 | | /* 150 isn't special; it's just an arbitrary non-ASCII char value. */ |
729 | | OPTION_PREPROCESSOR = 150, |
730 | | OPTION_USE_TEMP_FILE, |
731 | | OPTION_NO_USE_TEMP_FILE, |
732 | | OPTION_YYDEBUG, |
733 | | OPTION_INCLUDE_DIR, |
734 | | OPTION_PREPROCESSOR_ARG |
735 | | }; |
736 | | |
737 | | static const struct option long_options[] = |
738 | | { |
739 | | {"input", required_argument, 0, 'i'}, |
740 | | {"output", required_argument, 0, 'o'}, |
741 | | {"input-format", required_argument, 0, 'J'}, |
742 | | {"output-format", required_argument, 0, 'O'}, |
743 | | {"target", required_argument, 0, 'F'}, |
744 | | {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR}, |
745 | | {"preprocessor-arg", required_argument, 0, OPTION_PREPROCESSOR_ARG}, |
746 | | {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR}, |
747 | | {"define", required_argument, 0, 'D'}, |
748 | | {"undefine", required_argument, 0, 'U'}, |
749 | | {"verbose", no_argument, 0, 'v'}, |
750 | | {"codepage", required_argument, 0, 'c'}, |
751 | | {"language", required_argument, 0, 'l'}, |
752 | | {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE}, |
753 | | {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE}, |
754 | | {"yydebug", no_argument, 0, OPTION_YYDEBUG}, |
755 | | {"version", no_argument, 0, 'V'}, |
756 | | {"help", no_argument, 0, 'h'}, |
757 | | {0, no_argument, 0, 0} |
758 | | }; |
759 | | |
760 | | void |
761 | | windres_add_include_dir (const char *p) |
762 | 0 | { |
763 | 0 | struct include_dir *n, **pp; |
764 | | |
765 | | /* Computing paths is often complicated and error prone. |
766 | | The easiest way to check for mistakes is at the time |
767 | | we add them to include_dirs. */ |
768 | 0 | assert (p != NULL); |
769 | 0 | assert (*p != '\0'); |
770 | | |
771 | 0 | n = xmalloc (sizeof *n); |
772 | 0 | n->next = NULL; |
773 | 0 | n->dir = (char * ) p; |
774 | |
|
775 | 0 | for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next) |
776 | 0 | ; |
777 | 0 | *pp = n; |
778 | 0 | } |
779 | | |
780 | | /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */ |
781 | | int main (int, char **); |
782 | | |
783 | | /* The main function. */ |
784 | | |
785 | | int |
786 | | old_main32 (int argc, char **argv); |
787 | | int old_main32 (int argc, char **argv) |
788 | 0 | { |
789 | 0 | int c; |
790 | 0 | char *input_filename; |
791 | 0 | char *output_filename; |
792 | 0 | enum res_format input_format; |
793 | 0 | enum res_format input_format_tmp; |
794 | 0 | enum res_format output_format; |
795 | 0 | char *target; |
796 | 0 | char *preprocessor; |
797 | 0 | char *preprocargs; |
798 | 0 | const char *quotedarg; |
799 | 0 | int language; |
800 | 0 | rc_res_directory *resources; |
801 | 0 | int use_temp_file; |
802 | |
|
803 | 0 | #ifdef HAVE_LC_MESSAGES |
804 | 0 | setlocale (LC_MESSAGES, ""); |
805 | 0 | #endif |
806 | 0 | setlocale (LC_CTYPE, ""); |
807 | 0 | bindtextdomain (PACKAGE, LOCALEDIR); |
808 | 0 | textdomain (PACKAGE); |
809 | |
|
810 | 0 | program_name = argv[0]; |
811 | 0 | xmalloc_set_program_name (program_name); |
812 | 0 | bfd_set_error_program_name (program_name); |
813 | |
|
814 | 0 | expandargv (&argc, &argv); |
815 | |
|
816 | 0 | if (bfd_init () != BFD_INIT_MAGIC) |
817 | 0 | fatal (_("fatal error: libbfd ABI mismatch")); |
818 | 0 | set_default_bfd_target (); |
819 | |
|
820 | 0 | res_init (); |
821 | |
|
822 | 0 | input_filename = NULL; |
823 | 0 | output_filename = NULL; |
824 | 0 | input_format = RES_FORMAT_UNKNOWN; |
825 | 0 | output_format = RES_FORMAT_UNKNOWN; |
826 | 0 | target = NULL; |
827 | 0 | preprocessor = NULL; |
828 | 0 | preprocargs = NULL; |
829 | 0 | language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */ |
830 | 0 | use_temp_file = 0; |
831 | |
|
832 | 0 | while ((c = getopt_long (argc, argv, "c:f:i:l:o:I:J:O:F:D:U:rhHvV", long_options, |
833 | 0 | (int *) 0)) != EOF) |
834 | 0 | { |
835 | 0 | switch (c) |
836 | 0 | { |
837 | 0 | case 'c': |
838 | 0 | { |
839 | 0 | rc_uint_type ncp; |
840 | |
|
841 | 0 | if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X')) |
842 | 0 | ncp = (rc_uint_type) strtol (optarg + 2, NULL, 16); |
843 | 0 | else |
844 | 0 | ncp = (rc_uint_type) strtol (optarg, NULL, 10); |
845 | 0 | if (ncp == CP_UTF16 || ! unicode_is_valid_codepage (ncp)) |
846 | 0 | fatal (_("invalid codepage specified.\n")); |
847 | 0 | wind_default_codepage = wind_current_codepage = ncp; |
848 | 0 | } |
849 | 0 | break; |
850 | | |
851 | 0 | case 'i': |
852 | 0 | input_filename = optarg; |
853 | 0 | break; |
854 | | |
855 | 0 | case 'f': |
856 | | /* For compatibility with rc we accept "-fo <name>" as being the |
857 | | equivalent of "-o <name>". We do not advertise this fact |
858 | | though, as we do not want users to use non-GNU like command |
859 | | line switches. */ |
860 | 0 | if (*optarg != 'o') |
861 | 0 | fatal (_("invalid option -f\n")); |
862 | 0 | optarg++; |
863 | 0 | if (* optarg == 0) |
864 | 0 | { |
865 | 0 | if (optind == argc) |
866 | 0 | fatal (_("No filename following the -fo option.\n")); |
867 | 0 | optarg = argv [optind++]; |
868 | 0 | } |
869 | | /* Fall through. */ |
870 | | |
871 | 0 | case 'o': |
872 | 0 | output_filename = optarg; |
873 | 0 | break; |
874 | | |
875 | 0 | case 'J': |
876 | 0 | input_format = format_from_name (optarg, 1); |
877 | 0 | break; |
878 | | |
879 | 0 | case 'O': |
880 | 0 | output_format = format_from_name (optarg, 1); |
881 | 0 | break; |
882 | | |
883 | 0 | case 'F': |
884 | 0 | target = optarg; |
885 | 0 | break; |
886 | | |
887 | 0 | case OPTION_PREPROCESSOR: |
888 | 0 | if (strchr (optarg, ' ')) |
889 | 0 | { |
890 | 0 | if (asprintf (& preprocessor, "\"%s\"", optarg) == -1) |
891 | 0 | preprocessor = optarg; |
892 | 0 | } |
893 | 0 | else |
894 | 0 | preprocessor = optarg; |
895 | 0 | break; |
896 | | |
897 | 0 | case OPTION_PREPROCESSOR_ARG: |
898 | 0 | if (preprocargs == NULL) |
899 | 0 | { |
900 | 0 | quotedarg = quot (optarg); |
901 | 0 | preprocargs = xstrdup (quotedarg); |
902 | 0 | } |
903 | 0 | else |
904 | 0 | { |
905 | 0 | char *n; |
906 | |
|
907 | 0 | quotedarg = quot (optarg); |
908 | 0 | n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 2); |
909 | 0 | sprintf (n, "%s %s", preprocargs, quotedarg); |
910 | 0 | free (preprocargs); |
911 | 0 | preprocargs = n; |
912 | 0 | } |
913 | 0 | break; |
914 | | |
915 | 0 | case 'D': |
916 | 0 | case 'U': |
917 | 0 | if (preprocargs == NULL) |
918 | 0 | { |
919 | 0 | quotedarg = quot (optarg); |
920 | 0 | preprocargs = xmalloc (strlen (quotedarg) + 3); |
921 | 0 | sprintf (preprocargs, "-%c%s", c, quotedarg); |
922 | 0 | } |
923 | 0 | else |
924 | 0 | { |
925 | 0 | char *n; |
926 | |
|
927 | 0 | quotedarg = quot (optarg); |
928 | 0 | n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4); |
929 | 0 | sprintf (n, "%s -%c%s", preprocargs, c, quotedarg); |
930 | 0 | free (preprocargs); |
931 | 0 | preprocargs = n; |
932 | 0 | } |
933 | 0 | break; |
934 | | |
935 | 0 | case 'r': |
936 | | /* Ignored for compatibility with rc. */ |
937 | 0 | break; |
938 | | |
939 | 0 | case 'v': |
940 | 0 | verbose ++; |
941 | 0 | break; |
942 | | |
943 | 0 | case 'I': |
944 | | /* For backward compatibility, should be removed in the future. */ |
945 | 0 | input_format_tmp = format_from_name (optarg, 0); |
946 | 0 | if (input_format_tmp != RES_FORMAT_UNKNOWN) |
947 | 0 | { |
948 | 0 | struct stat statbuf; |
949 | 0 | char modebuf[11]; |
950 | |
|
951 | 0 | if (stat (optarg, & statbuf) == 0 |
952 | | /* Coded this way to avoid importing knowledge of S_ISDIR into this file. */ |
953 | 0 | && (mode_string (statbuf.st_mode, modebuf), modebuf[0] == 'd')) |
954 | | /* We have a -I option with a directory name that just happens |
955 | | to match a format name as well. eg: -I res Assume that the |
956 | | user knows what they are doing and do not complain. */ |
957 | 0 | ; |
958 | 0 | else |
959 | 0 | { |
960 | 0 | fprintf (stderr, |
961 | 0 | _("Option -I is deprecated for setting the input format, please use -J instead.\n")); |
962 | 0 | input_format = input_format_tmp; |
963 | 0 | break; |
964 | 0 | } |
965 | 0 | } |
966 | | /* Fall through. */ |
967 | | |
968 | 0 | case OPTION_INCLUDE_DIR: |
969 | 0 | if (preprocargs == NULL) |
970 | 0 | { |
971 | 0 | quotedarg = quot (optarg); |
972 | 0 | preprocargs = xmalloc (strlen (quotedarg) + 3); |
973 | 0 | sprintf (preprocargs, "-I%s", quotedarg); |
974 | 0 | } |
975 | 0 | else |
976 | 0 | { |
977 | 0 | char *n; |
978 | |
|
979 | 0 | quotedarg = quot (optarg); |
980 | 0 | n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4); |
981 | 0 | sprintf (n, "%s -I%s", preprocargs, quotedarg); |
982 | 0 | free (preprocargs); |
983 | 0 | preprocargs = n; |
984 | 0 | } |
985 | |
|
986 | 0 | windres_add_include_dir (optarg); |
987 | |
|
988 | 0 | break; |
989 | | |
990 | 0 | case 'l': |
991 | 0 | language = strtol (optarg, (char **) NULL, 16); |
992 | 0 | break; |
993 | | |
994 | 0 | case OPTION_USE_TEMP_FILE: |
995 | 0 | use_temp_file = 1; |
996 | 0 | break; |
997 | | |
998 | 0 | case OPTION_NO_USE_TEMP_FILE: |
999 | 0 | use_temp_file = 0; |
1000 | 0 | break; |
1001 | | |
1002 | | #ifdef YYDEBUG |
1003 | | case OPTION_YYDEBUG: |
1004 | | yydebug = 1; |
1005 | | break; |
1006 | | #endif |
1007 | | |
1008 | 0 | case 'h': |
1009 | 0 | case 'H': |
1010 | 0 | usage (stdout, 0); |
1011 | 0 | break; |
1012 | | |
1013 | 0 | case 'V': |
1014 | 0 | print_version ("windres"); |
1015 | 0 | break; |
1016 | | |
1017 | 0 | default: |
1018 | 0 | usage (stderr, 1); |
1019 | 0 | break; |
1020 | 0 | } |
1021 | 0 | } |
1022 | | |
1023 | 0 | if (input_filename == NULL && optind < argc) |
1024 | 0 | { |
1025 | 0 | input_filename = argv[optind]; |
1026 | 0 | ++optind; |
1027 | 0 | } |
1028 | |
|
1029 | 0 | if (output_filename == NULL && optind < argc) |
1030 | 0 | { |
1031 | 0 | output_filename = argv[optind]; |
1032 | 0 | ++optind; |
1033 | 0 | } |
1034 | |
|
1035 | 0 | if (argc != optind) |
1036 | 0 | usage (stderr, 1); |
1037 | |
|
1038 | 0 | if (input_format == RES_FORMAT_UNKNOWN) |
1039 | 0 | { |
1040 | 0 | if (input_filename == NULL) |
1041 | 0 | input_format = RES_FORMAT_RC; |
1042 | 0 | else |
1043 | 0 | input_format = format_from_filename (input_filename, 1); |
1044 | 0 | } |
1045 | |
|
1046 | 0 | if (output_format == RES_FORMAT_UNKNOWN) |
1047 | 0 | { |
1048 | 0 | if (output_filename == NULL) |
1049 | 0 | output_format = RES_FORMAT_RC; |
1050 | 0 | else |
1051 | 0 | output_format = format_from_filename (output_filename, 0); |
1052 | 0 | } |
1053 | |
|
1054 | 0 | set_endianness (NULL, target); |
1055 | | |
1056 | | /* Read the input file. */ |
1057 | 0 | switch (input_format) |
1058 | 0 | { |
1059 | 0 | default: |
1060 | 0 | abort (); |
1061 | 0 | case RES_FORMAT_RC: |
1062 | 0 | resources = read_rc_file (input_filename, preprocessor, preprocargs, |
1063 | 0 | language, use_temp_file); |
1064 | 0 | break; |
1065 | 0 | case RES_FORMAT_RES: |
1066 | 0 | resources = read_res_file (input_filename); |
1067 | 0 | break; |
1068 | 0 | case RES_FORMAT_COFF: |
1069 | 0 | resources = read_coff_rsrc (input_filename, target); |
1070 | 0 | break; |
1071 | 0 | } |
1072 | | |
1073 | 0 | if (resources == NULL) |
1074 | 0 | fatal (_("no resources")); |
1075 | | |
1076 | | /* Sort the resources. This is required for COFF, convenient for |
1077 | | rc, and unimportant for res. */ |
1078 | 0 | resources = sort_resources (resources); |
1079 | | |
1080 | | /* Write the output file. */ |
1081 | 0 | reswr_init (); |
1082 | |
|
1083 | 0 | switch (output_format) |
1084 | 0 | { |
1085 | 0 | default: |
1086 | 0 | abort (); |
1087 | 0 | case RES_FORMAT_RC: |
1088 | 0 | write_rc_file (output_filename, resources); |
1089 | 0 | break; |
1090 | 0 | case RES_FORMAT_RES: |
1091 | 0 | write_res_file (output_filename, resources); |
1092 | 0 | break; |
1093 | 0 | case RES_FORMAT_COFF: |
1094 | 0 | write_coff_file (output_filename, target, resources); |
1095 | 0 | break; |
1096 | 0 | } |
1097 | | |
1098 | 0 | xexit (0); |
1099 | 0 | return 0; |
1100 | 0 | } |
1101 | | |
1102 | | static void |
1103 | | set_endianness (bfd *abfd, const char *target) |
1104 | 0 | { |
1105 | 0 | const bfd_target *target_vec; |
1106 | |
|
1107 | 0 | def_target_arch = NULL; |
1108 | 0 | target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL, |
1109 | 0 | &def_target_arch); |
1110 | 0 | if (! target_vec) |
1111 | 0 | fatal ("Can't detect target endianness and architecture."); |
1112 | 0 | if (! def_target_arch) |
1113 | 0 | fatal ("Can't detect architecture."); |
1114 | 0 | } |
1115 | | |
1116 | | bfd * |
1117 | | windres_open_as_binary (const char *filename, int rdmode) |
1118 | 0 | { |
1119 | 0 | bfd *abfd; |
1120 | |
|
1121 | 0 | abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary")); |
1122 | 0 | if (! abfd) |
1123 | 0 | fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output")); |
1124 | | |
1125 | 0 | if (rdmode && ! bfd_check_format (abfd, bfd_object)) |
1126 | 0 | fatal ("can't open `%s' for input.", filename); |
1127 | | |
1128 | 0 | return abfd; |
1129 | 0 | } |
1130 | | |
1131 | | void |
1132 | | set_windres_bfd_endianness (windres_bfd *wrbfd, int is_bigendian) |
1133 | 0 | { |
1134 | 0 | assert (!! wrbfd); |
1135 | 0 | switch (WR_KIND(wrbfd)) |
1136 | 0 | { |
1137 | 0 | case WR_KIND_BFD_BIN_L: |
1138 | 0 | if (is_bigendian) |
1139 | 0 | WR_KIND(wrbfd) = WR_KIND_BFD_BIN_B; |
1140 | 0 | break; |
1141 | 0 | case WR_KIND_BFD_BIN_B: |
1142 | 0 | if (! is_bigendian) |
1143 | 0 | WR_KIND(wrbfd) = WR_KIND_BFD_BIN_L; |
1144 | 0 | break; |
1145 | 0 | default: |
1146 | | /* only binary bfd can be overriden. */ |
1147 | 0 | abort (); |
1148 | 0 | } |
1149 | 0 | } |
1150 | | |
1151 | | void |
1152 | | set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind) |
1153 | 30 | { |
1154 | 30 | assert (!! wrbfd); |
1155 | 30 | switch (kind) |
1156 | 30 | { |
1157 | 0 | case WR_KIND_TARGET: |
1158 | 0 | abfd = NULL; |
1159 | 0 | sec = NULL; |
1160 | 0 | break; |
1161 | 30 | case WR_KIND_BFD: |
1162 | 30 | case WR_KIND_BFD_BIN_L: |
1163 | 30 | case WR_KIND_BFD_BIN_B: |
1164 | 30 | assert (!! abfd); |
1165 | 30 | assert (!!sec); |
1166 | 30 | break; |
1167 | 30 | default: |
1168 | 0 | abort (); |
1169 | 30 | } |
1170 | 30 | WR_KIND(wrbfd) = kind; |
1171 | 30 | WR_BFD(wrbfd) = abfd; |
1172 | 30 | WR_SECTION(wrbfd) = sec; |
1173 | 30 | } |
1174 | | |
1175 | | void |
1176 | | set_windres_bfd_content (windres_bfd *wrbfd, const void *data, rc_uint_type off, |
1177 | | rc_uint_type length) |
1178 | 0 | { |
1179 | 0 | if (WR_KIND(wrbfd) != WR_KIND_TARGET) |
1180 | 0 | { |
1181 | 0 | if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length)) |
1182 | 0 | bfd_fatal ("bfd_set_section_contents"); |
1183 | 0 | } |
1184 | 0 | else |
1185 | 0 | abort (); |
1186 | 0 | } |
1187 | | |
1188 | | void |
1189 | | get_windres_bfd_content (windres_bfd *wrbfd, void *data, rc_uint_type off, |
1190 | | rc_uint_type length) |
1191 | 0 | { |
1192 | 0 | if (WR_KIND(wrbfd) != WR_KIND_TARGET) |
1193 | 0 | { |
1194 | 0 | if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length)) |
1195 | 0 | bfd_fatal ("bfd_get_section_contents"); |
1196 | 0 | } |
1197 | 0 | else |
1198 | 0 | abort (); |
1199 | 0 | } |
1200 | | |
1201 | | void |
1202 | | windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value) |
1203 | 0 | { |
1204 | 0 | switch (WR_KIND(wrbfd)) |
1205 | 0 | { |
1206 | 0 | case WR_KIND_TARGET: |
1207 | 0 | target_put_8 (p, value); |
1208 | 0 | break; |
1209 | 0 | case WR_KIND_BFD: |
1210 | 0 | case WR_KIND_BFD_BIN_L: |
1211 | 0 | case WR_KIND_BFD_BIN_B: |
1212 | 0 | bfd_put_8 (WR_BFD(wrbfd), value, p); |
1213 | 0 | break; |
1214 | 0 | default: |
1215 | 0 | abort (); |
1216 | 0 | } |
1217 | 0 | } |
1218 | | |
1219 | | void |
1220 | | windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value) |
1221 | 0 | { |
1222 | 0 | switch (WR_KIND(wrbfd)) |
1223 | 0 | { |
1224 | 0 | case WR_KIND_TARGET: |
1225 | 0 | target_put_16 (data, value); |
1226 | 0 | break; |
1227 | 0 | case WR_KIND_BFD: |
1228 | 0 | case WR_KIND_BFD_BIN_B: |
1229 | 0 | bfd_put_16 (WR_BFD(wrbfd), value, data); |
1230 | 0 | break; |
1231 | 0 | case WR_KIND_BFD_BIN_L: |
1232 | 0 | bfd_putl16 (value, data); |
1233 | 0 | break; |
1234 | 0 | default: |
1235 | 0 | abort (); |
1236 | 0 | } |
1237 | 0 | } |
1238 | | |
1239 | | void |
1240 | | windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value) |
1241 | 0 | { |
1242 | 0 | switch (WR_KIND(wrbfd)) |
1243 | 0 | { |
1244 | 0 | case WR_KIND_TARGET: |
1245 | 0 | target_put_32 (data, value); |
1246 | 0 | break; |
1247 | 0 | case WR_KIND_BFD: |
1248 | 0 | case WR_KIND_BFD_BIN_B: |
1249 | 0 | bfd_put_32 (WR_BFD(wrbfd), value, data); |
1250 | 0 | break; |
1251 | 0 | case WR_KIND_BFD_BIN_L: |
1252 | 0 | bfd_putl32 (value, data); |
1253 | 0 | break; |
1254 | 0 | default: |
1255 | 0 | abort (); |
1256 | 0 | } |
1257 | 0 | } |
1258 | | |
1259 | | rc_uint_type |
1260 | | windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length) |
1261 | 0 | { |
1262 | 0 | if (length < 1) |
1263 | 0 | fatal ("windres_get_8: unexpected eob."); |
1264 | 0 | switch (WR_KIND(wrbfd)) |
1265 | 0 | { |
1266 | 0 | case WR_KIND_TARGET: |
1267 | 0 | return target_get_8 (data, length); |
1268 | 0 | case WR_KIND_BFD: |
1269 | 0 | case WR_KIND_BFD_BIN_B: |
1270 | 0 | case WR_KIND_BFD_BIN_L: |
1271 | 0 | return bfd_get_8 (WR_BFD(wrbfd), data); |
1272 | 0 | default: |
1273 | 0 | abort (); |
1274 | 0 | } |
1275 | 0 | return 0; |
1276 | 0 | } |
1277 | | |
1278 | | rc_uint_type |
1279 | | windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length) |
1280 | 0 | { |
1281 | 0 | if (length < 2) |
1282 | 0 | fatal ("windres_get_16: unexpected eob."); |
1283 | 0 | switch (WR_KIND(wrbfd)) |
1284 | 0 | { |
1285 | 0 | case WR_KIND_TARGET: |
1286 | 0 | return target_get_16 (data, length); |
1287 | 0 | case WR_KIND_BFD: |
1288 | 0 | case WR_KIND_BFD_BIN_B: |
1289 | 0 | return bfd_get_16 (WR_BFD(wrbfd), data); |
1290 | 0 | case WR_KIND_BFD_BIN_L: |
1291 | 0 | return bfd_getl16 (data); |
1292 | 0 | default: |
1293 | 0 | abort (); |
1294 | 0 | } |
1295 | 0 | return 0; |
1296 | 0 | } |
1297 | | |
1298 | | rc_uint_type |
1299 | | windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length) |
1300 | 0 | { |
1301 | 0 | if (length < 4) |
1302 | 0 | fatal ("windres_get_32: unexpected eob."); |
1303 | 0 | switch (WR_KIND(wrbfd)) |
1304 | 0 | { |
1305 | 0 | case WR_KIND_TARGET: |
1306 | 0 | return target_get_32 (data, length); |
1307 | 0 | case WR_KIND_BFD: |
1308 | 0 | case WR_KIND_BFD_BIN_B: |
1309 | 0 | return bfd_get_32 (WR_BFD(wrbfd), data); |
1310 | 0 | case WR_KIND_BFD_BIN_L: |
1311 | 0 | return bfd_getl32 (data); |
1312 | 0 | default: |
1313 | 0 | abort (); |
1314 | 0 | } |
1315 | 0 | return 0; |
1316 | 0 | } |
1317 | | |
1318 | | static rc_uint_type |
1319 | | target_get_8 (const void *p, rc_uint_type length) |
1320 | 0 | { |
1321 | 0 | rc_uint_type ret; |
1322 | |
|
1323 | 0 | if (length < 1) |
1324 | 0 | fatal ("Resource too small for getting 8-bit value."); |
1325 | | |
1326 | 0 | ret = (rc_uint_type) *((const bfd_byte *) p); |
1327 | 0 | return ret & 0xff; |
1328 | 0 | } |
1329 | | |
1330 | | static rc_uint_type |
1331 | | target_get_16 (const void *p, rc_uint_type length) |
1332 | 0 | { |
1333 | 0 | if (length < 2) |
1334 | 0 | fatal ("Resource too small for getting 16-bit value."); |
1335 | | |
1336 | 0 | if (target_is_bigendian) |
1337 | 0 | return bfd_getb16 (p); |
1338 | 0 | else |
1339 | 0 | return bfd_getl16 (p); |
1340 | 0 | } |
1341 | | |
1342 | | static rc_uint_type |
1343 | | target_get_32 (const void *p, rc_uint_type length) |
1344 | 0 | { |
1345 | 0 | if (length < 4) |
1346 | 0 | fatal ("Resource too small for getting 32-bit value."); |
1347 | | |
1348 | 0 | if (target_is_bigendian) |
1349 | 0 | return bfd_getb32 (p); |
1350 | 0 | else |
1351 | 0 | return bfd_getl32 (p); |
1352 | 0 | } |
1353 | | |
1354 | | static void |
1355 | | target_put_8 (void *p, rc_uint_type value) |
1356 | 0 | { |
1357 | 0 | assert (!! p); |
1358 | 0 | *((bfd_byte *) p)=(bfd_byte) value; |
1359 | 0 | } |
1360 | | |
1361 | | static void |
1362 | | target_put_16 (void *p, rc_uint_type value) |
1363 | 0 | { |
1364 | 0 | assert (!! p); |
1365 | | |
1366 | 0 | if (target_is_bigendian) |
1367 | 0 | bfd_putb16 (value, p); |
1368 | 0 | else |
1369 | 0 | bfd_putl16 (value, p); |
1370 | 0 | } |
1371 | | |
1372 | | static void |
1373 | | target_put_32 (void *p, rc_uint_type value) |
1374 | 0 | { |
1375 | 0 | assert (!! p); |
1376 | | |
1377 | 0 | if (target_is_bigendian) |
1378 | 0 | bfd_putb32 (value, p); |
1379 | 0 | else |
1380 | 0 | bfd_putl32 (value, p); |
1381 | 0 | } |
1382 | | |
1383 | | static int isInComment = 0; |
1384 | | |
1385 | | int wr_printcomment (FILE *e, const char *fmt, ...) |
1386 | 0 | { |
1387 | 0 | va_list arg; |
1388 | 0 | int r = 0; |
1389 | |
|
1390 | 0 | if (isInComment) |
1391 | 0 | r += fprintf (e, "\n "); |
1392 | 0 | else |
1393 | 0 | fprintf (e, "/* "); |
1394 | 0 | isInComment = 1; |
1395 | 0 | if (fmt == NULL) |
1396 | 0 | return r; |
1397 | 0 | va_start (arg, fmt); |
1398 | 0 | r += vfprintf (e, fmt, arg); |
1399 | 0 | va_end (arg); |
1400 | 0 | return r; |
1401 | 0 | } |
1402 | | |
1403 | | int wr_print (FILE *e, const char *fmt, ...) |
1404 | 0 | { |
1405 | 0 | va_list arg; |
1406 | 0 | int r = 0; |
1407 | 0 | if (isInComment) |
1408 | 0 | r += fprintf (e, ". */\n"); |
1409 | 0 | isInComment = 0; |
1410 | 0 | if (! fmt) |
1411 | 0 | return r; |
1412 | 0 | va_start (arg, fmt); |
1413 | 0 | r += vfprintf (e, fmt, arg); |
1414 | 0 | va_end (arg); |
1415 | 0 | return r; |
1416 | 0 | } |