Another windres snapshot. Can now read the COFF resources directory,
[deliverable/binutils-gdb.git] / binutils / resrc.c
1 /* resrc.c -- read and write Windows rc files.
2 Copyright 1997 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
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., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21
22 /* This file contains function that read and write Windows rc files.
23 These are text files that represent resources. */
24
25 #include "bfd.h"
26 #include "bucomm.h"
27 #include "libiberty.h"
28 #include "windres.h"
29
30 #include <assert.h>
31 #include <ctype.h>
32 #include <sys/stat.h>
33
34 /* The default preprocessor. */
35
36 #define DEFAULT_PREPROCESSOR "gcc -E -xc-header -DRC_INVOKED"
37
38 /* We read the directory entries in a cursor or icon file into
39 instances of this structure. */
40
41 struct icondir
42 {
43 /* Width of image. */
44 unsigned char width;
45 /* Height of image. */
46 unsigned char height;
47 /* Number of colors in image. */
48 unsigned char colorcount;
49 union
50 {
51 struct
52 {
53 /* Color planes. */
54 unsigned short planes;
55 /* Bits per pixel. */
56 unsigned short bits;
57 } icon;
58 struct
59 {
60 /* X coordinate of hotspot. */
61 unsigned short xhotspot;
62 /* Y coordinate of hotspot. */
63 unsigned short yhotspot;
64 } cursor;
65 } u;
66 /* Bytes in image. */
67 unsigned long bytes;
68 /* File offset of image. */
69 unsigned long offset;
70 };
71
72 /* The name of the rc file we are reading. */
73
74 char *rc_filename;
75
76 /* The line number in the rc file. */
77
78 int rc_lineno;
79
80 /* The pipe we are reading from, so that we can close it if we exit. */
81
82 static FILE *cpp_pipe;
83
84 /* As we read the rc file, we attach information to this structure. */
85
86 static struct res_directory *resources;
87
88 /* The number of cursor resources we have written out. */
89
90 static int cursors;
91
92 /* The number of font resources we have written out. */
93
94 static int fonts;
95
96 /* Font directory information. */
97
98 struct fontdir *fontdirs;
99
100 /* Resource info to use for fontdirs. */
101
102 struct res_res_info fontdirs_resinfo;
103
104 /* The number of icon resources we have written out. */
105
106 static int icons;
107
108 /* Local functions. */
109
110 static void close_pipe PARAMS ((void));
111 static void unexpected_eof PARAMS ((const char *));
112 static int get_word PARAMS ((FILE *, const char *));
113 static unsigned long get_long PARAMS ((FILE *, const char *));
114 static void get_data
115 PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
116 static void define_fontdirs PARAMS ((void));
117 \f
118 /* Read an rc file. */
119
120 struct res_directory *
121 read_rc_file (filename, preprocessor, preprocargs, language)
122 const char *filename;
123 const char *preprocessor;
124 const char *preprocargs;
125 int language;
126 {
127 char *cmd;
128
129 if (preprocessor == NULL)
130 preprocessor = DEFAULT_PREPROCESSOR;
131
132 if (preprocargs == NULL)
133 preprocargs = "";
134 if (filename == NULL)
135 filename = "-";
136
137 cmd = xmalloc (strlen (preprocessor)
138 + strlen (preprocargs)
139 + strlen (filename)
140 + 10);
141 sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
142
143 cpp_pipe = popen (cmd, FOPEN_RT);
144 if (cpp_pipe == NULL)
145 fatal ("can't popen `%s': %s", cmd, strerror (errno));
146
147 xatexit (close_pipe);
148
149 rc_filename = xstrdup (filename);
150 rc_lineno = 1;
151 if (language != -1)
152 rcparse_set_language (language);
153 yyin = cpp_pipe;
154 yyparse ();
155
156 if (pclose (cpp_pipe) != 0)
157 fprintf (stderr, "%s: warning: preprocessor failed\n", program_name);
158 cpp_pipe = NULL;
159
160 if (fontdirs != NULL)
161 define_fontdirs ();
162
163 free (rc_filename);
164 rc_filename = NULL;
165
166 return resources;
167 }
168
169 /* Close the pipe if it is open. This is called via xatexit. */
170
171 void
172 close_pipe ()
173 {
174 if (cpp_pipe != NULL)
175 pclose (cpp_pipe);
176 }
177
178 /* Report an error while reading an rc file. */
179
180 void
181 yyerror (msg)
182 const char *msg;
183 {
184 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
185 }
186
187 /* Issue a warning while reading an rc file. */
188
189 void
190 rcparse_warning (msg)
191 const char *msg;
192 {
193 fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
194 }
195
196 /* Die if we get an unexpected end of file. */
197
198 static void
199 unexpected_eof (msg)
200 const char *msg;
201 {
202 fatal ("%s: unexpected EOF", msg);
203 }
204
205 /* Read a 16 bit word from a file. The data is assumed to be little
206 endian. */
207
208 static int
209 get_word (e, msg)
210 FILE *e;
211 const char *msg;
212 {
213 int b1, b2;
214
215 b1 = getc (e);
216 b2 = getc (e);
217 if (feof (e))
218 unexpected_eof (msg);
219 return ((b2 & 0xff) << 8) | (b1 & 0xff);
220 }
221
222 /* Read a 32 bit word from a file. The data is assumed to be little
223 endian. */
224
225 static unsigned long
226 get_long (e, msg)
227 FILE *e;
228 const char *msg;
229 {
230 int b1, b2, b3, b4;
231
232 b1 = getc (e);
233 b2 = getc (e);
234 b3 = getc (e);
235 b4 = getc (e);
236 if (feof (e))
237 unexpected_eof (msg);
238 return (((((((b4 & 0xff) << 8)
239 | (b3 & 0xff)) << 8)
240 | (b2 & 0xff)) << 8)
241 | (b1 & 0xff));
242 }
243
244 /* Read data from a file. This is a wrapper to do error checking. */
245
246 static void
247 get_data (e, p, c, msg)
248 FILE *e;
249 unsigned char *p;
250 unsigned long c;
251 const char *msg;
252 {
253 unsigned long got;
254
255 got = fread (p, 1, c, e);
256 if (got == c)
257 return;
258
259 fatal ("%s: read of %lu returned %lu", msg, c, got);
260 }
261 \f
262 /* Define an accelerator resource. */
263
264 void
265 define_accelerator (id, resinfo, data)
266 struct res_id id;
267 const struct res_res_info *resinfo;
268 struct accelerator *data;
269 {
270 struct res_resource *r;
271
272 r = define_standard_resource (&resources, RT_ACCELERATORS, id,
273 resinfo->language, 0);
274 r->type = RES_TYPE_ACCELERATOR;
275 r->u.acc = data;
276 r->res_info = *resinfo;
277 }
278
279 /* Define a bitmap resource. Bitmap data is stored in a file. The
280 first 14 bytes of the file are a standard header, which is not
281 included in the resource data. */
282
283 #define BITMAP_SKIP (14)
284
285 void
286 define_bitmap (id, resinfo, filename)
287 struct res_id id;
288 const struct res_res_info *resinfo;
289 const char *filename;
290 {
291 FILE *e;
292 char *real_filename;
293 struct stat s;
294 unsigned char *data;
295 int i;
296 struct res_resource *r;
297
298 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
299
300 if (stat (real_filename, &s) < 0)
301 fatal ("stat failed on bitmap file `%s': %s", real_filename,
302 strerror (errno));
303
304 data = (unsigned char *) xmalloc (s.st_size - BITMAP_SKIP);
305
306 for (i = 0; i < BITMAP_SKIP; i++)
307 getc (e);
308
309 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
310
311 fclose (e);
312 free (real_filename);
313
314 r = define_standard_resource (&resources, RT_BITMAP, id,
315 resinfo->language, 0);
316
317 r->type = RES_TYPE_BITMAP;
318 r->u.data.length = s.st_size - BITMAP_SKIP;
319 r->u.data.data = data;
320 r->res_info = *resinfo;
321 }
322
323 /* Define a cursor resource. A cursor file may contain a set of
324 bitmaps, each representing the same cursor at various different
325 resolutions. They each get written out with a different ID. The
326 real cursor resource is then a group resource which can be used to
327 select one of the actual cursors. */
328
329 void
330 define_cursor (id, resinfo, filename)
331 struct res_id id;
332 const struct res_res_info *resinfo;
333 const char *filename;
334 {
335 FILE *e;
336 char *real_filename;
337 int type, count, i;
338 struct icondir *icondirs;
339 int first_cursor;
340 struct res_resource *r;
341 struct group_cursor *first, **pp;
342
343 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
344
345 /* A cursor file is basically an icon file. The start of the file
346 is a three word structure. The first word is ignored. The
347 second word is the type of data. The third word is the number of
348 entries. */
349
350 get_word (e, real_filename);
351 type = get_word (e, real_filename);
352 count = get_word (e, real_filename);
353 if (type != 2)
354 fatal ("cursor file `%s' does not contain cursor data", real_filename);
355
356 /* Read in the icon directory entries. */
357
358 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
359
360 for (i = 0; i < count; i++)
361 {
362 icondirs[i].width = getc (e);
363 icondirs[i].height = getc (e);
364 icondirs[i].colorcount = getc (e);
365 getc (e);
366 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
367 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
368 icondirs[i].bytes = get_long (e, real_filename);
369 icondirs[i].offset = get_long (e, real_filename);
370
371 if (feof (e))
372 unexpected_eof (real_filename);
373 }
374
375 /* Define each cursor as a unique resource. */
376
377 first_cursor = cursors;
378
379 for (i = 0; i < count; i++)
380 {
381 unsigned char *data;
382 struct res_id name;
383 struct cursor *c;
384
385 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
386 fatal ("%s: fseek to %lu failed: %s", real_filename,
387 icondirs[i].offset, strerror (errno));
388
389 data = (unsigned char *) xmalloc (icondirs[i].bytes);
390
391 get_data (e, data, icondirs[i].bytes, real_filename);
392
393 c = (struct cursor *) xmalloc (sizeof *c);
394 c->xhotspot = icondirs[i].u.cursor.xhotspot;
395 c->yhotspot = icondirs[i].u.cursor.yhotspot;
396 c->length = icondirs[i].bytes;
397 c->data = data;
398
399 ++cursors;
400
401 name.named = 0;
402 name.u.id = cursors;
403
404 r = define_standard_resource (&resources, RT_CURSOR, name,
405 resinfo->language, 0);
406 r->type = RES_TYPE_CURSOR;
407 r->u.cursor = c;
408 r->res_info = *resinfo;
409 }
410
411 fclose (e);
412 free (real_filename);
413
414 /* Define a cursor group resource. */
415
416 first = NULL;
417 pp = &first;
418 for (i = 0; i < count; i++)
419 {
420 struct group_cursor *cg;
421
422 /* These manipulations of icondirs into cg are copied from rcl. */
423
424 cg = (struct group_cursor *) xmalloc (sizeof *cg);
425 cg->next = NULL;
426 cg->width = icondirs[i].width;
427 cg->height = 2 * icondirs[i].height;
428 cg->planes = 1;
429 cg->bits = 4;
430 cg->bytes = icondirs[i].bytes + 8;
431 cg->index = first_cursor + i + 1;
432
433 *pp = cg;
434 pp = &(*pp)->next;
435 }
436
437 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
438 resinfo->language, 0);
439 r->type = RES_TYPE_GROUP_CURSOR;
440 r->u.group_cursor = first;
441 r->res_info = *resinfo;
442 }
443
444 /* Define a dialog resource. */
445
446 void
447 define_dialog (id, resinfo, dialog)
448 struct res_id id;
449 const struct res_res_info *resinfo;
450 const struct dialog *dialog;
451 {
452 struct dialog *copy;
453 struct res_resource *r;
454
455 copy = (struct dialog *) xmalloc (sizeof *copy);
456 *copy = *dialog;
457
458 r = define_standard_resource (&resources, RT_DIALOG, id,
459 resinfo->language, 0);
460 r->type = RES_TYPE_DIALOG;
461 r->u.dialog = copy;
462 r->res_info = *resinfo;
463 }
464
465 /* Define a dialog control. This does not define a resource, but
466 merely allocates and fills in a structure. */
467
468 struct dialog_control *
469 define_control (text, id, x, y, width, height, class, style, exstyle)
470 char *text;
471 unsigned long id;
472 unsigned long x;
473 unsigned long y;
474 unsigned long width;
475 unsigned long height;
476 unsigned long class;
477 unsigned long style;
478 unsigned long exstyle;
479 {
480 struct dialog_control *n;
481
482 n = (struct dialog_control *) xmalloc (sizeof *n);
483 n->next = NULL;
484 n->id = id;
485 n->style = style;
486 n->exstyle = exstyle;
487 n->x = x;
488 n->y = y;
489 n->width = width;
490 n->height = height;
491 n->class.named = 0;
492 n->class.u.id = class;
493 if (text != NULL)
494 res_string_to_id (&n->text, text);
495 else
496 {
497 n->text.named = 0;
498 n->text.u.id = 0;
499 }
500 free (text);
501 n->data = NULL;
502 n->help = 0;
503
504 return n;
505 }
506
507 /* Define a font resource. */
508
509 void
510 define_font (id, resinfo, filename)
511 struct res_id id;
512 const struct res_res_info *resinfo;
513 const char *filename;
514 {
515 FILE *e;
516 char *real_filename;
517 struct stat s;
518 unsigned char *data;
519 struct res_resource *r;
520 struct fontdir *fd;
521 long offset;
522 const char *device, *face;
523 struct fontdir **pp;
524
525 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
526
527 if (stat (real_filename, &s) < 0)
528 fatal ("stat failed on bitmap file `%s': %s", real_filename,
529 strerror (errno));
530
531 data = (unsigned char *) xmalloc (s.st_size);
532
533 get_data (e, data, s.st_size, real_filename);
534
535 fclose (e);
536 free (real_filename);
537
538 r = define_standard_resource (&resources, RT_FONT, id,
539 resinfo->language, 0);
540
541 r->type = RES_TYPE_FONT;
542 r->u.data.length = s.st_size;
543 r->u.data.data = data;
544 r->res_info = *resinfo;
545
546 /* For each font resource, we must add an entry in the FONTDIR
547 resource. The FONTDIR resource includes some strings in the font
548 file. To find them, we have to do some magic on the data we have
549 read. */
550
551 offset = ((((((data[47] << 8)
552 | data[46]) << 8)
553 | data[45]) << 8)
554 | data[44]);
555 if (offset > 0 && offset < s.st_size)
556 device = (char *) data + offset;
557 else
558 device = "";
559
560 offset = ((((((data[51] << 8)
561 | data[50]) << 8)
562 | data[49]) << 8)
563 | data[48]);
564 if (offset > 0 && offset < s.st_size)
565 face = (char *) data + offset;
566 else
567 face = "";
568
569 ++fonts;
570
571 fd = (struct fontdir *) xmalloc (sizeof *fd);
572 fd->next = NULL;
573 fd->index = fonts;
574 fd->length = 58 + strlen (device) + strlen (face);
575 fd->data = (unsigned char *) xmalloc (fd->length);
576
577 memcpy (fd->data, data, 56);
578 strcpy ((char *) fd->data + 56, device);
579 strcpy ((char *) fd->data + 57 + strlen (device), face);
580
581 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
582 ;
583 *pp = fd;
584
585 /* For the single fontdirs resource, we always use the resource
586 information of the last font. I don't know what else to do. */
587 fontdirs_resinfo = *resinfo;
588 }
589
590 /* Define the fontdirs resource. This is called after the entire rc
591 file has been parsed, if any font resources were seen. */
592
593 static void
594 define_fontdirs ()
595 {
596 struct res_resource *r;
597 struct res_id id;
598
599 id.named = 0;
600 id.u.id = 1;
601
602 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
603
604 r->type = RES_TYPE_FONTDIR;
605 r->u.fontdir = fontdirs;
606 r->res_info = fontdirs_resinfo;
607 }
608
609 /* Define an icon resource. An icon file may contain a set of
610 bitmaps, each representing the same icon at various different
611 resolutions. They each get written out with a different ID. The
612 real icon resource is then a group resource which can be used to
613 select one of the actual icon bitmaps. */
614
615 void
616 define_icon (id, resinfo, filename)
617 struct res_id id;
618 const struct res_res_info *resinfo;
619 const char *filename;
620 {
621 FILE *e;
622 char *real_filename;
623 int type, count, i;
624 struct icondir *icondirs;
625 int first_icon;
626 struct res_resource *r;
627 struct group_icon *first, **pp;
628
629 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
630
631 /* The start of an icon file is a three word structure. The first
632 word is ignored. The second word is the type of data. The third
633 word is the number of entries. */
634
635 get_word (e, real_filename);
636 type = get_word (e, real_filename);
637 count = get_word (e, real_filename);
638 if (type != 1)
639 fatal ("icon file `%s' does not contain icon data", real_filename);
640
641 /* Read in the icon directory entries. */
642
643 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
644
645 for (i = 0; i < count; i++)
646 {
647 icondirs[i].width = getc (e);
648 icondirs[i].height = getc (e);
649 icondirs[i].colorcount = getc (e);
650 getc (e);
651 icondirs[i].u.icon.planes = get_word (e, real_filename);
652 icondirs[i].u.icon.bits = get_word (e, real_filename);
653 icondirs[i].bytes = get_long (e, real_filename);
654 icondirs[i].offset = get_long (e, real_filename);
655
656 if (feof (e))
657 unexpected_eof (real_filename);
658 }
659
660 /* Define each icon as a unique resource. */
661
662 first_icon = icons;
663
664 for (i = 0; i < count; i++)
665 {
666 unsigned char *data;
667 struct res_id name;
668
669 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
670 fatal ("%s: fseek to %lu failed: %s", real_filename,
671 icondirs[i].offset, strerror (errno));
672
673 data = (unsigned char *) xmalloc (icondirs[i].bytes);
674
675 get_data (e, data, icondirs[i].bytes, real_filename);
676
677 ++icons;
678
679 name.named = 0;
680 name.u.id = icons;
681
682 r = define_standard_resource (&resources, RT_ICON, name,
683 resinfo->language, 0);
684 r->type = RES_TYPE_ICON;
685 r->u.data.length = icondirs[i].bytes;
686 r->u.data.data = data;
687 r->res_info = *resinfo;
688 }
689
690 fclose (e);
691 free (real_filename);
692
693 /* Define an icon group resource. */
694
695 first = NULL;
696 pp = &first;
697 for (i = 0; i < count; i++)
698 {
699 struct group_icon *cg;
700
701 /* FIXME: rcl sets planes and bits based on colors, rather than
702 just copying the values from the file. */
703
704 cg = (struct group_icon *) xmalloc (sizeof *cg);
705 cg->next = NULL;
706 cg->width = icondirs[i].width;
707 cg->height = icondirs[i].height;
708 cg->colors = icondirs[i].colorcount;
709 cg->planes = icondirs[i].u.icon.planes;
710 cg->bits = icondirs[i].u.icon.bits;
711 cg->bytes = icondirs[i].bytes;
712 cg->index = first_icon + i + 1;
713
714 *pp = cg;
715 pp = &(*pp)->next;
716 }
717
718 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
719 resinfo->language, 0);
720 r->type = RES_TYPE_GROUP_ICON;
721 r->u.group_icon = first;
722 r->res_info = *resinfo;
723 }
724
725 /* Define a menu resource. */
726
727 void
728 define_menu (id, resinfo, menuitems)
729 struct res_id id;
730 const struct res_res_info *resinfo;
731 struct menuitem *menuitems;
732 {
733 struct res_resource *r;
734
735 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
736 r->type = RES_TYPE_MENU;
737 r->u.menu = menuitems;
738 r->res_info = *resinfo;
739 }
740
741 /* Define a menu item. This does not define a resource, but merely
742 allocates and fills in a structure. */
743
744 struct menuitem *
745 define_menuitem (text, menuid, type, state, help, menuitems)
746 char *text;
747 int menuid;
748 unsigned long type;
749 unsigned long state;
750 unsigned long help;
751 struct menuitem *menuitems;
752 {
753 struct menuitem *mi;
754
755 mi = (struct menuitem *) xmalloc (sizeof *mi);
756 mi->next = NULL;
757 mi->type = type;
758 mi->state = state;
759 mi->id = menuid;
760 mi->text = text;
761 mi->help = help;
762 mi->popup = menuitems;
763 return mi;
764 }
765
766 /* Define a messagetable resource. */
767
768 void
769 define_messagetable (id, resinfo, filename)
770 struct res_id id;
771 const struct res_res_info *resinfo;
772 const char *filename;
773 {
774 FILE *e;
775 char *real_filename;
776 struct stat s;
777 unsigned char *data;
778 struct res_resource *r;
779
780 e = open_file_search (filename, FOPEN_RB, "messagetable file",
781 &real_filename);
782
783 if (stat (real_filename, &s) < 0)
784 fatal ("stat failed on bitmap file `%s': %s", real_filename,
785 strerror (errno));
786
787 data = (unsigned char *) xmalloc (s.st_size);
788
789 get_data (e, data, s.st_size, real_filename);
790
791 fclose (e);
792 free (real_filename);
793
794 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
795 resinfo->language, 0);
796
797 r->type = RES_TYPE_MESSAGETABLE;
798 r->u.data.length = s.st_size;
799 r->u.data.data = data;
800 r->res_info = *resinfo;
801 }
802
803 /* Define an rcdata resource. */
804
805 void
806 define_rcdata (id, resinfo, data)
807 struct res_id id;
808 const struct res_res_info *resinfo;
809 struct rcdata_data *data;
810 {
811 struct res_resource *r;
812
813 r = define_standard_resource (&resources, RT_RCDATA, id,
814 resinfo->language, 0);
815 r->type = RES_TYPE_RCDATA;
816 r->u.rcdata = data;
817 r->res_info = *resinfo;
818 }
819
820 /* Add an rcdata_item to an rcdata resource. */
821
822 struct rcdata_data *
823 append_rcdata_item (data, item)
824 struct rcdata_data *data;
825 struct rcdata_item *item;
826 {
827 if (data == NULL)
828 {
829 data = (struct rcdata_data *) xmalloc (sizeof *data);
830 data->first = item;
831 data->last = item;
832 }
833 else
834 {
835 data->last->next = item;
836 data->last = item;
837 }
838
839 return data;
840 }
841
842 /* Add a string to an rcdata resource. */
843
844 struct rcdata_data *
845 append_rcdata_string (data, string)
846 struct rcdata_data *data;
847 char *string;
848 {
849 struct rcdata_item *ri;
850
851 ri = (struct rcdata_item *) xmalloc (sizeof *ri);
852 ri->next = NULL;
853 ri->type = RCDATA_STRING;
854 ri->u.string = string;
855
856 return append_rcdata_item (data, ri);
857 }
858
859 /* Add a number to an rcdata resource. */
860
861 struct rcdata_data *
862 append_rcdata_number (data, val, dword)
863 struct rcdata_data *data;
864 unsigned long val;
865 int dword;
866 {
867 struct rcdata_item *ri;
868
869 ri = (struct rcdata_item *) xmalloc (sizeof *ri);
870 ri->next = NULL;
871 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
872 ri->u.word = val;
873
874 return append_rcdata_item (data, ri);
875 }
876
877 /* Define a stringtable resource. This is called for each string
878 which appears in a STRINGTABLE statement. */
879
880 void
881 define_stringtable (resinfo, stringid, string)
882 const struct res_res_info *resinfo;
883 unsigned long stringid;
884 char *string;
885 {
886 struct res_id id;
887 struct res_resource *r;
888
889 id.named = 0;
890 id.u.id = stringid >> 4;
891 r = define_standard_resource (&resources, RT_STRING, id,
892 resinfo->language, 1);
893
894 if (r->type == RES_TYPE_UNINITIALIZED)
895 {
896 int i;
897
898 r->type = RES_TYPE_STRINGTABLE;
899 r->u.stringtable = ((struct stringtable *)
900 xmalloc (sizeof (struct stringtable)));
901 for (i = 0; i < 16; i++)
902 {
903 r->u.stringtable->strings[i].length = 0;
904 r->u.stringtable->strings[i].string = NULL;
905 }
906
907 r->res_info = *resinfo;
908 }
909
910 unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
911 &r->u.stringtable->strings[stringid & 0xf].string,
912 string);
913 free (string);
914 }
915
916 /* Define a user data resource where the data is in the rc file. */
917
918 void
919 define_user_data (id, type, resinfo, data)
920 struct res_id id;
921 struct res_id type;
922 const struct res_res_info *resinfo;
923 struct rcdata_data *data;
924 {
925 struct res_id ids[3];
926 struct res_resource *r;
927
928 ids[0] = type;
929 ids[1] = id;
930 ids[2].named = 0;
931 ids[2].u.id = resinfo->language;
932
933 r = define_resource (&resources, 3, ids, 0);
934 r->type = RES_TYPE_USERDATA;
935 r->u.userdata = data;
936 r->res_info = *resinfo;
937 }
938
939 /* Define a user data resource where the data is in a file. */
940
941 void
942 define_user_file (id, type, resinfo, filename)
943 struct res_id id;
944 struct res_id type;
945 const struct res_res_info *resinfo;
946 const char *filename;
947 {
948 FILE *e;
949 char *real_filename;
950 struct stat s;
951 unsigned char *data;
952 struct res_id ids[3];
953 struct res_resource *r;
954
955 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
956
957 if (stat (real_filename, &s) < 0)
958 fatal ("stat failed on bitmap file `%s': %s", real_filename,
959 strerror (errno));
960
961 data = (unsigned char *) xmalloc (s.st_size);
962
963 get_data (e, data, s.st_size, real_filename);
964
965 fclose (e);
966 free (real_filename);
967
968 ids[0] = type;
969 ids[1] = id;
970 ids[2].named = 0;
971 ids[2].u.id = resinfo->language;
972
973 r = define_resource (&resources, 3, ids, 0);
974 r->type = RES_TYPE_USERDATA;
975 r->u.userdata = ((struct rcdata_data *)
976 xmalloc (sizeof (struct rcdata_data)));
977 r->u.userdata->first = ((struct rcdata_item *)
978 xmalloc (sizeof (struct rcdata_item)));
979 r->u.userdata->last = r->u.userdata->first;
980 r->u.userdata->first->next = NULL;
981 r->u.userdata->first->type = RCDATA_BUFFER;
982 r->u.userdata->first->u.buffer.length = s.st_size;
983 r->u.userdata->first->u.buffer.data = data;
984 r->res_info = *resinfo;
985 }
986
987 /* Define a versioninfo resource. */
988
989 void
990 define_versioninfo (id, language, fixedverinfo, verinfo)
991 struct res_id id;
992 int language;
993 struct fixed_versioninfo *fixedverinfo;
994 struct ver_info *verinfo;
995 {
996 struct res_resource *r;
997
998 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
999 r->type = RES_TYPE_VERSIONINFO;
1000 r->u.versioninfo = ((struct versioninfo *)
1001 xmalloc (sizeof (struct versioninfo)));
1002 r->u.versioninfo->fixed = fixedverinfo;
1003 r->u.versioninfo->var = verinfo;
1004 r->res_info.language = language;
1005 }
1006
1007 /* Add string version info to a list of version information. */
1008
1009 struct ver_info *
1010 append_ver_stringfileinfo (verinfo, language, strings)
1011 struct ver_info *verinfo;
1012 char *language;
1013 struct ver_stringinfo *strings;
1014 {
1015 struct ver_info *vi, **pp;
1016
1017 vi = (struct ver_info *) xmalloc (sizeof *vi);
1018 vi->next = NULL;
1019 vi->type = VERINFO_STRING;
1020 unicode_from_ascii ((unsigned short *) NULL, &vi->u.string.language,
1021 language);
1022 free (language);
1023 vi->u.string.strings = strings;
1024
1025 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1026 ;
1027 *pp = vi;
1028
1029 return verinfo;
1030 }
1031
1032 /* Add variable version info to a list of version information. */
1033
1034 struct ver_info *
1035 append_ver_varfileinfo (verinfo, key, var)
1036 struct ver_info *verinfo;
1037 char *key;
1038 struct ver_varinfo *var;
1039 {
1040 struct ver_info *vi, **pp;
1041
1042 vi = (struct ver_info *) xmalloc (sizeof *vi);
1043 vi->next = NULL;
1044 vi->type = VERINFO_VAR;
1045 unicode_from_ascii ((unsigned short *) NULL, &vi->u.var.key, key);
1046 free (key);
1047 vi->u.var.var = var;
1048
1049 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1050 ;
1051 *pp = vi;
1052
1053 return verinfo;
1054 }
1055
1056 /* Append version string information to a list. */
1057
1058 struct ver_stringinfo *
1059 append_verval (strings, key, value)
1060 struct ver_stringinfo *strings;
1061 char *key;
1062 char *value;
1063 {
1064 struct ver_stringinfo *vs, **pp;
1065
1066 vs = (struct ver_stringinfo *) xmalloc (sizeof *vs);
1067 vs->next = NULL;
1068 unicode_from_ascii ((unsigned short *) NULL, &vs->key, key);
1069 free (key);
1070 unicode_from_ascii ((unsigned short *) NULL, &vs->value, value);
1071 free (value);
1072
1073 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1074 ;
1075 *pp = vs;
1076
1077 return strings;
1078 }
1079
1080 /* Append version variable information to a list. */
1081
1082 struct ver_varinfo *
1083 append_vertrans (var, language, charset)
1084 struct ver_varinfo *var;
1085 unsigned long language;
1086 unsigned long charset;
1087 {
1088 struct ver_varinfo *vv, **pp;
1089
1090 vv = (struct ver_varinfo *) xmalloc (sizeof *vv);
1091 vv->next = NULL;
1092 vv->language = language;
1093 vv->charset = charset;
1094
1095 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1096 ;
1097 *pp = vv;
1098
1099 return var;
1100 }
1101 \f
1102 /* Local functions used to write out an rc file. */
1103
1104 static void indent PARAMS ((FILE *, int));
1105 static void write_rc_directory
1106 PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
1107 const struct res_id *, int *, int));
1108 static void write_rc_subdir
1109 PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
1110 const struct res_id *, int *, int));
1111 static void write_rc_resource
1112 PARAMS ((FILE *, const struct res_id *, const struct res_id *,
1113 const struct res_resource *, int *));
1114 static void write_rc_accelerators
1115 PARAMS ((FILE *, const struct accelerator *));
1116 static void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
1117 static void write_rc_group_cursor
1118 PARAMS ((FILE *, const struct group_cursor *));
1119 static void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
1120 static void write_rc_dialog_control
1121 PARAMS ((FILE *, const struct dialog_control *));
1122 static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
1123 static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
1124 static void write_rc_menu PARAMS ((FILE *, const struct menuitem *, int, int));
1125 static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_data *, int));
1126 static void write_rc_stringtable
1127 PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
1128 static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
1129 static void write_rc_filedata
1130 PARAMS ((FILE *, unsigned long, const unsigned char *));
1131
1132 /* Indent a given number of spaces. */
1133
1134 static void
1135 indent (e, c)
1136 FILE *e;
1137 int c;
1138 {
1139 int i;
1140
1141 for (i = 0; i < c; i++)
1142 putc (' ', e);
1143 }
1144
1145 /* Dump the resources we have read in the format of an rc file.
1146
1147 Actually, we don't use the format of an rc file, because it's way
1148 too much of a pain--for example, we'd have to write icon resources
1149 into a file and refer to that file. We just generate a readable
1150 format that kind of looks like an rc file, and is useful for
1151 understanding the contents of a resource file. Someday we may want
1152 to generate an rc file which the rc compiler can read; if that day
1153 comes, this code will have to be fixed up. */
1154
1155 void
1156 write_rc_file (filename, resources)
1157 const char *filename;
1158 const struct res_directory *resources;
1159 {
1160 FILE *e;
1161 int language;
1162
1163 if (filename == NULL)
1164 e = stdout;
1165 else
1166 {
1167 e = fopen (filename, FOPEN_WT);
1168 if (e == NULL)
1169 fatal ("can't open `%s' for output: %s", filename, strerror (errno));
1170 }
1171
1172 language = -1;
1173 write_rc_directory (e, resources, (const struct res_id *) NULL,
1174 (const struct res_id *) NULL, &language, 1);
1175 }
1176
1177 /* Write out a directory. E is the file to write to. RD is the
1178 directory. TYPE is a pointer to the level 1 ID which serves as the
1179 resource type. NAME is a pointer to the level 2 ID which serves as
1180 an individual resource name. LANGUAGE is a pointer to the current
1181 language. LEVEL is the level in the tree. */
1182
1183 static void
1184 write_rc_directory (e, rd, type, name, language, level)
1185 FILE *e;
1186 const struct res_directory *rd;
1187 const struct res_id *type;
1188 const struct res_id *name;
1189 int *language;
1190 int level;
1191 {
1192 const struct res_entry *re;
1193
1194 /* Print out some COFF information that rc files can't represent. */
1195
1196 if (rd->time != 0)
1197 fprintf (e, "// Time stamp: %lu\n", rd->time);
1198 if (rd->characteristics != 0)
1199 fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1200 if (rd->major != 0 || rd->minor != 0)
1201 fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1202
1203 for (re = rd->entries; re != NULL; re = re->next)
1204 {
1205 switch (level)
1206 {
1207 case 1:
1208 /* If we're at level 1, the key of this resource is the
1209 type. This normally duplicates the information we have
1210 stored with the resource itself, but we need to remember
1211 the type if this is a user define resource type. */
1212 type = &re->id;
1213 break;
1214
1215 case 2:
1216 /* If we're at level 2, the key of this resource is the name
1217 we are going to use in the rc printout. */
1218 name = &re->id;
1219 break;
1220
1221 case 3:
1222 /* If we're at level 3, then this key represents a language.
1223 Use it to update the current language. */
1224 if (! re->id.named
1225 && re->id.u.id != *language
1226 && (re->id.u.id & 0xffff) == re->id.u.id)
1227 {
1228 fprintf (e, "LANGUAGE %lu, %lu\n",
1229 re->id.u.id & 0xff, (re->id.u.id >> 8) & 0xff);
1230 *language = re->id.u.id;
1231 }
1232 break;
1233
1234 default:
1235 break;
1236 }
1237
1238 if (re->subdir)
1239 write_rc_subdir (e, re, type, name, language, level);
1240 else
1241 {
1242 if (level == 3)
1243 {
1244 /* This is the normal case: the three levels are
1245 TYPE/NAME/LANGUAGE. NAME will have been set at level
1246 2, and represents the name to use. We probably just
1247 set LANGUAGE, and it will probably match what the
1248 resource itself records if anything. */
1249 write_rc_resource (e, type, name, re->u.res, language);
1250 }
1251 else
1252 {
1253 fprintf (e, "// Resource at unexpected level %d\n", level);
1254 write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1255 language);
1256 }
1257 }
1258 }
1259 }
1260
1261 /* Write out a subdirectory entry. E is the file to write to. RE is
1262 the subdirectory entry. TYPE and NAME are pointers to higher level
1263 IDs, or NULL. LANGUAGE is a pointer to the current language.
1264 LEVEL is the level in the tree. */
1265
1266 static void
1267 write_rc_subdir (e, re, type, name, language, level)
1268 FILE *e;
1269 const struct res_entry *re;
1270 const struct res_id *type;
1271 const struct res_id *name;
1272 int *language;
1273 int level;
1274 {
1275 fprintf (e, "\n");
1276 switch (level)
1277 {
1278 case 1:
1279 fprintf (e, "// Type: ");
1280 if (re->id.named)
1281 res_id_print (e, re->id, 1);
1282 else
1283 {
1284 const char *s;
1285
1286 switch (re->id.u.id)
1287 {
1288 case RT_CURSOR: s = "cursor"; break;
1289 case RT_BITMAP: s = "bitmap"; break;
1290 case RT_ICON: s = "icon"; break;
1291 case RT_MENU: s = "menu"; break;
1292 case RT_DIALOG: s = "dialog"; break;
1293 case RT_STRING: s = "stringtable"; break;
1294 case RT_FONTDIR: s = "fontdir"; break;
1295 case RT_FONT: s = "font"; break;
1296 case RT_ACCELERATORS: s = "accelerators"; break;
1297 case RT_RCDATA: s = "rcdata"; break;
1298 case RT_MESSAGETABLE: s = "messagetable"; break;
1299 case RT_GROUP_CURSOR: s = "group cursor"; break;
1300 case RT_GROUP_ICON: s = "group icon"; break;
1301 case RT_VERSION: s = "version"; break;
1302 case RT_DLGINCLUDE: s = "dlginclude"; break;
1303 case RT_PLUGPLAY: s = "plugplay"; break;
1304 case RT_VXD: s = "vxd"; break;
1305 case RT_ANICURSOR: s = "anicursor"; break;
1306 case RT_ANIICON: s = "aniicon"; break;
1307 default: s = NULL; break;
1308 }
1309
1310 if (s != NULL)
1311 fprintf (e, "%s", s);
1312 else
1313 res_id_print (e, re->id, 1);
1314 }
1315 fprintf (e, "\n");
1316 break;
1317
1318 case 2:
1319 fprintf (e, "// Name: ");
1320 res_id_print (e, re->id, 1);
1321 fprintf (e, "\n");
1322 break;
1323
1324 case 3:
1325 fprintf (e, "// Language: ");
1326 res_id_print (e, re->id, 1);
1327 fprintf (e, "\n");
1328 break;
1329
1330 default:
1331 fprintf (e, "// Level %d: ", level);
1332 res_id_print (e, re->id, 1);
1333 fprintf (e, "\n");
1334 }
1335
1336 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1337 }
1338
1339 /* Write out a single resource. E is the file to write to. TYPE is a
1340 pointer to the type of the resource. NAME is a pointer to the name
1341 of the resource; it will be NULL if there is a level mismatch. RES
1342 is the resource data. LANGUAGE is a pointer to the current
1343 language. */
1344
1345 static void
1346 write_rc_resource (e, type, name, res, language)
1347 FILE *e;
1348 const struct res_id *type;
1349 const struct res_id *name;
1350 const struct res_resource *res;
1351 int *language;
1352 {
1353 const char *s;
1354 int rt;
1355 int menuex = 0;
1356
1357 fprintf (e, "\n");
1358
1359 switch (res->type)
1360 {
1361 default:
1362 abort ();
1363
1364 case RES_TYPE_ACCELERATOR:
1365 s = "ACCELERATOR";
1366 rt = RT_ACCELERATORS;
1367 break;
1368
1369 case RES_TYPE_BITMAP:
1370 s = "BITMAP";
1371 rt = RT_BITMAP;
1372 break;
1373
1374 case RES_TYPE_CURSOR:
1375 s = "CURSOR";
1376 rt = RT_CURSOR;
1377 break;
1378
1379 case RES_TYPE_GROUP_CURSOR:
1380 s = "GROUP_CURSOR";
1381 rt = RT_GROUP_CURSOR;
1382 break;
1383
1384 case RES_TYPE_DIALOG:
1385 if (extended_dialog (res->u.dialog))
1386 s = "DIALOGEX";
1387 else
1388 s = "DIALOG";
1389 rt = RT_DIALOG;
1390 break;
1391
1392 case RES_TYPE_FONT:
1393 s = "FONT";
1394 rt = RT_FONT;
1395 break;
1396
1397 case RES_TYPE_FONTDIR:
1398 s = "FONTDIR";
1399 rt = RT_FONTDIR;
1400 break;
1401
1402 case RES_TYPE_ICON:
1403 s = "ICON";
1404 rt = RT_ICON;
1405 break;
1406
1407 case RES_TYPE_GROUP_ICON:
1408 s = "GROUP_ICON";
1409 rt = RT_GROUP_ICON;
1410 break;
1411
1412 case RES_TYPE_MENU:
1413 if (extended_menu (res->u.menu))
1414 {
1415 s = "MENUEX";
1416 menuex = 1;
1417 }
1418 else
1419 {
1420 s = "MENU";
1421 menuex = 0;
1422 }
1423 rt = RT_MENU;
1424 break;
1425
1426 case RES_TYPE_MESSAGETABLE:
1427 s = "MESSAGETABLE";
1428 rt = RT_MESSAGETABLE;
1429 break;
1430
1431 case RES_TYPE_RCDATA:
1432 s = "RCDATA";
1433 rt = RT_RCDATA;
1434 break;
1435
1436 case RES_TYPE_STRINGTABLE:
1437 s = "STRINGTABLE";
1438 rt = RT_STRING;
1439 break;
1440
1441 case RES_TYPE_USERDATA:
1442 s = NULL;
1443 rt = 0;
1444 break;
1445
1446 case RES_TYPE_VERSIONINFO:
1447 s = "VERSIONINFO";
1448 rt = RT_VERSION;
1449 break;
1450 }
1451
1452 if (rt != 0
1453 && type != NULL
1454 && (type->named || type->u.id != rt))
1455 {
1456 fprintf (e, "// Unexpected resource type mismatch: ");
1457 res_id_print (e, *type, 1);
1458 fprintf (e, " != %d", rt);
1459 }
1460
1461 if (res->coff_info.codepage != 0)
1462 fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1463 if (res->coff_info.reserved != 0)
1464 fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1465
1466 if (name != NULL)
1467 res_id_print (e, *name, 0);
1468 else
1469 fprintf (e, "??Unknown-Name??");
1470
1471 fprintf (e, " ");
1472 if (s != NULL)
1473 fprintf (e, "%s", s);
1474 else if (type != NULL)
1475 res_id_print (e, *type, 0);
1476 else
1477 fprintf (e, "??Unknown-Type??");
1478
1479 if (res->res_info.memflags != 0)
1480 {
1481 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1482 fprintf (e, " MOVEABLE");
1483 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1484 fprintf (e, " PURE");
1485 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1486 fprintf (e, " PRELOAD");
1487 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1488 fprintf (e, " DISCARDABLE");
1489 }
1490
1491 if (res->type == RES_TYPE_DIALOG)
1492 {
1493 fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1494 res->u.dialog->width, res->u.dialog->height);
1495 if (res->u.dialog->ex != NULL
1496 && res->u.dialog->ex->help != 0)
1497 fprintf (e, ", %lu", res->u.dialog->ex->help);
1498 }
1499
1500 fprintf (e, "\n");
1501
1502 if ((res->res_info.language != 0 && res->res_info.language != *language)
1503 || res->res_info.characteristics != 0
1504 || res->res_info.version != 0)
1505 {
1506 int modifiers;
1507
1508 switch (res->type)
1509 {
1510 case RES_TYPE_ACCELERATOR:
1511 case RES_TYPE_DIALOG:
1512 case RES_TYPE_MENU:
1513 case RES_TYPE_RCDATA:
1514 case RES_TYPE_STRINGTABLE:
1515 modifiers = 1;
1516 break;
1517
1518 default:
1519 modifiers = 0;
1520 break;
1521 }
1522
1523 if (res->res_info.language != 0 && res->res_info.language != *language)
1524 fprintf (e, "%sLANGUAGE %d, %d\n",
1525 modifiers ? "// " : "",
1526 res->res_info.language & 0xff,
1527 (res->res_info.language >> 8) & 0xff);
1528 if (res->res_info.characteristics != 0)
1529 fprintf (e, "%sCHARACTERISTICS %lu\n",
1530 modifiers ? "// " : "",
1531 res->res_info.characteristics);
1532 if (res->res_info.version != 0)
1533 fprintf (e, "%sVERSION %lu\n",
1534 modifiers ? "// " : "",
1535 res->res_info.version);
1536 }
1537
1538 switch (res->type)
1539 {
1540 default:
1541 abort ();
1542
1543 case RES_TYPE_ACCELERATOR:
1544 write_rc_accelerators (e, res->u.acc);
1545 break;
1546
1547 case RES_TYPE_CURSOR:
1548 write_rc_cursor (e, res->u.cursor);
1549 break;
1550
1551 case RES_TYPE_GROUP_CURSOR:
1552 write_rc_group_cursor (e, res->u.group_cursor);
1553 break;
1554
1555 case RES_TYPE_DIALOG:
1556 write_rc_dialog (e, res->u.dialog);
1557 break;
1558
1559 case RES_TYPE_FONTDIR:
1560 write_rc_fontdir (e, res->u.fontdir);
1561 break;
1562
1563 case RES_TYPE_GROUP_ICON:
1564 write_rc_group_icon (e, res->u.group_icon);
1565 break;
1566
1567 case RES_TYPE_MENU:
1568 write_rc_menu (e, res->u.menu, menuex, 0);
1569 break;
1570
1571 case RES_TYPE_RCDATA:
1572 write_rc_rcdata (e, res->u.rcdata, 0);
1573 break;
1574
1575 case RES_TYPE_STRINGTABLE:
1576 write_rc_stringtable (e, name, res->u.stringtable);
1577 break;
1578
1579 case RES_TYPE_USERDATA:
1580 write_rc_rcdata (e, res->u.userdata, 0);
1581 break;
1582
1583 case RES_TYPE_VERSIONINFO:
1584 write_rc_versioninfo (e, res->u.versioninfo);
1585 break;
1586
1587 case RES_TYPE_BITMAP:
1588 case RES_TYPE_FONT:
1589 case RES_TYPE_ICON:
1590 case RES_TYPE_MESSAGETABLE:
1591 write_rc_filedata (e, res->u.data.length, res->u.data.data);
1592 break;
1593 }
1594 }
1595
1596 /* Write out accelerator information. */
1597
1598 static void
1599 write_rc_accelerators (e, accelerators)
1600 FILE *e;
1601 const struct accelerator *accelerators;
1602 {
1603 const struct accelerator *acc;
1604
1605 fprintf (e, "BEGIN\n");
1606 for (acc = accelerators; acc != NULL; acc = acc->next)
1607 {
1608 int printable;
1609
1610 fprintf (e, " ");
1611
1612 if ((acc->key & 0x7f) == acc->key
1613 && isprint ((unsigned char) acc->key)
1614 && (acc->flags & ACC_VIRTKEY) == 0)
1615 {
1616 fprintf (e, "\"%c\"", acc->key);
1617 printable = 1;
1618 }
1619 else
1620 {
1621 fprintf (e, "%d", acc->key);
1622 printable = 0;
1623 }
1624
1625 fprintf (e, ", %d", acc->id);
1626
1627 if (! printable)
1628 {
1629 if ((acc->flags & ACC_VIRTKEY) != 0)
1630 fprintf (e, ", VIRTKEY");
1631 else
1632 fprintf (e, ", ASCII");
1633 }
1634
1635 if ((acc->flags & ACC_SHIFT) != 0)
1636 fprintf (e, ", SHIFT");
1637 if ((acc->flags & ACC_CONTROL) != 0)
1638 fprintf (e, ", CONTROL");
1639 if ((acc->flags & ACC_ALT) != 0)
1640 fprintf (e, ", ALT");
1641
1642 fprintf (e, "\n");
1643 }
1644
1645 fprintf (e, "END\n");
1646 }
1647
1648 /* Write out cursor information. This would normally be in a separate
1649 file, which the rc file would include. */
1650
1651 static void
1652 write_rc_cursor (e, cursor)
1653 FILE *e;
1654 const struct cursor *cursor;
1655 {
1656 fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
1657 cursor->yhotspot);
1658 write_rc_filedata (e, cursor->length, cursor->data);
1659 }
1660
1661 /* Write out group cursor data. This would normally be built from the
1662 cursor data. */
1663
1664 static void
1665 write_rc_group_cursor (e, group_cursor)
1666 FILE *e;
1667 const struct group_cursor *group_cursor;
1668 {
1669 const struct group_cursor *gc;
1670
1671 for (gc = group_cursor; gc != NULL; gc = gc->next)
1672 {
1673 fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
1674 gc->width, gc->height, gc->planes, gc->bits);
1675 fprintf (e, "// data bytes: %lu; index: %d\n",
1676 gc->bytes, gc->index);
1677 }
1678 }
1679
1680 /* Write dialog data. */
1681
1682 static void
1683 write_rc_dialog (e, dialog)
1684 FILE *e;
1685 const struct dialog *dialog;
1686 {
1687 const struct dialog_control *control;
1688
1689 if (dialog->style != 0)
1690 fprintf (e, "STYLE 0x%lx\n", dialog->style);
1691 if (dialog->exstyle != 0)
1692 fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
1693 if (dialog->class.named || dialog->class.u.id != 0)
1694 {
1695 fprintf (e, "CLASS ");
1696 res_id_print (e, dialog->class, 0);
1697 fprintf (e, "\n");
1698 }
1699 if (dialog->caption != NULL)
1700 fprintf (e, "CAPTION \"%s\"\n", dialog->caption);
1701 if (dialog->menu.named || dialog->menu.u.id != 0)
1702 {
1703 fprintf (e, "MENU ");
1704 res_id_print (e, dialog->menu, 0);
1705 fprintf (e, "\n");
1706 }
1707 if (dialog->font != NULL)
1708 {
1709 fprintf (e, "FONT %d, \"%s\"", dialog->pointsize, dialog->font);
1710 if (dialog->ex != NULL
1711 && (dialog->ex->weight != 0 || dialog->ex->italic != 0))
1712 fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
1713 fprintf (e, "\n");
1714 }
1715
1716 fprintf (e, "BEGIN\n");
1717
1718 for (control = dialog->controls; control != NULL; control = control->next)
1719 write_rc_dialog_control (e, control);
1720
1721 fprintf (e, "END\n");
1722 }
1723
1724 /* For each predefined control keyword, this table provides the class
1725 and the style. */
1726
1727 struct control_info
1728 {
1729 const char *name;
1730 unsigned short class;
1731 unsigned long style;
1732 };
1733
1734 static const struct control_info control_info[] =
1735 {
1736 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
1737 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
1738 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
1739 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
1740 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
1741 { "CTEXT", CTL_STATIC, SS_CENTER },
1742 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
1743 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
1744 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
1745 { "ICON", CTL_STATIC, SS_ICON },
1746 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
1747 { "LTEXT", CTL_STATIC, SS_LEFT },
1748 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
1749 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
1750 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
1751 { "RTEXT", CTL_STATIC, SS_RIGHT },
1752 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
1753 { "STATE3", CTL_BUTTON, BS_3STATE },
1754 /* It's important that USERBUTTON come after all the other button
1755 types, so that it won't be matched too early. */
1756 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
1757 { NULL, 0, 0 }
1758 };
1759
1760 /* Write a dialog control. */
1761
1762 static void
1763 write_rc_dialog_control (e, control)
1764 FILE *e;
1765 const struct dialog_control *control;
1766 {
1767 const struct control_info *ci;
1768
1769 fprintf (e, " ");
1770
1771 if (control->class.named)
1772 ci = NULL;
1773 else
1774 {
1775 for (ci = control_info; ci->name != NULL; ++ci)
1776 if (ci->class == control->class.u.id
1777 && (ci->style == (unsigned long) -1
1778 || ci->style == (control->style & 0xff)))
1779 break;
1780 }
1781
1782 if (ci->name != NULL)
1783 fprintf (e, "%s", ci->name);
1784 else
1785 fprintf (e, "CONTROL");
1786
1787 if (control->text.named || control->text.u.id != 0)
1788 {
1789 fprintf (e, " ");
1790 res_id_print (e, control->text, 1);
1791 fprintf (e, ",");
1792 }
1793
1794 fprintf (e, " %d, ", control->id);
1795
1796 if (ci->name == NULL)
1797 {
1798 res_id_print (e, control->class, 0);
1799 fprintf (e, ", 0x%lx, ", control->style);
1800 }
1801
1802 fprintf (e, "%d, %d", control->x, control->y);
1803
1804 if (control->style != SS_ICON
1805 || control->exstyle != 0
1806 || control->width != 0
1807 || control->height != 0
1808 || control->help != 0)
1809 {
1810 fprintf (e, ", %d, %d", control->width, control->height);
1811
1812 /* FIXME: We don't need to print the style if it is the default.
1813 More importantly, in certain cases we actually need to turn
1814 off parts of the forced style, by using NOT. */
1815 fprintf (e, ", 0x%lx", control->style);
1816
1817 if (control->exstyle != 0 || control->help != 0)
1818 fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
1819 }
1820
1821 fprintf (e, "\n");
1822
1823 if (control->data != NULL)
1824 write_rc_rcdata (e, control->data, 2);
1825 }
1826
1827 /* Write out font directory data. This would normally be built from
1828 the font data. */
1829
1830 static void
1831 write_rc_fontdir (e, fontdir)
1832 FILE *e;
1833 const struct fontdir *fontdir;
1834 {
1835 const struct fontdir *fc;
1836
1837 for (fc = fontdir; fc != NULL; fc = fc->next)
1838 {
1839 fprintf (e, "// Font index: %d\n", fc->index);
1840 write_rc_filedata (e, fc->length, fc->data);
1841 }
1842 }
1843
1844 /* Write out group icon data. This would normally be built from the
1845 icon data. */
1846
1847 static void
1848 write_rc_group_icon (e, group_icon)
1849 FILE *e;
1850 const struct group_icon *group_icon;
1851 {
1852 const struct group_icon *gi;
1853
1854 for (gi = group_icon; gi != NULL; gi = gi->next)
1855 {
1856 fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
1857 gi->width, gi->height, gi->colors, gi->planes, gi->bits);
1858 fprintf (e, "// data bytes: %lu; index: %d\n",
1859 gi->bytes, gi->index);
1860 }
1861 }
1862
1863 /* Write out a menu resource. */
1864
1865 static void
1866 write_rc_menu (e, menuitems, menuex, ind)
1867 FILE *e;
1868 const struct menuitem *menuitems;
1869 int menuex;
1870 int ind;
1871 {
1872 const struct menuitem *mi;
1873
1874 indent (e, ind);
1875 fprintf (e, "BEGIN\n");
1876
1877 for (mi = menuitems; mi != NULL; mi = mi->next)
1878 {
1879 indent (e, ind + 2);
1880
1881 if (mi->popup == NULL)
1882 fprintf (e, "MENUITEM");
1883 else
1884 fprintf (e, "POPUP");
1885
1886 if (! menuex
1887 && mi->popup == NULL
1888 && mi->text == NULL
1889 && mi->type == 0
1890 && mi->id == 0)
1891 {
1892 fprintf (e, " SEPARATOR\n");
1893 continue;
1894 }
1895
1896 if (mi->text == NULL)
1897 fprintf (e, " \"\"");
1898 else
1899 fprintf (e, " \"%s\"", mi->text);
1900
1901 if (! menuex)
1902 {
1903 if (mi->popup == NULL)
1904 fprintf (e, ", %d", mi->id);
1905
1906 if ((mi->type & MENUITEM_CHECKED) != 0)
1907 fprintf (e, ", CHECKED");
1908 if ((mi->type & MENUITEM_GRAYED) != 0)
1909 fprintf (e, ", GRAYED");
1910 if ((mi->type & MENUITEM_HELP) != 0)
1911 fprintf (e, ", HELP");
1912 if ((mi->type & MENUITEM_INACTIVE) != 0)
1913 fprintf (e, ", INACTIVE");
1914 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
1915 fprintf (e, ", MENUBARBREAK");
1916 if ((mi->type & MENUITEM_MENUBREAK) != 0)
1917 fprintf (e, ", MENUBREAK");
1918 }
1919 else
1920 {
1921 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
1922 {
1923 fprintf (e, ", %d", mi->id);
1924 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
1925 {
1926 fprintf (e, ", %lu", mi->type);
1927 if (mi->state != 0 || mi->help != 0)
1928 {
1929 fprintf (e, ", %lu", mi->state);
1930 if (mi->help != 0)
1931 fprintf (e, ", %lu", mi->help);
1932 }
1933 }
1934 }
1935 }
1936
1937 fprintf (e, "\n");
1938
1939 if (mi->popup != NULL)
1940 write_rc_menu (e, mi->popup, menuex, ind + 2);
1941 }
1942
1943 indent (e, ind);
1944 fprintf (e, "END\n");
1945 }
1946
1947 /* Write out an rcdata resource. This is also used for other types of
1948 resources that need to print arbitrary data. */
1949
1950 static void
1951 write_rc_rcdata (e, rcdata, ind)
1952 FILE *e;
1953 const struct rcdata_data *rcdata;
1954 int ind;
1955 {
1956 const struct rcdata_item *ri;
1957
1958 indent (e, ind);
1959 fprintf (e, "BEGIN\n");
1960
1961 for (ri = rcdata->first; ri != NULL; ri = ri->next)
1962 {
1963 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
1964 continue;
1965
1966 indent (e, ind + 2);
1967
1968 switch (ri->type)
1969 {
1970 default:
1971 abort ();
1972
1973 case RCDATA_WORD:
1974 fprintf (e, "%d", ri->u.word);
1975 break;
1976
1977 case RCDATA_DWORD:
1978 fprintf (e, "%luL", ri->u.dword);
1979 break;
1980
1981 case RCDATA_STRING:
1982 fprintf (e, "\"%s\"", ri->u.string);
1983 break;
1984
1985 case RCDATA_WSTRING:
1986 fprintf (e, "L\"");
1987 unicode_print (e, ri->u.wstring, -1);
1988 fprintf (e, "\"");
1989 break;
1990
1991 case RCDATA_BUFFER:
1992 {
1993 unsigned long i;
1994 int first;
1995
1996 /* Assume little endian data. */
1997
1998 first = 1;
1999 for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2000 {
2001 unsigned long l;
2002
2003 l = ((((((ri->u.buffer.data[i + 3] << 8)
2004 | ri->u.buffer.data[i + 2]) << 8)
2005 | ri->u.buffer.data[i + 1]) << 8)
2006 | ri->u.buffer.data[i]);
2007 if (first)
2008 first = 0;
2009 else
2010 {
2011 fprintf (e, ",\n");
2012 indent (e, ind + 2);
2013 }
2014 fprintf (e, "%luL", l);
2015 }
2016
2017 if (i + 1 < ri->u.buffer.length)
2018 {
2019 int i;
2020
2021 i = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2022 if (first)
2023 first = 0;
2024 else
2025 {
2026 fprintf (e, ",\n");
2027 indent (e, ind + 2);
2028 }
2029 fprintf (e, "%d", i);
2030 i += 2;
2031 }
2032
2033 if (i < ri->u.buffer.length)
2034 {
2035 if (first)
2036 first = 0;
2037 else
2038 {
2039 fprintf (e, ",\n");
2040 indent (e, ind + 2);
2041 }
2042 if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2043 && isprint (ri->u.buffer.data[i]))
2044 fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2045 else
2046 fprintf (e, "\"\%03o\"", ri->u.buffer.data[i]);
2047 }
2048
2049 break;
2050 }
2051 }
2052
2053 if (ri->next != NULL)
2054 fprintf (e, ",");
2055 fprintf (e, "\n");
2056 }
2057
2058 indent (e, ind);
2059 fprintf (e, "END\n");
2060 }
2061
2062 /* Write out a stringtable resource. */
2063
2064 static void
2065 write_rc_stringtable (e, name, stringtable)
2066 FILE *e;
2067 const struct res_id *name;
2068 const struct stringtable *stringtable;
2069 {
2070 unsigned long offset;
2071 int i;
2072
2073 if (name != NULL && ! name->named)
2074 offset = name->u.id << 4;
2075 else
2076 {
2077 fprintf (e, "// %s string table name\n",
2078 name == NULL ? "Missing" : "Invalid");
2079 offset = 0;
2080 }
2081
2082 fprintf (e, "BEGIN\n");
2083
2084 for (i = 0; i < 16; i++)
2085 {
2086 if (stringtable->strings[i].length != 0)
2087 {
2088 fprintf (e, " %lu, \"", offset + i);
2089 unicode_print (e, stringtable->strings[i].string,
2090 stringtable->strings[i].length);
2091 fprintf (e, "\"\n");
2092 }
2093 }
2094
2095 fprintf (e, "END\n");
2096 }
2097
2098 /* Write out a versioninfo resource. */
2099
2100 static void
2101 write_rc_versioninfo (e, versioninfo)
2102 FILE *e;
2103 const struct versioninfo *versioninfo;
2104 {
2105 const struct fixed_versioninfo *f;
2106 const struct ver_info *vi;
2107
2108 f = versioninfo->fixed;
2109 if (f->file_version_ms != 0 || f->file_version_ls != 0)
2110 fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2111 (f->file_version_ms >> 16) & 0xffff,
2112 f->file_version_ms & 0xffff,
2113 (f->file_version_ls >> 16) & 0xffff,
2114 f->file_version_ls & 0xffff);
2115 if (f->product_version_ms != 0 || f->product_version_ls != 0)
2116 fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2117 (f->product_version_ms >> 16) & 0xffff,
2118 f->product_version_ms & 0xffff,
2119 (f->product_version_ls >> 16) & 0xffff,
2120 f->product_version_ls & 0xffff);
2121 if (f->file_flags_mask != 0)
2122 fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2123 if (f->file_flags != 0)
2124 fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2125 if (f->file_os != 0)
2126 fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2127 if (f->file_type != 0)
2128 fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2129 if (f->file_subtype != 0)
2130 fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2131 if (f->file_date_ms != 0 || f->file_date_ls != 0)
2132 fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2133
2134 fprintf (e, "BEGIN\n");
2135
2136 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2137 {
2138 switch (vi->type)
2139 {
2140 case VERINFO_STRING:
2141 {
2142 const struct ver_stringinfo *vs;
2143
2144 fprintf (e, " BLOCK \"StringFileInfo\"\n");
2145 fprintf (e, " BEGIN\n");
2146 fprintf (e, " BLOCK \"");
2147 unicode_print (e, vi->u.string.language, -1);
2148 fprintf (e, "\"\n");
2149 fprintf (e, " BEGIN\n");
2150
2151 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2152 {
2153 fprintf (e, " VALUE \"");
2154 unicode_print (e, vs->key, -1);
2155 fprintf (e, "\", \"");
2156 unicode_print (e, vs->value, -1);
2157 fprintf (e, "\"\n");
2158 }
2159
2160 fprintf (e, " END\n");
2161 fprintf (e, " END\n");
2162 break;
2163 }
2164
2165 case VERINFO_VAR:
2166 {
2167 const struct ver_varinfo *vv;
2168
2169 fprintf (e, " BLOCK \"VarFileInfo\"\n");
2170 fprintf (e, " BEGIN\n");
2171 fprintf (e, " VALUE \"");
2172 unicode_print (e, vi->u.var.key, -1);
2173 fprintf (e, "\"");
2174
2175 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2176 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2177 vv->charset);
2178
2179 fprintf (e, "\n END\n");
2180
2181 break;
2182 }
2183 }
2184 }
2185
2186 fprintf (e, "END\n");
2187 }
2188
2189 /* Write out data which would normally be read from a file. */
2190
2191 static void
2192 write_rc_filedata (e, length, data)
2193 FILE *e;
2194 unsigned long length;
2195 const unsigned char *data;
2196 {
2197 unsigned long i;
2198
2199 for (i = 0; i + 15 < length; i += 16)
2200 {
2201 fprintf (e, "// %4lx: ", i);
2202 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2203 data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2204 data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2205 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2206 data[i + 8], data[i + 9], data[i + 10], data[i + 11],
2207 data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2208 }
2209
2210 if (i < length)
2211 {
2212 fprintf (e, "// %4lx:", i);
2213 while (i < length)
2214 {
2215 fprintf (e, " %02x", data[i]);
2216 ++i;
2217 }
2218 fprintf (e, "\n");
2219 }
2220 }
This page took 0.0952769999999999 seconds and 5 git commands to generate.