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