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