1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
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:
79: rc_res_directory *
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:
114: void
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:
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:
168: static int
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:
183: if ((off[0] + 8) > omax)
184: return 0;
185: read_res_data_hdr (wrbfd, off, omax, &reshdr);
186:
187:
188: read_res_id (wrbfd, off, omax, &type);
189:
190: read_res_id (wrbfd, off, omax, &name);
191:
192: off[0] = (off[0] + 3) & ~3;
193:
194:
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:
200: resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4);
201:
202: off[0] = (off[0] + 3) & ~3;
203:
204:
205: buff = res_alloc (reshdr.data_size);
206:
207: read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
208:
209: r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
210: r->res_info = resinfo;
211:
212: res_add_resource (r, &type, &name, resinfo.language, 0);
213:
214: return 1;
215: }
216:
217:
218: static rc_uint_type
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:
231:
232:
233:
234: type = &re->id;
235: break;
236:
237: case 2:
238:
239:
240: name = &re->id;
241: break;
242:
243: case 3:
244:
245:
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:
266:
267:
268:
269:
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
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:
376: static rc_uint_type
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:
392: static unsigned long
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:
403: static rc_uint_type
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
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
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:
456: static void
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:
468: static rc_uint_type
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:
500: static rc_uint_type
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:
518: static void
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)
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:
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: