Coverage Report

Created: 2023-06-29 07:03

/src/binutils-gdb/binutils/resrc.c
Line
Count
Source (jump to first uncovered line)
1
/* resrc.c -- read and write Windows rc files.
2
   Copyright (C) 1997-2023 Free Software Foundation, Inc.
3
   Written by Ian Lance Taylor, Cygnus Support.
4
   Rewritten by Kai Tietz, Onevision.
5
6
   This file is part of GNU Binutils.
7
8
   This program is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3 of the License, or
11
   (at your option) any later version.
12
13
   This program is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
18
   You should have received a copy of the GNU General Public License
19
   along with this program; if not, write to the Free Software
20
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21
   02110-1301, USA.  */
22
23
/* This file contains functions that read and write Windows rc files.
24
   These are text files that represent resources.  */
25
26
#include "sysdep.h"
27
#include "bfd.h"
28
#include "bucomm.h"
29
#include "libiberty.h"
30
#include "safe-ctype.h"
31
#include "windres.h"
32
33
#include <assert.h>
34
35
#ifdef HAVE_SYS_WAIT_H
36
#include <sys/wait.h>
37
#else /* ! HAVE_SYS_WAIT_H */
38
#if ! defined (_WIN32) || defined (__CYGWIN__)
39
#ifndef WIFEXITED
40
#define WIFEXITED(w)  (((w)&0377) == 0)
41
#endif
42
#ifndef WIFSIGNALED
43
#define WIFSIGNALED(w)  (((w)&0377) != 0177 && ((w)&~0377) == 0)
44
#endif
45
#ifndef WTERMSIG
46
#define WTERMSIG(w) ((w) & 0177)
47
#endif
48
#ifndef WEXITSTATUS
49
#define WEXITSTATUS(w)  (((w) >> 8) & 0377)
50
#endif
51
#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
52
#ifndef WIFEXITED
53
#define WIFEXITED(w)  (((w) & 0xff) == 0)
54
#endif
55
#ifndef WIFSIGNALED
56
#define WIFSIGNALED(w)  (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
57
#endif
58
#ifndef WTERMSIG
59
#define WTERMSIG(w) ((w) & 0x7f)
60
#endif
61
#ifndef WEXITSTATUS
62
#define WEXITSTATUS(w)  (((w) & 0xff00) >> 8)
63
#endif
64
#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
65
#endif /* ! HAVE_SYS_WAIT_H */
66
67
#ifndef STDOUT_FILENO
68
#define STDOUT_FILENO 1
69
#endif
70
71
#if defined (_WIN32) && ! defined (__CYGWIN__)
72
#define popen _popen
73
#define pclose _pclose
74
#endif
75
76
/* The default preprocessor.  */
77
78
0
#define DEFAULT_PREPROCESSOR_CMD "gcc"
79
0
#define DEFAULT_PREPROCESSOR_ARGS "-E -xc -DRC_INVOKED"
80
81
/* We read the directory entries in a cursor or icon file into
82
   instances of this structure.  */
83
84
struct icondir
85
{
86
  /* Width of image.  */
87
  bfd_byte width;
88
  /* Height of image.  */
89
  bfd_byte height;
90
  /* Number of colors in image.  */
91
  bfd_byte colorcount;
92
  union
93
  {
94
    struct
95
    {
96
      /* Color planes.  */
97
      unsigned short planes;
98
      /* Bits per pixel.  */
99
      unsigned short bits;
100
    } icon;
101
    struct
102
    {
103
      /* X coordinate of hotspot.  */
104
      unsigned short xhotspot;
105
      /* Y coordinate of hotspot.  */
106
      unsigned short yhotspot;
107
    } cursor;
108
  } u;
109
  /* Bytes in image.  */
110
  unsigned long bytes;
111
  /* File offset of image.  */
112
  unsigned long offset;
113
};
114
115
/* The name of the rc file we are reading.  */
116
117
char *rc_filename;
118
119
/* The line number in the rc file.  */
120
121
int rc_lineno;
122
123
/* The pipe we are reading from, so that we can close it if we exit.  */
124
125
FILE *cpp_pipe;
126
127
/* The temporary file used if we're not using popen, so we can delete it
128
   if we exit.  */
129
130
static char *cpp_temp_file;
131
132
/* Input stream is either a file or a pipe.  */
133
134
static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
135
136
/* As we read the rc file, we attach information to this structure.  */
137
138
static rc_res_directory *resources;
139
140
/* The number of cursor resources we have written out.  */
141
142
static int cursors;
143
144
/* The number of font resources we have written out.  */
145
146
static int fonts;
147
148
/* Font directory information.  */
149
150
rc_fontdir *fontdirs;
151
152
/* Resource info to use for fontdirs.  */
153
154
rc_res_res_info fontdirs_resinfo;
155
156
/* The number of icon resources we have written out.  */
157
158
static int icons;
159
160
/* The windres target bfd .  */
161
162
static windres_bfd wrtarget =
163
{
164
  (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
165
};
166
167
/* Local functions for rcdata based resource definitions.  */
168
169
static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
170
        rc_rcdata_item *);
171
static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
172
        rc_rcdata_item *);
173
static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
174
          rc_rcdata_item *);
175
static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
176
          rc_rcdata_item *);
177
static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
178
           rc_rcdata_item *);
179
static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
180
          rc_rcdata_item *);
181
static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
182
static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
183
184
static int run_cmd (char *, const char *);
185
static FILE *open_input_stream (char *);
186
static FILE *look_for_default
187
  (char *, const char *, int, const char *, const char *);
188
static void close_input_stream (void);
189
static void unexpected_eof (const char *);
190
static int get_word (FILE *, const char *);
191
static unsigned long get_long (FILE *, const char *);
192
static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
193
static void define_fontdirs (void);
194

195
/* Run `cmd' and redirect the output to `redir'.  */
196
197
static int
198
run_cmd (char *cmd, const char *redir)
199
0
{
200
0
  char *s;
201
0
  int pid, wait_status, retcode;
202
0
  int i;
203
0
  const char **argv;
204
0
  char *errmsg_fmt = NULL, *errmsg_arg = NULL;
205
0
  char *temp_base = make_temp_file (NULL);
206
0
  int in_quote;
207
0
  char sep;
208
0
  int redir_handle = -1;
209
0
  int stdout_save = -1;
210
211
  /* Count the args.  */
212
0
  i = 0;
213
214
0
  for (s = cmd; *s; s++)
215
0
    if (*s == ' ')
216
0
      i++;
217
218
0
  i++;
219
0
  argv = xmalloc (sizeof (char *) * (i + 3));
220
0
  i = 0;
221
0
  s = cmd;
222
223
0
  while (1)
224
0
    {
225
0
      while (*s == ' ' && *s != 0)
226
0
  s++;
227
228
0
      if (*s == 0)
229
0
  break;
230
231
0
      in_quote = (*s == '\'' || *s == '"');
232
0
      sep = (in_quote) ? *s++ : ' ';
233
0
      argv[i++] = s;
234
235
0
      while (*s != sep && *s != 0)
236
0
  s++;
237
238
0
      if (*s == 0)
239
0
  break;
240
241
0
      *s++ = 0;
242
243
0
      if (in_quote)
244
0
  s++;
245
0
    }
246
0
  argv[i++] = NULL;
247
248
  /* Setup the redirection.  We can't use the usual fork/exec and redirect
249
     since we may be running on non-POSIX Windows host.  */
250
251
0
  fflush (stdout);
252
0
  fflush (stderr);
253
254
  /* Open temporary output file.  */
255
0
  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
256
0
  if (redir_handle == -1)
257
0
    fatal (_("can't open temporary file `%s': %s"), redir,
258
0
     strerror (errno));
259
260
  /* Duplicate the stdout file handle so it can be restored later.  */
261
0
  stdout_save = dup (STDOUT_FILENO);
262
0
  if (stdout_save == -1)
263
0
    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
264
265
  /* Redirect stdout to our output file.  */
266
0
  dup2 (redir_handle, STDOUT_FILENO);
267
268
0
  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
269
0
      &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
270
0
  free (argv);
271
272
  /* Restore stdout to its previous setting.  */
273
0
  dup2 (stdout_save, STDOUT_FILENO);
274
275
  /* Close response file.  */
276
0
  close (redir_handle);
277
278
0
  if (pid == -1)
279
0
    {
280
0
      fatal ("%s %s: %s", errmsg_fmt, errmsg_arg, strerror (errno));
281
0
      return 1;
282
0
    }
283
284
0
  retcode = 0;
285
0
  pid = pwait (pid, &wait_status, 0);
286
287
0
  if (pid == -1)
288
0
    {
289
0
      fatal (_("wait: %s"), strerror (errno));
290
0
      retcode = 1;
291
0
    }
292
0
  else if (WIFSIGNALED (wait_status))
293
0
    {
294
0
      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
295
0
      retcode = 1;
296
0
    }
297
0
  else if (WIFEXITED (wait_status))
298
0
    {
299
0
      if (WEXITSTATUS (wait_status) != 0)
300
0
  {
301
0
    fatal (_("%s exited with status %d"), cmd,
302
0
           WEXITSTATUS (wait_status));
303
0
    retcode = 1;
304
0
  }
305
0
    }
306
0
  else
307
0
    retcode = 1;
308
309
0
  return retcode;
310
0
}
311
312
static FILE *
313
open_input_stream (char *cmd)
314
0
{
315
0
  if (istream_type == ISTREAM_FILE)
316
0
    {
317
0
      char *fileprefix;
318
319
0
      fileprefix = make_temp_file (NULL);
320
0
      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
321
0
      sprintf (cpp_temp_file, "%s.irc", fileprefix);
322
0
      free (fileprefix);
323
324
0
      if (run_cmd (cmd, cpp_temp_file))
325
0
  fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
326
327
0
      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);
328
0
      if (cpp_pipe == NULL)
329
0
  fatal (_("can't open temporary file `%s': %s"),
330
0
         cpp_temp_file, strerror (errno));
331
332
0
      if (verbose)
333
0
  fprintf (stderr,
334
0
           _("Using temporary file `%s' to read preprocessor output\n"),
335
0
     cpp_temp_file);
336
0
    }
337
0
  else
338
0
    {
339
0
      cpp_pipe = popen (cmd, FOPEN_RT);
340
0
      if (cpp_pipe == NULL)
341
0
  fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
342
0
      if (verbose)
343
0
  fprintf (stderr, _("Using popen to read preprocessor output\n"));
344
0
    }
345
346
0
  xatexit (close_input_stream);
347
0
  return cpp_pipe;
348
0
}
349
350
/* Determine if FILENAME contains special characters that
351
   can cause problems unless the entire filename is quoted.  */
352
353
static int
354
filename_need_quotes (const char *filename)
355
0
{
356
0
  if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
357
0
    return 0;
358
359
0
  while (*filename != 0)
360
0
    {
361
0
      switch (*filename)
362
0
        {
363
0
        case '&':
364
0
        case ' ':
365
0
        case '<':
366
0
        case '>':
367
0
        case '|':
368
0
        case '%':
369
0
          return 1;
370
0
        }
371
0
      ++filename;
372
0
    }
373
0
  return 0;
374
0
}
375
376
/* Look for the preprocessor program.  */
377
378
static FILE *
379
look_for_default (char *cmd, const char *prefix, int end_prefix,
380
      const char *preprocargs, const char *filename)
381
0
{
382
0
  int found;
383
0
  struct stat s;
384
0
  const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
385
386
0
  strcpy (cmd, prefix);
387
388
0
  sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR_CMD);
389
390
0
  if (
391
#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
392
      strchr (cmd, '\\') ||
393
#endif
394
0
      strchr (cmd, '/'))
395
0
    {
396
0
      found = (stat (cmd, &s) == 0
397
#ifdef HAVE_EXECUTABLE_SUFFIX
398
         || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
399
#endif
400
0
         );
401
402
0
      if (! found)
403
0
  {
404
0
    if (verbose)
405
0
      fprintf (stderr, _("Tried `%s'\n"), cmd);
406
0
    return NULL;
407
0
  }
408
0
    }
409
410
0
  if (filename_need_quotes (cmd))
411
0
    {
412
0
      char *cmd_copy = xmalloc (strlen (cmd));
413
0
      strcpy (cmd_copy, cmd);
414
0
      sprintf (cmd, "\"%s\"", cmd_copy);
415
0
      free (cmd_copy);
416
0
    }
417
418
0
  sprintf (cmd + strlen (cmd), " %s %s %s%s%s",
419
0
     DEFAULT_PREPROCESSOR_ARGS, preprocargs, fnquotes, filename, fnquotes);
420
421
0
  if (verbose)
422
0
    fprintf (stderr, _("Using `%s'\n"), cmd);
423
424
0
  cpp_pipe = open_input_stream (cmd);
425
0
  return cpp_pipe;
426
0
}
427
428
/* Read an rc file.  */
429
430
rc_res_directory *
431
read_rc_file (const char *filename, const char *preprocessor,
432
        const char *preprocargs, int language, int use_temp_file)
433
0
{
434
0
  char *cmd;
435
0
  const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
436
437
0
  if (filename == NULL)
438
0
    filename = "-";
439
  /* Setup the default resource import path taken from input file.  */
440
0
  else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
441
0
    {
442
0
      char *edit, *dir;
443
444
0
      if (filename[0] == '/'
445
0
    || filename[0] == '\\'
446
0
    || filename[1] == ':')
447
        /* Absolute path.  */
448
0
  edit = dir = xstrdup (filename);
449
0
      else
450
0
  {
451
    /* Relative path.  */
452
0
    edit = dir = xmalloc (strlen (filename) + 3);
453
0
    sprintf (dir, "./%s", filename);
454
0
  }
455
456
      /* Walk dir backwards stopping at the first directory separator.  */
457
0
      edit += strlen (dir);
458
0
      while (edit > dir && (edit[-1] != '\\' && edit[-1] != '/'))
459
0
  {
460
0
    --edit;
461
0
    edit[0] = 0;
462
0
  }
463
464
      /* Cut off trailing slash.  */
465
0
      --edit;
466
0
      edit[0] = 0;
467
468
      /* Convert all back slashes to forward slashes.  */
469
0
      while ((edit = strchr (dir, '\\')) != NULL)
470
0
  *edit = '/';
471
472
0
      windres_add_include_dir (dir);
473
0
    }
474
475
0
  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
476
477
0
  if (preprocargs == NULL)
478
0
    preprocargs = "";
479
480
0
  if (preprocessor)
481
0
    {
482
0
      cmd = xmalloc (strlen (preprocessor)
483
0
         + strlen (preprocargs)
484
0
         + strlen (filename)
485
0
         + strlen (fnquotes) * 2
486
0
         + 10);
487
0
      sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
488
0
         fnquotes, filename, fnquotes);
489
490
0
      cpp_pipe = open_input_stream (cmd);
491
0
    }
492
0
  else
493
0
    {
494
0
      char *dash, *slash, *cp;
495
496
0
      cmd = xmalloc (strlen (program_name)
497
0
         + strlen (DEFAULT_PREPROCESSOR_CMD)
498
0
         + strlen (DEFAULT_PREPROCESSOR_ARGS)
499
0
         + strlen (preprocargs)
500
0
         + strlen (filename)
501
0
         + strlen (fnquotes) * 2
502
#ifdef HAVE_EXECUTABLE_SUFFIX
503
         + strlen (EXECUTABLE_SUFFIX)
504
#endif
505
0
         + 10);
506
507
508
0
      dash = slash = 0;
509
0
      for (cp = program_name; *cp; cp++)
510
0
  {
511
0
    if (*cp == '-')
512
0
      dash = cp;
513
0
    if (
514
#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
515
        *cp == ':' || *cp == '\\' ||
516
#endif
517
0
        *cp == '/')
518
0
      {
519
0
        slash = cp;
520
0
        dash = 0;
521
0
      }
522
0
  }
523
524
0
      cpp_pipe = 0;
525
526
0
      if (dash)
527
0
  {
528
    /* First, try looking for a prefixed gcc in the windres
529
       directory, with the same prefix as windres */
530
531
0
    cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
532
0
               preprocargs, filename);
533
0
  }
534
535
0
      if (slash && ! cpp_pipe)
536
0
  {
537
    /* Next, try looking for a gcc in the same directory as
538
             that windres */
539
540
0
    cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
541
0
               preprocargs, filename);
542
0
  }
543
544
0
      if (! cpp_pipe)
545
0
  {
546
    /* Sigh, try the default */
547
548
0
    cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
549
0
  }
550
551
0
    }
552
553
0
  free (cmd);
554
555
0
  rc_filename = xstrdup (filename);
556
0
  rc_lineno = 1;
557
0
  if (language != -1)
558
0
    rcparse_set_language (language);
559
0
  yyparse ();
560
0
  rcparse_discard_strings ();
561
562
0
  close_input_stream ();
563
564
0
  if (fontdirs != NULL)
565
0
    define_fontdirs ();
566
567
0
  free (rc_filename);
568
0
  rc_filename = NULL;
569
570
0
  return resources;
571
0
}
572
573
/* Close the input stream if it is open.  */
574
575
static void
576
close_input_stream (void)
577
0
{
578
0
  if (istream_type == ISTREAM_FILE)
579
0
    {
580
0
      if (cpp_pipe != NULL)
581
0
  fclose (cpp_pipe);
582
583
0
      if (cpp_temp_file != NULL)
584
0
  {
585
0
    int errno_save = errno;
586
587
0
    unlink (cpp_temp_file);
588
0
    errno = errno_save;
589
0
    free (cpp_temp_file);
590
0
  }
591
0
    }
592
0
  else
593
0
    {
594
0
      if (cpp_pipe != NULL)
595
0
        {
596
0
    int err;
597
0
    err = pclose (cpp_pipe);
598
    /* We are reading from a pipe, therefore we don't
599
             know if cpp failed or succeeded until pclose.  */
600
0
    if (err != 0 || errno == ECHILD)
601
0
      {
602
        /* Since this is also run via xatexit, safeguard.  */
603
0
        cpp_pipe = NULL;
604
0
        cpp_temp_file = NULL;
605
0
        fatal (_("preprocessing failed."));
606
0
      }
607
0
        }
608
0
    }
609
610
  /* Since this is also run via xatexit, safeguard.  */
611
0
  cpp_pipe = NULL;
612
0
  cpp_temp_file = NULL;
613
0
}
614
615
/* Report an error while reading an rc file.  */
616
617
void
618
yyerror (const char *msg)
619
0
{
620
0
  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
621
0
}
622
623
/* Issue a warning while reading an rc file.  */
624
625
void
626
rcparse_warning (const char *msg)
627
0
{
628
0
  fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
629
0
}
630
631
/* Die if we get an unexpected end of file.  */
632
633
static void
634
unexpected_eof (const char *msg)
635
0
{
636
0
  fatal (_("%s: unexpected EOF"), msg);
637
0
}
638
639
/* Read a 16 bit word from a file.  The data is assumed to be little
640
   endian.  */
641
642
static int
643
get_word (FILE *e, const char *msg)
644
0
{
645
0
  int b1, b2;
646
647
0
  b1 = getc (e);
648
0
  b2 = getc (e);
649
0
  if (feof (e))
650
0
    unexpected_eof (msg);
651
0
  return ((b2 & 0xff) << 8) | (b1 & 0xff);
652
0
}
653
654
/* Read a 32 bit word from a file.  The data is assumed to be little
655
   endian.  */
656
657
static unsigned long
658
get_long (FILE *e, const char *msg)
659
0
{
660
0
  int b1, b2, b3, b4;
661
662
0
  b1 = getc (e);
663
0
  b2 = getc (e);
664
0
  b3 = getc (e);
665
0
  b4 = getc (e);
666
0
  if (feof (e))
667
0
    unexpected_eof (msg);
668
0
  return (((((((b4 & 0xff) << 8)
669
0
        | (b3 & 0xff)) << 8)
670
0
      | (b2 & 0xff)) << 8)
671
0
    | (b1 & 0xff));
672
0
}
673
674
/* Read data from a file.  This is a wrapper to do error checking.  */
675
676
static void
677
get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
678
0
{
679
0
  rc_uint_type got; /* $$$d */
680
681
0
  got = (rc_uint_type) fread (p, 1, c, e);
682
0
  if (got == c)
683
0
    return;
684
685
0
  fatal (_("%s: read of %lu returned %lu"),
686
0
   msg, (unsigned long) c, (unsigned long) got);
687
0
}
688

689
/* Define an accelerator resource.  */
690
691
void
692
define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
693
        rc_accelerator *data)
694
0
{
695
0
  rc_res_resource *r;
696
697
0
  r = define_standard_resource (&resources, RT_ACCELERATOR, id,
698
0
        resinfo->language, 0);
699
0
  r->type = RES_TYPE_ACCELERATOR;
700
0
  r->u.acc = data;
701
0
  r->res_info = *resinfo;
702
0
}
703
704
/* Define a bitmap resource.  Bitmap data is stored in a file.  The
705
   first 14 bytes of the file are a standard header, which is not
706
   included in the resource data.  */
707
708
0
#define BITMAP_SKIP (14)
709
710
void
711
define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
712
         const char *filename)
713
0
{
714
0
  FILE *e;
715
0
  char *real_filename;
716
0
  struct stat s;
717
0
  bfd_byte *data;
718
0
  rc_uint_type i;
719
0
  rc_res_resource *r;
720
721
0
  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
722
723
0
  if (stat (real_filename, &s) < 0)
724
0
    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
725
0
     strerror (errno));
726
727
0
  data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
728
729
0
  for (i = 0; i < BITMAP_SKIP; i++)
730
0
    getc (e);
731
732
0
  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
733
734
0
  fclose (e);
735
0
  free (real_filename);
736
737
0
  r = define_standard_resource (&resources, RT_BITMAP, id,
738
0
        resinfo->language, 0);
739
740
0
  r->type = RES_TYPE_BITMAP;
741
0
  r->u.data.length = s.st_size - BITMAP_SKIP;
742
0
  r->u.data.data = data;
743
0
  r->res_info = *resinfo;
744
0
}
745
746
/* Define a cursor resource.  A cursor file may contain a set of
747
   bitmaps, each representing the same cursor at various different
748
   resolutions.  They each get written out with a different ID.  The
749
   real cursor resource is then a group resource which can be used to
750
   select one of the actual cursors.  */
751
752
void
753
define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
754
         const char *filename)
755
0
{
756
0
  FILE *e;
757
0
  char *real_filename;
758
0
  int type, count, i;
759
0
  struct icondir *icondirs;
760
0
  int first_cursor;
761
0
  rc_res_resource *r;
762
0
  rc_group_cursor *first, **pp;
763
764
0
  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
765
766
  /* A cursor file is basically an icon file.  The start of the file
767
     is a three word structure.  The first word is ignored.  The
768
     second word is the type of data.  The third word is the number of
769
     entries.  */
770
771
0
  get_word (e, real_filename);
772
0
  type = get_word (e, real_filename);
773
0
  count = get_word (e, real_filename);
774
0
  if (type != 2)
775
0
    fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
776
777
  /* Read in the icon directory entries.  */
778
779
0
  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
780
781
0
  for (i = 0; i < count; i++)
782
0
    {
783
0
      icondirs[i].width = getc (e);
784
0
      icondirs[i].height = getc (e);
785
0
      icondirs[i].colorcount = getc (e);
786
0
      getc (e);
787
0
      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
788
0
      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
789
0
      icondirs[i].bytes = get_long (e, real_filename);
790
0
      icondirs[i].offset = get_long (e, real_filename);
791
792
0
      if (feof (e))
793
0
  unexpected_eof (real_filename);
794
0
    }
795
796
  /* Define each cursor as a unique resource.  */
797
798
0
  first_cursor = cursors;
799
800
0
  for (i = 0; i < count; i++)
801
0
    {
802
0
      bfd_byte *data;
803
0
      rc_res_id name;
804
0
      rc_cursor *c;
805
806
0
      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
807
0
  fatal (_("%s: fseek to %lu failed: %s"), real_filename,
808
0
         icondirs[i].offset, strerror (errno));
809
810
0
      data = (bfd_byte *) res_alloc (icondirs[i].bytes);
811
812
0
      get_data (e, data, icondirs[i].bytes, real_filename);
813
814
0
      c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
815
0
      c->xhotspot = icondirs[i].u.cursor.xhotspot;
816
0
      c->yhotspot = icondirs[i].u.cursor.yhotspot;
817
0
      c->length = icondirs[i].bytes;
818
0
      c->data = data;
819
820
0
      ++cursors;
821
822
0
      name.named = 0;
823
0
      name.u.id = cursors;
824
825
0
      r = define_standard_resource (&resources, RT_CURSOR, name,
826
0
            resinfo->language, 0);
827
0
      r->type = RES_TYPE_CURSOR;
828
0
      r->u.cursor = c;
829
0
      r->res_info = *resinfo;
830
0
    }
831
832
0
  fclose (e);
833
0
  free (real_filename);
834
835
  /* Define a cursor group resource.  */
836
837
0
  first = NULL;
838
0
  pp = &first;
839
0
  for (i = 0; i < count; i++)
840
0
    {
841
0
      rc_group_cursor *cg;
842
843
0
      cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
844
0
      cg->next = NULL;
845
0
      cg->width = icondirs[i].width;
846
0
      cg->height = 2 * icondirs[i].height;
847
848
      /* FIXME: What should these be set to?  */
849
0
      cg->planes = 1;
850
0
      cg->bits = 1;
851
852
0
      cg->bytes = icondirs[i].bytes + 4;
853
0
      cg->index = first_cursor + i + 1;
854
855
0
      *pp = cg;
856
0
      pp = &(*pp)->next;
857
0
    }
858
859
0
  free (icondirs);
860
861
0
  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
862
0
        resinfo->language, 0);
863
0
  r->type = RES_TYPE_GROUP_CURSOR;
864
0
  r->u.group_cursor = first;
865
0
  r->res_info = *resinfo;
866
0
}
867
868
/* Define a dialog resource.  */
869
870
void
871
define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
872
         const rc_dialog *dialog)
873
0
{
874
0
  rc_dialog *copy;
875
0
  rc_res_resource *r;
876
877
0
  copy = (rc_dialog *) res_alloc (sizeof *copy);
878
0
  *copy = *dialog;
879
880
0
  r = define_standard_resource (&resources, RT_DIALOG, id,
881
0
        resinfo->language, 0);
882
0
  r->type = RES_TYPE_DIALOG;
883
0
  r->u.dialog = copy;
884
0
  r->res_info = *resinfo;
885
0
}
886
887
/* Define a dialog control.  This does not define a resource, but
888
   merely allocates and fills in a structure.  */
889
890
rc_dialog_control *
891
define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
892
    rc_uint_type y, rc_uint_type width, rc_uint_type height,
893
    const rc_res_id class, rc_uint_type style,
894
    rc_uint_type exstyle)
895
0
{
896
0
  rc_dialog_control *n;
897
898
0
  n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
899
0
  n->next = NULL;
900
0
  n->id = id;
901
0
  n->style = style;
902
0
  n->exstyle = exstyle;
903
0
  n->x = x;
904
0
  n->y = y;
905
0
  n->width = width;
906
0
  n->height = height;
907
0
  n->class = class;
908
0
  n->text = iid;
909
0
  n->data = NULL;
910
0
  n->help = 0;
911
912
0
  return n;
913
0
}
914
915
rc_dialog_control *
916
define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
917
         rc_uint_type y, rc_uint_type style,
918
         rc_uint_type exstyle, rc_uint_type help,
919
         rc_rcdata_item *data, rc_dialog_ex *ex)
920
0
{
921
0
  rc_dialog_control *n;
922
0
  rc_res_id tid;
923
0
  rc_res_id cid;
924
925
0
  if (style == 0)
926
0
    style = SS_ICON | WS_CHILD | WS_VISIBLE;
927
0
  res_string_to_id (&tid, "");
928
0
  cid.named = 0;
929
0
  cid.u.id = CTL_STATIC;
930
0
  n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
931
0
  n->text = iid;
932
0
  if (help && ! ex)
933
0
    rcparse_warning (_("help ID requires DIALOGEX"));
934
0
  if (data && ! ex)
935
0
    rcparse_warning (_("control data requires DIALOGEX"));
936
0
  n->help = help;
937
0
  n->data = data;
938
939
0
  return n;
940
0
}
941
942
/* Define a font resource.  */
943
944
void
945
define_font (rc_res_id id, const rc_res_res_info *resinfo,
946
       const char *filename)
947
0
{
948
0
  FILE *e;
949
0
  char *real_filename;
950
0
  struct stat s;
951
0
  bfd_byte *data;
952
0
  rc_res_resource *r;
953
0
  long offset;
954
0
  long fontdatalength;
955
0
  bfd_byte *fontdata;
956
0
  rc_fontdir *fd;
957
0
  const char *device, *face;
958
0
  rc_fontdir **pp;
959
960
0
  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
961
962
0
  if (stat (real_filename, &s) < 0)
963
0
    fatal (_("stat failed on font file `%s': %s"), real_filename,
964
0
     strerror (errno));
965
966
0
  data = (bfd_byte *) res_alloc (s.st_size);
967
968
0
  get_data (e, data, s.st_size, real_filename);
969
970
0
  fclose (e);
971
0
  free (real_filename);
972
973
0
  r = define_standard_resource (&resources, RT_FONT, id,
974
0
        resinfo->language, 0);
975
976
0
  r->type = RES_TYPE_FONT;
977
0
  r->u.data.length = s.st_size;
978
0
  r->u.data.data = data;
979
0
  r->res_info = *resinfo;
980
981
  /* For each font resource, we must add an entry in the FONTDIR
982
     resource.  The FONTDIR resource includes some strings in the font
983
     file.  To find them, we have to do some magic on the data we have
984
     read.  */
985
986
0
  offset = ((((((data[47] << 8)
987
0
    | data[46]) << 8)
988
0
        | data[45]) << 8)
989
0
      | data[44]);
990
0
  if (offset > 0 && offset < s.st_size)
991
0
    device = (char *) data + offset;
992
0
  else
993
0
    device = "";
994
995
0
  offset = ((((((data[51] << 8)
996
0
    | data[50]) << 8)
997
0
        | data[49]) << 8)
998
0
      | data[48]);
999
0
  if (offset > 0 && offset < s.st_size)
1000
0
    face = (char *) data + offset;
1001
0
  else
1002
0
    face = "";
1003
1004
0
  ++fonts;
1005
1006
0
  fontdatalength = 58 + strlen (device) + strlen (face);
1007
0
  fontdata = (bfd_byte *) res_alloc (fontdatalength);
1008
0
  memcpy (fontdata, data, 56);
1009
0
  strcpy ((char *) fontdata + 56, device);
1010
0
  strcpy ((char *) fontdata + 57 + strlen (device), face);
1011
1012
0
  fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1013
0
  fd->next = NULL;
1014
0
  fd->index = fonts;
1015
0
  fd->length = fontdatalength;
1016
0
  fd->data = fontdata;
1017
1018
0
  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
1019
0
    ;
1020
0
  *pp = fd;
1021
1022
  /* For the single fontdirs resource, we always use the resource
1023
     information of the last font.  I don't know what else to do.  */
1024
0
  fontdirs_resinfo = *resinfo;
1025
0
}
1026
1027
static void
1028
define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1029
        rc_rcdata_item *data)
1030
0
{
1031
0
  rc_res_resource *r;
1032
0
  rc_uint_type len_data;
1033
0
  bfd_byte *pb_data;
1034
1035
0
  r = define_standard_resource (&resources, RT_FONT, id,
1036
0
        resinfo->language, 0);
1037
1038
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1039
1040
0
  r->type = RES_TYPE_FONT;
1041
0
  r->u.data.length = len_data;
1042
0
  r->u.data.data = pb_data;
1043
0
  r->res_info = *resinfo;
1044
0
}
1045
1046
/* Define the fontdirs resource.  This is called after the entire rc
1047
   file has been parsed, if any font resources were seen.  */
1048
1049
static void
1050
define_fontdirs (void)
1051
0
{
1052
0
  rc_res_resource *r;
1053
0
  rc_res_id id;
1054
1055
0
  id.named = 0;
1056
0
  id.u.id = 1;
1057
1058
0
  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1059
1060
0
  r->type = RES_TYPE_FONTDIR;
1061
0
  r->u.fontdir = fontdirs;
1062
0
  r->res_info = fontdirs_resinfo;
1063
0
}
1064
1065
static bfd_byte *
1066
rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
1067
0
{
1068
0
  const rc_rcdata_item *d;
1069
0
  bfd_byte *ret = NULL, *pret;
1070
0
  rc_uint_type len = 0;
1071
1072
0
  for (d = data; d != NULL; d = d->next)
1073
0
    len += rcdata_copy (d, NULL);
1074
0
  if (len != 0)
1075
0
    {
1076
0
      ret = pret = (bfd_byte *) res_alloc (len);
1077
0
      for (d = data; d != NULL; d = d->next)
1078
0
  pret += rcdata_copy (d, pret);
1079
0
    }
1080
0
  if (plen)
1081
0
    *plen = len;
1082
0
  return ret;
1083
0
}
1084
1085
static void
1086
define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1087
           rc_rcdata_item *data)
1088
0
{
1089
0
  rc_res_resource *r;
1090
0
  rc_fontdir *fd, *fd_first, *fd_cur;
1091
0
  rc_uint_type len_data;
1092
0
  bfd_byte *pb_data;
1093
0
  rc_uint_type c;
1094
1095
0
  fd_cur = fd_first = NULL;
1096
0
  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1097
1098
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1099
1100
0
  if (pb_data)
1101
0
    {
1102
0
      rc_uint_type off = 2;
1103
0
      c = windres_get_16 (&wrtarget, pb_data, len_data);
1104
0
      for (; c > 0; c--)
1105
0
  {
1106
0
    size_t len;
1107
0
    rc_uint_type safe_pos = off;
1108
0
    const struct bin_fontdir_item *bfi;
1109
1110
0
    bfi = (const struct bin_fontdir_item *) pb_data + off;
1111
0
    fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1112
0
    fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1113
0
    fd->data = pb_data + off;
1114
0
    off += 56;
1115
0
    len = strlen ((char *) bfi->device_name) + 1;
1116
0
    off += (rc_uint_type) len;
1117
0
    off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1118
0
    fd->length = (off - safe_pos);
1119
0
    fd->next = NULL;
1120
0
    if (fd_first == NULL)
1121
0
      fd_first = fd;
1122
0
    else
1123
0
      fd_cur->next = fd;
1124
0
    fd_cur = fd;
1125
0
  }
1126
0
    }
1127
0
  r->type = RES_TYPE_FONTDIR;
1128
0
  r->u.fontdir = fd_first;
1129
0
  r->res_info = *resinfo;
1130
0
}
1131
1132
static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1133
          rc_rcdata_item *data)
1134
0
{
1135
0
  rc_res_resource *r;
1136
0
  rc_uint_type len_data;
1137
0
  bfd_byte *pb_data;
1138
1139
0
  r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1140
1141
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1142
0
  r->type = RES_TYPE_MESSAGETABLE;
1143
0
  r->u.data.length = len_data;
1144
0
  r->u.data.data = pb_data;
1145
0
  r->res_info = *resinfo;
1146
0
}
1147
1148
/* Define an icon resource.  An icon file may contain a set of
1149
   bitmaps, each representing the same icon at various different
1150
   resolutions.  They each get written out with a different ID.  The
1151
   real icon resource is then a group resource which can be used to
1152
   select one of the actual icon bitmaps.  */
1153
1154
void
1155
define_icon (rc_res_id id, const rc_res_res_info *resinfo,
1156
       const char *filename)
1157
0
{
1158
0
  FILE *e;
1159
0
  char *real_filename;
1160
0
  int type, count, i;
1161
0
  struct icondir *icondirs;
1162
0
  int first_icon;
1163
0
  rc_res_resource *r;
1164
0
  rc_group_icon *first, **pp;
1165
1166
0
  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1167
1168
  /* The start of an icon file is a three word structure.  The first
1169
     word is ignored.  The second word is the type of data.  The third
1170
     word is the number of entries.  */
1171
1172
0
  get_word (e, real_filename);
1173
0
  type = get_word (e, real_filename);
1174
0
  count = get_word (e, real_filename);
1175
0
  if (type != 1)
1176
0
    fatal (_("icon file `%s' does not contain icon data"), real_filename);
1177
1178
  /* Read in the icon directory entries.  */
1179
1180
0
  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1181
1182
0
  for (i = 0; i < count; i++)
1183
0
    {
1184
0
      icondirs[i].width = getc (e);
1185
0
      icondirs[i].height = getc (e);
1186
0
      icondirs[i].colorcount = getc (e);
1187
0
      getc (e);
1188
0
      icondirs[i].u.icon.planes = get_word (e, real_filename);
1189
0
      icondirs[i].u.icon.bits = get_word (e, real_filename);
1190
0
      icondirs[i].bytes = get_long (e, real_filename);
1191
0
      icondirs[i].offset = get_long (e, real_filename);
1192
1193
0
      if (feof (e))
1194
0
  unexpected_eof (real_filename);
1195
0
    }
1196
1197
  /* Define each icon as a unique resource.  */
1198
1199
0
  first_icon = icons;
1200
1201
0
  for (i = 0; i < count; i++)
1202
0
    {
1203
0
      bfd_byte *data;
1204
0
      rc_res_id name;
1205
1206
0
      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1207
0
  fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1208
0
         icondirs[i].offset, strerror (errno));
1209
1210
0
      data = (bfd_byte *) res_alloc (icondirs[i].bytes);
1211
1212
0
      get_data (e, data, icondirs[i].bytes, real_filename);
1213
1214
0
      ++icons;
1215
1216
0
      name.named = 0;
1217
0
      name.u.id = icons;
1218
1219
0
      r = define_standard_resource (&resources, RT_ICON, name,
1220
0
            resinfo->language, 0);
1221
0
      r->type = RES_TYPE_ICON;
1222
0
      r->u.data.length = icondirs[i].bytes;
1223
0
      r->u.data.data = data;
1224
0
      r->res_info = *resinfo;
1225
0
    }
1226
1227
0
  fclose (e);
1228
0
  free (real_filename);
1229
1230
  /* Define an icon group resource.  */
1231
1232
0
  first = NULL;
1233
0
  pp = &first;
1234
0
  for (i = 0; i < count; i++)
1235
0
    {
1236
0
      rc_group_icon *cg;
1237
1238
      /* For some reason, at least in some files the planes and bits
1239
         are zero.  We instead set them from the color.  This is
1240
         copied from rcl.  */
1241
1242
0
      cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1243
0
      cg->next = NULL;
1244
0
      cg->width = icondirs[i].width;
1245
0
      cg->height = icondirs[i].height;
1246
0
      cg->colors = icondirs[i].colorcount;
1247
1248
0
      if (icondirs[i].u.icon.planes)
1249
0
  cg->planes = icondirs[i].u.icon.planes;
1250
0
      else
1251
0
  cg->planes = 1;
1252
1253
0
      if (icondirs[i].u.icon.bits)
1254
0
  cg->bits = icondirs[i].u.icon.bits;
1255
0
      else
1256
0
  {
1257
0
    cg->bits = 0;
1258
1259
0
    while ((1L << cg->bits) < cg->colors)
1260
0
      ++cg->bits;
1261
0
  }
1262
1263
0
      cg->bytes = icondirs[i].bytes;
1264
0
      cg->index = first_icon + i + 1;
1265
1266
0
      *pp = cg;
1267
0
      pp = &(*pp)->next;
1268
0
    }
1269
1270
0
  free (icondirs);
1271
1272
0
  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1273
0
        resinfo->language, 0);
1274
0
  r->type = RES_TYPE_GROUP_ICON;
1275
0
  r->u.group_icon = first;
1276
0
  r->res_info = *resinfo;
1277
0
}
1278
1279
static void
1280
define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1281
        rc_rcdata_item *data)
1282
0
{
1283
0
  rc_res_resource *r;
1284
0
  rc_group_icon *cg, *first, *cur;
1285
0
  rc_uint_type len_data;
1286
0
  bfd_byte *pb_data;
1287
1288
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1289
1290
0
  cur = NULL;
1291
0
  first = NULL;
1292
1293
0
  while (len_data >= 6)
1294
0
    {
1295
0
      int c, i;
1296
0
      unsigned short type;
1297
0
      type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1298
0
      if (type != 1)
1299
0
  fatal (_("unexpected group icon type %d"), type);
1300
0
      c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1301
0
      len_data -= 6;
1302
0
      pb_data += 6;
1303
1304
0
      for (i = 0; i < c; i++)
1305
0
  {
1306
0
    if (len_data < 14)
1307
0
      fatal ("too small group icon rcdata");
1308
0
    cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1309
0
    cg->next = NULL;
1310
0
    cg->width = pb_data[0];
1311
0
    cg->height = pb_data[1];
1312
0
    cg->colors = pb_data[2];
1313
0
    cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1314
0
    cg->bits =  windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1315
0
    cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1316
0
    cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1317
0
    if (! first)
1318
0
      first = cg;
1319
0
    else
1320
0
      cur->next = cg;
1321
0
    cur = cg;
1322
0
    pb_data += 14;
1323
0
    len_data -= 14;
1324
0
  }
1325
0
    }
1326
0
  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1327
0
        resinfo->language, 0);
1328
0
  r->type = RES_TYPE_GROUP_ICON;
1329
0
  r->u.group_icon = first;
1330
0
  r->res_info = *resinfo;
1331
0
}
1332
1333
static void
1334
define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1335
          rc_rcdata_item *data)
1336
0
{
1337
0
  rc_res_resource *r;
1338
0
  rc_group_cursor *cg, *first, *cur;
1339
0
  rc_uint_type len_data;
1340
0
  bfd_byte *pb_data;
1341
1342
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1343
1344
0
  first = cur = NULL;
1345
1346
0
  while (len_data >= 6)
1347
0
    {
1348
0
      int c, i;
1349
0
      unsigned short type;
1350
0
      type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1351
0
      if (type != 2)
1352
0
  fatal (_("unexpected group cursor type %d"), type);
1353
0
      c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1354
0
      len_data -= 6;
1355
0
      pb_data += 6;
1356
1357
0
      for (i = 0; i < c; i++)
1358
0
  {
1359
0
    if (len_data < 14)
1360
0
      fatal ("too small group icon rcdata");
1361
0
    cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1362
0
    cg->next = NULL;
1363
0
    cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1364
0
    cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1365
0
    cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1366
0
    cg->bits =  windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1367
0
    cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1368
0
    cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1369
0
    if (! first)
1370
0
      first = cg;
1371
0
    else
1372
0
      cur->next = cg;
1373
0
    cur = cg;
1374
0
    pb_data += 14;
1375
0
    len_data -= 14;
1376
0
  }
1377
0
    }
1378
1379
0
  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1380
0
        resinfo->language, 0);
1381
0
  r->type = RES_TYPE_GROUP_CURSOR;
1382
0
  r->u.group_cursor = first;
1383
0
  r->res_info = *resinfo;
1384
0
}
1385
1386
static void
1387
define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1388
          rc_rcdata_item *data)
1389
0
{
1390
0
  rc_cursor *c;
1391
0
  rc_res_resource *r;
1392
0
  rc_uint_type len_data;
1393
0
  bfd_byte *pb_data;
1394
1395
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1396
1397
0
  c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1398
0
  c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1399
0
  c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1400
0
  c->length = len_data - BIN_CURSOR_SIZE;
1401
0
  c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1402
1403
0
  r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1404
0
  r->type = RES_TYPE_CURSOR;
1405
0
  r->u.cursor = c;
1406
0
  r->res_info = *resinfo;
1407
0
}
1408
1409
static void
1410
define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1411
          rc_rcdata_item *data)
1412
0
{
1413
0
  rc_res_resource *r;
1414
0
  rc_uint_type len_data;
1415
0
  bfd_byte *pb_data;
1416
1417
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1418
1419
0
  r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1420
0
  r->type = RES_TYPE_BITMAP;
1421
0
  r->u.data.length = len_data;
1422
0
  r->u.data.data = pb_data;
1423
0
  r->res_info = *resinfo;
1424
0
}
1425
1426
static void
1427
define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1428
        rc_rcdata_item *data)
1429
0
{
1430
0
  rc_res_resource *r;
1431
0
  rc_uint_type len_data;
1432
0
  bfd_byte *pb_data;
1433
1434
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1435
1436
0
  r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1437
0
  r->type = RES_TYPE_ICON;
1438
0
  r->u.data.length = len_data;
1439
0
  r->u.data.data = pb_data;
1440
0
  r->res_info = *resinfo;
1441
0
}
1442
1443
/* Define a menu resource.  */
1444
1445
void
1446
define_menu (rc_res_id id, const rc_res_res_info *resinfo,
1447
       rc_menuitem *menuitems)
1448
0
{
1449
0
  rc_menu *m;
1450
0
  rc_res_resource *r;
1451
1452
0
  m = (rc_menu *) res_alloc (sizeof (rc_menu));
1453
0
  m->items = menuitems;
1454
0
  m->help = 0;
1455
1456
0
  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1457
0
  r->type = RES_TYPE_MENU;
1458
0
  r->u.menu = m;
1459
0
  r->res_info = *resinfo;
1460
0
}
1461
1462
/* Define a menu item.  This does not define a resource, but merely
1463
   allocates and fills in a structure.  */
1464
1465
rc_menuitem *
1466
define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1467
     rc_uint_type state, rc_uint_type help,
1468
     rc_menuitem *menuitems)
1469
0
{
1470
0
  rc_menuitem *mi;
1471
1472
0
  mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
1473
0
  mi->next = NULL;
1474
0
  mi->type = type;
1475
0
  mi->state = state;
1476
0
  mi->id = menuid;
1477
0
  mi->text = unichar_dup (text);
1478
0
  mi->help = help;
1479
0
  mi->popup = menuitems;
1480
0
  return mi;
1481
0
}
1482
1483
/* Define a messagetable resource.  */
1484
1485
void
1486
define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
1487
         const char *filename)
1488
0
{
1489
0
  FILE *e;
1490
0
  char *real_filename;
1491
0
  struct stat s;
1492
0
  bfd_byte *data;
1493
0
  rc_res_resource *r;
1494
1495
0
  e = open_file_search (filename, FOPEN_RB, "messagetable file",
1496
0
      &real_filename);
1497
1498
0
  if (stat (real_filename, &s) < 0)
1499
0
    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1500
0
     strerror (errno));
1501
1502
0
  data = (bfd_byte *) res_alloc (s.st_size);
1503
1504
0
  get_data (e, data, s.st_size, real_filename);
1505
1506
0
  fclose (e);
1507
0
  free (real_filename);
1508
1509
0
  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1510
0
        resinfo->language, 0);
1511
1512
0
  r->type = RES_TYPE_MESSAGETABLE;
1513
0
  r->u.data.length = s.st_size;
1514
0
  r->u.data.data = data;
1515
0
  r->res_info = *resinfo;
1516
0
}
1517
1518
/* Define an rcdata resource.  */
1519
1520
void
1521
define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1522
         rc_rcdata_item *data)
1523
0
{
1524
0
  rc_res_resource *r;
1525
1526
0
  r = define_standard_resource (&resources, RT_RCDATA, id,
1527
0
        resinfo->language, 0);
1528
0
  r->type = RES_TYPE_RCDATA;
1529
0
  r->u.rcdata = data;
1530
0
  r->res_info = *resinfo;
1531
0
}
1532
1533
/* Create an rcdata item holding a string.  */
1534
1535
rc_rcdata_item *
1536
define_rcdata_string (const char *string, rc_uint_type len)
1537
0
{
1538
0
  rc_rcdata_item *ri;
1539
0
  char *s;
1540
1541
0
  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1542
0
  ri->next = NULL;
1543
0
  ri->type = RCDATA_STRING;
1544
0
  ri->u.string.length = len;
1545
0
  s = (char *) res_alloc (len);
1546
0
  memcpy (s, string, len);
1547
0
  ri->u.string.s = s;
1548
1549
0
  return ri;
1550
0
}
1551
1552
/* Create an rcdata item holding a unicode string.  */
1553
1554
rc_rcdata_item *
1555
define_rcdata_unistring (const unichar *string, rc_uint_type len)
1556
0
{
1557
0
  rc_rcdata_item *ri;
1558
0
  unichar *s;
1559
1560
0
  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1561
0
  ri->next = NULL;
1562
0
  ri->type = RCDATA_WSTRING;
1563
0
  ri->u.wstring.length = len;
1564
0
  s = (unichar *) res_alloc (len * sizeof (unichar));
1565
0
  memcpy (s, string, len * sizeof (unichar));
1566
0
  ri->u.wstring.w = s;
1567
1568
0
  return ri;
1569
0
}
1570
1571
/* Create an rcdata item holding a number.  */
1572
1573
rc_rcdata_item *
1574
define_rcdata_number (rc_uint_type val, int dword)
1575
0
{
1576
0
  rc_rcdata_item *ri;
1577
1578
0
  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1579
0
  ri->next = NULL;
1580
0
  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1581
0
  ri->u.word = val;
1582
1583
0
  return ri;
1584
0
}
1585
1586
/* Define a stringtable resource.  This is called for each string
1587
   which appears in a STRINGTABLE statement.  */
1588
1589
void
1590
define_stringtable (const rc_res_res_info *resinfo,
1591
        rc_uint_type stringid, const unichar *string, int len)
1592
0
{
1593
0
  unichar *h;
1594
0
  rc_res_id id;
1595
0
  rc_res_resource *r;
1596
1597
0
  id.named = 0;
1598
0
  id.u.id = (stringid >> 4) + 1;
1599
0
  r = define_standard_resource (&resources, RT_STRING, id,
1600
0
        resinfo->language, 1);
1601
1602
0
  if (r->type == RES_TYPE_UNINITIALIZED)
1603
0
    {
1604
0
      int i;
1605
1606
0
      r->type = RES_TYPE_STRINGTABLE;
1607
0
      r->u.stringtable = ((rc_stringtable *)
1608
0
        res_alloc (sizeof (rc_stringtable)));
1609
0
      for (i = 0; i < 16; i++)
1610
0
  {
1611
0
    r->u.stringtable->strings[i].length = 0;
1612
0
    r->u.stringtable->strings[i].string = NULL;
1613
0
  }
1614
1615
0
      r->res_info = *resinfo;
1616
0
    }
1617
0
  h = (unichar *) res_alloc ((len + 1) * sizeof (unichar));
1618
0
  if (len)
1619
0
    memcpy (h, string, len * sizeof (unichar));
1620
0
  h[len] = 0;
1621
0
  r->u.stringtable->strings[stringid & 0xf].length = (rc_uint_type) len;
1622
0
  r->u.stringtable->strings[stringid & 0xf].string = h;
1623
0
}
1624
1625
void
1626
define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1627
    rc_toolbar_item *items)
1628
0
{
1629
0
  rc_toolbar *t;
1630
0
  rc_res_resource *r;
1631
1632
0
  t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1633
0
  t->button_width = width;
1634
0
  t->button_height = height;
1635
0
  t->nitems = 0;
1636
0
  t->items = items;
1637
0
  while (items != NULL)
1638
0
  {
1639
0
    t->nitems+=1;
1640
0
    items = items->next;
1641
0
  }
1642
0
  r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1643
0
  r->type = RES_TYPE_TOOLBAR;
1644
0
  r->u.toolbar = t;
1645
0
  r->res_info = *resinfo;
1646
0
}
1647
1648
/* Define a user data resource where the data is in the rc file.  */
1649
1650
void
1651
define_user_data (rc_res_id id, rc_res_id type,
1652
      const rc_res_res_info *resinfo,
1653
      rc_rcdata_item *data)
1654
0
{
1655
0
  rc_res_id ids[3];
1656
0
  rc_res_resource *r;
1657
0
  bfd_byte *pb_data;
1658
0
  rc_uint_type len_data;
1659
1660
  /* We have to check if the binary data is parsed specially.  */
1661
0
  if (type.named == 0)
1662
0
    {
1663
0
      switch (type.u.id)
1664
0
      {
1665
0
      case RT_FONTDIR:
1666
0
  define_fontdir_rcdata (id, resinfo, data);
1667
0
  return;
1668
0
      case RT_FONT:
1669
0
  define_font_rcdata (id, resinfo, data);
1670
0
  return;
1671
0
      case RT_ICON:
1672
0
  define_icon_rcdata (id, resinfo, data);
1673
0
  return;
1674
0
      case RT_BITMAP:
1675
0
  define_bitmap_rcdata (id, resinfo, data);
1676
0
  return;
1677
0
      case RT_CURSOR:
1678
0
  define_cursor_rcdata (id, resinfo, data);
1679
0
  return;
1680
0
      case RT_GROUP_ICON:
1681
0
  define_group_icon_rcdata (id, resinfo, data);
1682
0
  return;
1683
0
      case RT_GROUP_CURSOR:
1684
0
  define_group_cursor_rcdata (id, resinfo, data);
1685
0
  return;
1686
0
      case RT_MESSAGETABLE:
1687
0
  define_messagetable_rcdata (id, resinfo, data);
1688
0
  return;
1689
0
      default:
1690
  /* Treat as normal user-data.  */
1691
0
  break;
1692
0
      }
1693
0
    }
1694
0
  ids[0] = type;
1695
0
  ids[1] = id;
1696
0
  ids[2].named = 0;
1697
0
  ids[2].u.id = resinfo->language;
1698
1699
0
  r = define_resource (& resources, 3, ids, 0);
1700
0
  r->type = RES_TYPE_USERDATA;
1701
0
  r->u.userdata = ((rc_rcdata_item *)
1702
0
       res_alloc (sizeof (rc_rcdata_item)));
1703
0
  r->u.userdata->next = NULL;
1704
0
  r->u.userdata->type = RCDATA_BUFFER;
1705
0
  pb_data = rcdata_render_as_buffer (data, &len_data);
1706
0
  r->u.userdata->u.buffer.length = len_data;
1707
0
  r->u.userdata->u.buffer.data = pb_data;
1708
0
  r->res_info = *resinfo;
1709
0
}
1710
1711
void
1712
define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
1713
        const char *filename)
1714
0
{
1715
0
  rc_rcdata_item *ri;
1716
0
  FILE *e;
1717
0
  char *real_filename;
1718
0
  struct stat s;
1719
0
  bfd_byte *data;
1720
1721
0
  e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1722
1723
1724
0
  if (stat (real_filename, &s) < 0)
1725
0
    fatal (_("stat failed on file `%s': %s"), real_filename,
1726
0
     strerror (errno));
1727
1728
0
  data = (bfd_byte *) res_alloc (s.st_size);
1729
1730
0
  get_data (e, data, s.st_size, real_filename);
1731
1732
0
  fclose (e);
1733
0
  free (real_filename);
1734
1735
0
  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1736
0
  ri->next = NULL;
1737
0
  ri->type = RCDATA_BUFFER;
1738
0
  ri->u.buffer.length = s.st_size;
1739
0
  ri->u.buffer.data = data;
1740
1741
0
  define_rcdata (id, resinfo, ri);
1742
0
}
1743
1744
/* Define a user data resource where the data is in a file.  */
1745
1746
void
1747
define_user_file (rc_res_id id, rc_res_id type,
1748
      const rc_res_res_info *resinfo, const char *filename)
1749
0
{
1750
0
  FILE *e;
1751
0
  char *real_filename;
1752
0
  struct stat s;
1753
0
  bfd_byte *data;
1754
0
  rc_res_id ids[3];
1755
0
  rc_res_resource *r;
1756
1757
0
  e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1758
1759
0
  if (stat (real_filename, &s) < 0)
1760
0
    fatal (_("stat failed on file `%s': %s"), real_filename,
1761
0
     strerror (errno));
1762
1763
0
  data = (bfd_byte *) res_alloc (s.st_size);
1764
1765
0
  get_data (e, data, s.st_size, real_filename);
1766
1767
0
  fclose (e);
1768
0
  free (real_filename);
1769
1770
0
  ids[0] = type;
1771
0
  ids[1] = id;
1772
0
  ids[2].named = 0;
1773
0
  ids[2].u.id = resinfo->language;
1774
1775
0
  r = define_resource (&resources, 3, ids, 0);
1776
0
  r->type = RES_TYPE_USERDATA;
1777
0
  r->u.userdata = ((rc_rcdata_item *)
1778
0
       res_alloc (sizeof (rc_rcdata_item)));
1779
0
  r->u.userdata->next = NULL;
1780
0
  r->u.userdata->type = RCDATA_BUFFER;
1781
0
  r->u.userdata->u.buffer.length = s.st_size;
1782
0
  r->u.userdata->u.buffer.data = data;
1783
0
  r->res_info = *resinfo;
1784
0
}
1785
1786
/* Define a versioninfo resource.  */
1787
1788
void
1789
define_versioninfo (rc_res_id id, rc_uint_type language,
1790
        rc_fixed_versioninfo *fixedverinfo,
1791
        rc_ver_info *verinfo)
1792
0
{
1793
0
  rc_res_resource *r;
1794
1795
0
  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1796
0
  r->type = RES_TYPE_VERSIONINFO;
1797
0
  r->u.versioninfo = ((rc_versioninfo *)
1798
0
          res_alloc (sizeof (rc_versioninfo)));
1799
0
  r->u.versioninfo->fixed = fixedverinfo;
1800
0
  r->u.versioninfo->var = verinfo;
1801
0
  r->res_info.language = language;
1802
0
}
1803
1804
/* Add string version info to a list of version information.  */
1805
1806
rc_ver_info *
1807
append_ver_stringfileinfo (rc_ver_info *verinfo,
1808
         rc_ver_stringtable *stringtables)
1809
0
{
1810
0
  rc_ver_info *vi, **pp;
1811
1812
0
  vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1813
0
  vi->next = NULL;
1814
0
  vi->type = VERINFO_STRING;
1815
0
  vi->u.string.stringtables = stringtables;
1816
1817
0
  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1818
0
    ;
1819
0
  *pp = vi;
1820
1821
0
  return verinfo;
1822
0
}
1823
1824
rc_ver_stringtable *
1825
append_ver_stringtable (rc_ver_stringtable *stringtable,
1826
      const char *language,
1827
      rc_ver_stringinfo *strings)
1828
0
{
1829
0
  rc_ver_stringtable *vst, **pp;
1830
1831
0
  vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1832
0
  vst->next = NULL;
1833
0
  unicode_from_ascii ((rc_uint_type *) NULL, &vst->language, language);
1834
0
  vst->strings = strings;
1835
1836
0
  for (pp = &stringtable; *pp != NULL; pp = &(*pp)->next)
1837
0
    ;
1838
0
  *pp = vst;
1839
1840
0
  return stringtable;
1841
0
}
1842
1843
/* Add variable version info to a list of version information.  */
1844
1845
rc_ver_info *
1846
append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1847
      rc_ver_varinfo *var)
1848
0
{
1849
0
  rc_ver_info *vi, **pp;
1850
1851
0
  vi = (rc_ver_info *) res_alloc (sizeof *vi);
1852
0
  vi->next = NULL;
1853
0
  vi->type = VERINFO_VAR;
1854
0
  vi->u.var.key = unichar_dup (key);
1855
0
  vi->u.var.var = var;
1856
1857
0
  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1858
0
    ;
1859
0
  *pp = vi;
1860
1861
0
  return verinfo;
1862
0
}
1863
1864
/* Append version string information to a list.  */
1865
1866
rc_ver_stringinfo *
1867
append_verval (rc_ver_stringinfo *strings, const unichar *key,
1868
         const unichar *value)
1869
0
{
1870
0
  rc_ver_stringinfo *vs, **pp;
1871
1872
0
  vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1873
0
  vs->next = NULL;
1874
0
  vs->key = unichar_dup (key);
1875
0
  vs->value = unichar_dup (value);
1876
1877
0
  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1878
0
    ;
1879
0
  *pp = vs;
1880
1881
0
  return strings;
1882
0
}
1883
1884
/* Append version variable information to a list.  */
1885
1886
rc_ver_varinfo *
1887
append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1888
     rc_uint_type charset)
1889
0
{
1890
0
  rc_ver_varinfo *vv, **pp;
1891
1892
0
  vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1893
0
  vv->next = NULL;
1894
0
  vv->language = language;
1895
0
  vv->charset = charset;
1896
1897
0
  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1898
0
    ;
1899
0
  *pp = vv;
1900
1901
0
  return var;
1902
0
}
1903

1904
/* Local functions used to write out an rc file.  */
1905
1906
static void indent (FILE *, int);
1907
static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1908
        const rc_res_id *, rc_uint_type *, int);
1909
static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1910
           const rc_res_id *, rc_uint_type *, int);
1911
static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1912
             const rc_res_resource *, rc_uint_type *);
1913
static void write_rc_accelerators (FILE *, const rc_accelerator *);
1914
static void write_rc_cursor (FILE *, const rc_cursor *);
1915
static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1916
static void write_rc_dialog (FILE *, const rc_dialog *);
1917
static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1918
static void write_rc_fontdir (FILE *, const rc_fontdir *);
1919
static void write_rc_group_icon (FILE *, const rc_group_icon *);
1920
static void write_rc_menu (FILE *, const rc_menu *, int);
1921
static void write_rc_toolbar (FILE *, const rc_toolbar *);
1922
static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1923
static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
1924
1925
static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1926
static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1927
static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1928
static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
1929
1930
/* Indent a given number of spaces.  */
1931
1932
static void
1933
indent (FILE *e, int c)
1934
0
{
1935
0
  int i;
1936
1937
0
  for (i = 0; i < c; i++)
1938
0
    putc (' ', e);
1939
0
}
1940
1941
/* Dump the resources we have read in the format of an rc file.
1942
1943
   Reasoned by the fact, that some resources need to be stored into file and
1944
   refer to that file, we use the user-data model for that to express it binary
1945
   without the need to store it somewhere externally.  */
1946
1947
void
1948
write_rc_file (const char *filename, const rc_res_directory *res_dir)
1949
0
{
1950
0
  FILE *e;
1951
0
  rc_uint_type language;
1952
1953
0
  if (filename == NULL)
1954
0
    e = stdout;
1955
0
  else
1956
0
    {
1957
0
      e = fopen (filename, FOPEN_WT);
1958
0
      if (e == NULL)
1959
0
  fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1960
0
    }
1961
1962
0
  language = (rc_uint_type) ((bfd_signed_vma) -1);
1963
0
  write_rc_directory (e, res_dir, (const rc_res_id *) NULL,
1964
0
          (const rc_res_id *) NULL, &language, 1);
1965
0
}
1966
1967
/* Write out a directory.  E is the file to write to.  RD is the
1968
   directory.  TYPE is a pointer to the level 1 ID which serves as the
1969
   resource type.  NAME is a pointer to the level 2 ID which serves as
1970
   an individual resource name.  LANGUAGE is a pointer to the current
1971
   language.  LEVEL is the level in the tree.  */
1972
1973
static void
1974
write_rc_directory (FILE *e, const rc_res_directory *rd,
1975
        const rc_res_id *type, const rc_res_id *name,
1976
        rc_uint_type *language, int level)
1977
0
{
1978
0
  const rc_res_entry *re;
1979
1980
  /* Print out some COFF information that rc files can't represent.  */
1981
0
  if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1982
0
    {
1983
0
      wr_printcomment (e, "COFF information not part of RC");
1984
0
  if (rd->time != 0)
1985
0
  wr_printcomment (e, "Time stamp: %u", rd->time);
1986
0
  if (rd->characteristics != 0)
1987
0
  wr_printcomment (e, "Characteristics: %u", rd->characteristics);
1988
0
  if (rd->major != 0 || rd->minor != 0)
1989
0
  wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1990
0
    }
1991
1992
0
  for (re = rd->entries;  re != NULL; re = re->next)
1993
0
    {
1994
0
      switch (level)
1995
0
  {
1996
0
  case 1:
1997
    /* If we're at level 1, the key of this resource is the
1998
             type.  This normally duplicates the information we have
1999
             stored with the resource itself, but we need to remember
2000
             the type if this is a user define resource type.  */
2001
0
    type = &re->id;
2002
0
    break;
2003
2004
0
  case 2:
2005
    /* If we're at level 2, the key of this resource is the name
2006
       we are going to use in the rc printout.  */
2007
0
    name = &re->id;
2008
0
    break;
2009
2010
0
  case 3:
2011
    /* If we're at level 3, then this key represents a language.
2012
       Use it to update the current language.  */
2013
0
    if (! re->id.named
2014
0
        && re->id.u.id != (unsigned long) (unsigned int) *language
2015
0
        && (re->id.u.id & 0xffff) == re->id.u.id)
2016
0
      {
2017
0
        wr_print (e, "LANGUAGE %u, %u\n",
2018
0
           re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
2019
0
           (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
2020
0
        *language = re->id.u.id;
2021
0
      }
2022
0
    break;
2023
2024
0
  default:
2025
0
    break;
2026
0
  }
2027
2028
0
      if (re->subdir)
2029
0
  write_rc_subdir (e, re, type, name, language, level);
2030
0
      else
2031
0
  {
2032
0
    if (level == 3)
2033
0
      {
2034
        /* This is the normal case: the three levels are
2035
                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
2036
                 2, and represents the name to use.  We probably just
2037
                 set LANGUAGE, and it will probably match what the
2038
                 resource itself records if anything.  */
2039
0
        write_rc_resource (e, type, name, re->u.res, language);
2040
0
      }
2041
0
    else
2042
0
      {
2043
0
        wr_printcomment (e, "Resource at unexpected level %d", level);
2044
0
        write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
2045
0
         language);
2046
0
      }
2047
0
  }
2048
0
    }
2049
0
  if (rd->entries == NULL)
2050
0
    {
2051
0
      wr_print_flush (e);
2052
0
    }
2053
0
}
2054
2055
/* Write out a subdirectory entry.  E is the file to write to.  RE is
2056
   the subdirectory entry.  TYPE and NAME are pointers to higher level
2057
   IDs, or NULL.  LANGUAGE is a pointer to the current language.
2058
   LEVEL is the level in the tree.  */
2059
2060
static void
2061
write_rc_subdir (FILE *e, const rc_res_entry *re,
2062
     const rc_res_id *type, const rc_res_id *name,
2063
     rc_uint_type *language, int level)
2064
0
{
2065
0
  fprintf (e, "\n");
2066
0
  switch (level)
2067
0
    {
2068
0
    case 1:
2069
0
      wr_printcomment (e, "Type: ");
2070
0
      if (re->id.named)
2071
0
  res_id_print (e, re->id, 1);
2072
0
      else
2073
0
  {
2074
0
    const char *s;
2075
2076
0
    switch (re->id.u.id)
2077
0
      {
2078
0
      case RT_CURSOR: s = "cursor"; break;
2079
0
      case RT_BITMAP: s = "bitmap"; break;
2080
0
      case RT_ICON: s = "icon"; break;
2081
0
      case RT_MENU: s = "menu"; break;
2082
0
      case RT_DIALOG: s = "dialog"; break;
2083
0
      case RT_STRING: s = "stringtable"; break;
2084
0
      case RT_FONTDIR: s = "fontdir"; break;
2085
0
      case RT_FONT: s = "font"; break;
2086
0
      case RT_ACCELERATOR: s = "accelerators"; break;
2087
0
      case RT_RCDATA: s = "rcdata"; break;
2088
0
      case RT_MESSAGETABLE: s = "messagetable"; break;
2089
0
      case RT_GROUP_CURSOR: s = "group cursor"; break;
2090
0
      case RT_GROUP_ICON: s = "group icon"; break;
2091
0
      case RT_VERSION: s = "version"; break;
2092
0
      case RT_DLGINCLUDE: s = "dlginclude"; break;
2093
0
      case RT_PLUGPLAY: s = "plugplay"; break;
2094
0
      case RT_VXD: s = "vxd"; break;
2095
0
      case RT_ANICURSOR: s = "anicursor"; break;
2096
0
      case RT_ANIICON: s = "aniicon"; break;
2097
0
      case RT_TOOLBAR: s = "toolbar"; break;
2098
0
      case RT_HTML: s = "html"; break;
2099
0
      default: s = NULL; break;
2100
0
      }
2101
2102
0
    if (s != NULL)
2103
0
      fprintf (e, "%s", s);
2104
0
    else
2105
0
      res_id_print (e, re->id, 1);
2106
0
  }
2107
0
      break;
2108
2109
0
    case 2:
2110
0
      wr_printcomment (e, "Name: ");
2111
0
      res_id_print (e, re->id, 1);
2112
0
      break;
2113
2114
0
    case 3:
2115
0
      wr_printcomment (e, "Language: ");
2116
0
      res_id_print (e, re->id, 1);
2117
0
      break;
2118
2119
0
    default:
2120
0
      wr_printcomment (e, "Level %d: ", level);
2121
0
      res_id_print (e, re->id, 1);
2122
0
    }
2123
2124
0
  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
2125
0
}
2126
2127
/* Write out a single resource.  E is the file to write to.  TYPE is a
2128
   pointer to the type of the resource.  NAME is a pointer to the name
2129
   of the resource; it will be NULL if there is a level mismatch.  RES
2130
   is the resource data.  LANGUAGE is a pointer to the current
2131
   language.  */
2132
2133
static void
2134
write_rc_resource (FILE *e, const rc_res_id *type,
2135
       const rc_res_id *name, const rc_res_resource *res,
2136
       rc_uint_type *language)
2137
0
{
2138
0
  const char *s;
2139
0
  int rt;
2140
0
  int menuex = 0;
2141
2142
0
  switch (res->type)
2143
0
    {
2144
0
    default:
2145
0
      abort ();
2146
2147
0
    case RES_TYPE_ACCELERATOR:
2148
0
      s = "ACCELERATORS";
2149
0
      rt = RT_ACCELERATOR;
2150
0
      break;
2151
2152
0
    case RES_TYPE_BITMAP:
2153
0
      s = "2 /* RT_BITMAP */";
2154
0
      rt = RT_BITMAP;
2155
0
      break;
2156
2157
0
    case RES_TYPE_CURSOR:
2158
0
      s = "1 /* RT_CURSOR */";
2159
0
      rt = RT_CURSOR;
2160
0
      break;
2161
2162
0
    case RES_TYPE_GROUP_CURSOR:
2163
0
      s = "12 /* RT_GROUP_CURSOR */";
2164
0
      rt = RT_GROUP_CURSOR;
2165
0
      break;
2166
2167
0
    case RES_TYPE_DIALOG:
2168
0
      if (extended_dialog (res->u.dialog))
2169
0
  s = "DIALOGEX";
2170
0
      else
2171
0
  s = "DIALOG";
2172
0
      rt = RT_DIALOG;
2173
0
      break;
2174
2175
0
    case RES_TYPE_FONT:
2176
0
      s = "8 /* RT_FONT */";
2177
0
      rt = RT_FONT;
2178
0
      break;
2179
2180
0
    case RES_TYPE_FONTDIR:
2181
0
      s = "7 /* RT_FONTDIR */";
2182
0
      rt = RT_FONTDIR;
2183
0
      break;
2184
2185
0
    case RES_TYPE_ICON:
2186
0
      s = "3 /* RT_ICON */";
2187
0
      rt = RT_ICON;
2188
0
      break;
2189
2190
0
    case RES_TYPE_GROUP_ICON:
2191
0
      s = "14 /* RT_GROUP_ICON */";
2192
0
      rt = RT_GROUP_ICON;
2193
0
      break;
2194
2195
0
    case RES_TYPE_MENU:
2196
0
      if (extended_menu (res->u.menu))
2197
0
  {
2198
0
    s = "MENUEX";
2199
0
    menuex = 1;
2200
0
  }
2201
0
      else
2202
0
  {
2203
0
    s = "MENU";
2204
0
    menuex = 0;
2205
0
  }
2206
0
      rt = RT_MENU;
2207
0
      break;
2208
2209
0
    case RES_TYPE_MESSAGETABLE:
2210
0
      s = "11 /* RT_MESSAGETABLE */";
2211
0
      rt = RT_MESSAGETABLE;
2212
0
      break;
2213
2214
0
    case RES_TYPE_RCDATA:
2215
0
      s = "RCDATA";
2216
0
      rt = RT_RCDATA;
2217
0
      break;
2218
2219
0
    case RES_TYPE_STRINGTABLE:
2220
0
      s = "STRINGTABLE";
2221
0
      rt = RT_STRING;
2222
0
      break;
2223
2224
0
    case RES_TYPE_USERDATA:
2225
0
      s = NULL;
2226
0
      rt = 0;
2227
0
      break;
2228
2229
0
    case RES_TYPE_VERSIONINFO:
2230
0
      s = "VERSIONINFO";
2231
0
      rt = RT_VERSION;
2232
0
      break;
2233
2234
0
    case RES_TYPE_TOOLBAR:
2235
0
      s = "TOOLBAR";
2236
0
      rt = RT_TOOLBAR;
2237
0
      break;
2238
0
    }
2239
2240
0
  if (rt != 0
2241
0
      && type != NULL
2242
0
      && (type->named || type->u.id != (unsigned long) rt))
2243
0
    {
2244
0
      wr_printcomment (e, "Unexpected resource type mismatch: ");
2245
0
      res_id_print (e, *type, 1);
2246
0
      fprintf (e, " != %d", rt);
2247
0
    }
2248
2249
0
  if (res->coff_info.codepage != 0)
2250
0
    wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
2251
0
  if (res->coff_info.reserved != 0)
2252
0
    wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
2253
2254
0
  wr_print (e, "\n");
2255
0
  if (rt == RT_STRING)
2256
0
    ;
2257
0
  else
2258
0
    {
2259
0
  if (name != NULL)
2260
0
  res_id_print (e, *name, 1);
2261
0
  else
2262
0
    fprintf (e, "??Unknown-Name??");
2263
0
  fprintf (e, " ");
2264
0
    }
2265
2266
0
  if (s != NULL)
2267
0
    fprintf (e, "%s", s);
2268
0
  else if (type != NULL)
2269
0
    {
2270
0
      if (type->named == 0)
2271
0
  {
2272
0
#define PRINT_RT_NAME(NAME) case NAME: \
2273
0
  fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2274
0
  break
2275
2276
0
    switch (type->u.id)
2277
0
      {
2278
0
      default:
2279
0
    res_id_print (e, *type, 0);
2280
0
        break;
2281
2282
0
      PRINT_RT_NAME(RT_MANIFEST);
2283
0
      PRINT_RT_NAME(RT_ANICURSOR);
2284
0
      PRINT_RT_NAME(RT_ANIICON);
2285
0
      PRINT_RT_NAME(RT_RCDATA);
2286
0
      PRINT_RT_NAME(RT_ICON);
2287
0
      PRINT_RT_NAME(RT_CURSOR);
2288
0
      PRINT_RT_NAME(RT_BITMAP);
2289
0
      PRINT_RT_NAME(RT_PLUGPLAY);
2290
0
      PRINT_RT_NAME(RT_VXD);
2291
0
      PRINT_RT_NAME(RT_FONT);
2292
0
      PRINT_RT_NAME(RT_FONTDIR);
2293
0
      PRINT_RT_NAME(RT_HTML);
2294
0
      PRINT_RT_NAME(RT_MESSAGETABLE);
2295
0
      PRINT_RT_NAME(RT_DLGINCLUDE);
2296
0
      PRINT_RT_NAME(RT_DLGINIT);
2297
0
      }
2298
0
#undef PRINT_RT_NAME
2299
0
  }
2300
0
      else
2301
0
  res_id_print (e, *type, 1);
2302
0
    }
2303
0
  else
2304
0
    fprintf (e, "??Unknown-Type??");
2305
2306
0
  if (res->res_info.memflags != 0)
2307
0
    {
2308
0
      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
2309
0
  fprintf (e, " MOVEABLE");
2310
0
      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
2311
0
  fprintf (e, " PURE");
2312
0
      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
2313
0
  fprintf (e, " PRELOAD");
2314
0
      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
2315
0
  fprintf (e, " DISCARDABLE");
2316
0
    }
2317
2318
0
  if (res->type == RES_TYPE_DIALOG)
2319
0
    {
2320
0
      fprintf (e, " %d, %d, %d, %d",
2321
0
         (int) res->u.dialog->x, (int) res->u.dialog->y,
2322
0
         (int) res->u.dialog->width, (int) res->u.dialog->height);
2323
0
      if (res->u.dialog->ex != NULL
2324
0
    && res->u.dialog->ex->help != 0)
2325
0
  fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
2326
0
    }
2327
0
  else if (res->type == RES_TYPE_TOOLBAR)
2328
0
  {
2329
0
    fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2330
0
       (int) res->u.toolbar->button_height);
2331
0
    }
2332
2333
0
  fprintf (e, "\n");
2334
2335
0
  if ((res->res_info.language != 0 && res->res_info.language != *language)
2336
0
      || res->res_info.characteristics != 0
2337
0
      || res->res_info.version != 0)
2338
0
    {
2339
0
      int modifiers;
2340
2341
0
      switch (res->type)
2342
0
  {
2343
0
  case RES_TYPE_ACCELERATOR:
2344
0
  case RES_TYPE_DIALOG:
2345
0
  case RES_TYPE_MENU:
2346
0
  case RES_TYPE_RCDATA:
2347
0
  case RES_TYPE_STRINGTABLE:
2348
0
    modifiers = 1;
2349
0
    break;
2350
2351
0
  default:
2352
0
    modifiers = 0;
2353
0
    break;
2354
0
  }
2355
2356
0
      if (res->res_info.language != 0 && res->res_info.language != *language)
2357
0
  fprintf (e, "%sLANGUAGE %d, %d\n",
2358
0
     modifiers ? "// " : "",
2359
0
     (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2360
0
     (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
2361
0
      if (res->res_info.characteristics != 0)
2362
0
  fprintf (e, "%sCHARACTERISTICS %u\n",
2363
0
     modifiers ? "// " : "",
2364
0
     (unsigned int) res->res_info.characteristics);
2365
0
      if (res->res_info.version != 0)
2366
0
  fprintf (e, "%sVERSION %u\n",
2367
0
     modifiers ? "// " : "",
2368
0
     (unsigned int) res->res_info.version);
2369
0
    }
2370
2371
0
  switch (res->type)
2372
0
    {
2373
0
    default:
2374
0
      abort ();
2375
2376
0
    case RES_TYPE_ACCELERATOR:
2377
0
      write_rc_accelerators (e, res->u.acc);
2378
0
      break;
2379
2380
0
    case RES_TYPE_CURSOR:
2381
0
      write_rc_cursor (e, res->u.cursor);
2382
0
      break;
2383
2384
0
    case RES_TYPE_GROUP_CURSOR:
2385
0
      write_rc_group_cursor (e, res->u.group_cursor);
2386
0
      break;
2387
2388
0
    case RES_TYPE_DIALOG:
2389
0
      write_rc_dialog (e, res->u.dialog);
2390
0
      break;
2391
2392
0
    case RES_TYPE_FONTDIR:
2393
0
      write_rc_fontdir (e, res->u.fontdir);
2394
0
      break;
2395
2396
0
    case RES_TYPE_GROUP_ICON:
2397
0
      write_rc_group_icon (e, res->u.group_icon);
2398
0
      break;
2399
2400
0
    case RES_TYPE_MENU:
2401
0
      write_rc_menu (e, res->u.menu, menuex);
2402
0
      break;
2403
2404
0
    case RES_TYPE_RCDATA:
2405
0
      write_rc_rcdata (e, res->u.rcdata, 0);
2406
0
      break;
2407
2408
0
    case RES_TYPE_STRINGTABLE:
2409
0
      write_rc_stringtable (e, name, res->u.stringtable);
2410
0
      break;
2411
2412
0
    case RES_TYPE_USERDATA:
2413
0
      write_rc_rcdata (e, res->u.userdata, 0);
2414
0
      break;
2415
2416
0
    case RES_TYPE_TOOLBAR:
2417
0
      write_rc_toolbar (e, res->u.toolbar);
2418
0
      break;
2419
2420
0
    case RES_TYPE_VERSIONINFO:
2421
0
      write_rc_versioninfo (e, res->u.versioninfo);
2422
0
      break;
2423
2424
0
    case RES_TYPE_BITMAP:
2425
0
    case RES_TYPE_FONT:
2426
0
    case RES_TYPE_ICON:
2427
0
      write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2428
0
      break;
2429
0
    case RES_TYPE_MESSAGETABLE:
2430
0
      write_rc_messagetable (e, res->u.data.length, res->u.data.data);
2431
0
      break;
2432
0
    }
2433
0
}
2434
2435
/* Write out accelerator information.  */
2436
2437
static void
2438
write_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
2439
0
{
2440
0
  const rc_accelerator *acc;
2441
2442
0
  fprintf (e, "BEGIN\n");
2443
0
  for (acc = accelerators; acc != NULL; acc = acc->next)
2444
0
    {
2445
0
      int printable;
2446
2447
0
      fprintf (e, "  ");
2448
2449
0
      if ((acc->key & 0x7f) == acc->key
2450
0
    && ISPRINT (acc->key)
2451
0
    && (acc->flags & ACC_VIRTKEY) == 0)
2452
0
  {
2453
0
    fprintf (e, "\"%c\"", (char) acc->key);
2454
0
    printable = 1;
2455
0
  }
2456
0
      else
2457
0
  {
2458
0
    fprintf (e, "%d", (int) acc->key);
2459
0
    printable = 0;
2460
0
  }
2461
2462
0
      fprintf (e, ", %d", (int) acc->id);
2463
2464
0
      if (! printable)
2465
0
  {
2466
0
    if ((acc->flags & ACC_VIRTKEY) != 0)
2467
0
      fprintf (e, ", VIRTKEY");
2468
0
    else
2469
0
      fprintf (e, ", ASCII");
2470
0
  }
2471
2472
0
      if ((acc->flags & ACC_SHIFT) != 0)
2473
0
  fprintf (e, ", SHIFT");
2474
0
      if ((acc->flags & ACC_CONTROL) != 0)
2475
0
  fprintf (e, ", CONTROL");
2476
0
      if ((acc->flags & ACC_ALT) != 0)
2477
0
  fprintf (e, ", ALT");
2478
2479
0
      fprintf (e, "\n");
2480
0
    }
2481
2482
0
  fprintf (e, "END\n");
2483
0
}
2484
2485
/* Write out cursor information.  This would normally be in a separate
2486
   file, which the rc file would include.  */
2487
2488
static void
2489
write_rc_cursor (FILE *e, const rc_cursor *cursor)
2490
0
{
2491
0
  fprintf (e, "BEGIN\n");
2492
0
  indent (e, 2);
2493
0
  fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d.  */\n",
2494
0
     (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2495
0
     (int) cursor->xhotspot, (int) cursor->yhotspot);
2496
0
  write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2497
0
            0, 0, 0);
2498
0
  fprintf (e, "END\n");
2499
0
}
2500
2501
/* Write out group cursor data.  This would normally be built from the
2502
   cursor data.  */
2503
2504
static void
2505
write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
2506
0
{
2507
0
  const rc_group_cursor *gc;
2508
0
  int c;
2509
2510
0
  for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2511
0
    ;
2512
0
  fprintf (e, "BEGIN\n");
2513
2514
0
  indent (e, 2);
2515
0
  fprintf (e, "0, 2, %d%s\t /* Having %d items.  */\n", c, (c != 0 ? "," : ""), c);
2516
0
  indent (e, 4);
2517
0
  fprintf (e, "/* width, height, planes, bits, bytes, index.  */\n");
2518
2519
0
  for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2520
0
    {
2521
0
      indent (e, 4);
2522
0
      fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2523
0
  (int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2524
0
  (unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2525
0
      fprintf (e, "/* width: %d; height %d; planes %d; bits %d.  */\n",
2526
0
       (int) gc->width, (int) gc->height, (int) gc->planes,
2527
0
       (int) gc->bits);
2528
0
    }
2529
0
  fprintf (e, "END\n");
2530
0
}
2531
2532
/* Write dialog data.  */
2533
2534
static void
2535
write_rc_dialog (FILE *e, const rc_dialog *dialog)
2536
0
{
2537
0
  const rc_dialog_control *control;
2538
2539
0
  fprintf (e, "STYLE 0x%x\n", dialog->style);
2540
2541
0
  if (dialog->exstyle != 0)
2542
0
    fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
2543
2544
0
  if ((dialog->class.named && dialog->class.u.n.length > 0)
2545
0
      || dialog->class.u.id != 0)
2546
0
    {
2547
0
      fprintf (e, "CLASS ");
2548
0
      res_id_print (e, dialog->class, 1);
2549
0
      fprintf (e, "\n");
2550
0
    }
2551
2552
0
  if (dialog->caption != NULL)
2553
0
    {
2554
0
      fprintf (e, "CAPTION ");
2555
0
      unicode_print_quoted (e, dialog->caption, -1);
2556
0
      fprintf (e, "\n");
2557
0
    }
2558
2559
0
  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2560
0
      || dialog->menu.u.id != 0)
2561
0
    {
2562
0
      fprintf (e, "MENU ");
2563
0
      res_id_print (e, dialog->menu, 0);
2564
0
      fprintf (e, "\n");
2565
0
    }
2566
2567
0
  if (dialog->font != NULL)
2568
0
    {
2569
0
      fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2570
0
      unicode_print_quoted (e, dialog->font, -1);
2571
0
      if (dialog->ex != NULL
2572
0
    && (dialog->ex->weight != 0
2573
0
        || dialog->ex->italic != 0
2574
0
        || dialog->ex->charset != 1))
2575
0
  fprintf (e, ", %d, %d, %d",
2576
0
     (int) dialog->ex->weight,
2577
0
     (int) dialog->ex->italic,
2578
0
     (int) dialog->ex->charset);
2579
0
      fprintf (e, "\n");
2580
0
    }
2581
2582
0
  fprintf (e, "BEGIN\n");
2583
2584
0
  for (control = dialog->controls; control != NULL; control = control->next)
2585
0
    write_rc_dialog_control (e, control);
2586
2587
0
  fprintf (e, "END\n");
2588
0
}
2589
2590
/* For each predefined control keyword, this table provides the class
2591
   and the style.  */
2592
2593
struct control_info
2594
{
2595
  const char *name;
2596
  unsigned short class;
2597
  unsigned long style;
2598
};
2599
2600
static const struct control_info control_info[] =
2601
{
2602
  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2603
  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2604
  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2605
  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2606
  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2607
  { "CTEXT", CTL_STATIC, SS_CENTER },
2608
  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2609
  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2610
  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2611
  { "ICON", CTL_STATIC, SS_ICON },
2612
  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2613
  { "LTEXT", CTL_STATIC, SS_LEFT },
2614
  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2615
  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2616
  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2617
  { "RTEXT", CTL_STATIC, SS_RIGHT },
2618
  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2619
  { "STATE3", CTL_BUTTON, BS_3STATE },
2620
  /* It's important that USERBUTTON come after all the other button
2621
     types, so that it won't be matched too early.  */
2622
  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2623
  { NULL, 0, 0 }
2624
};
2625
2626
/* Write a dialog control.  */
2627
2628
static void
2629
write_rc_dialog_control (FILE *e, const rc_dialog_control *control)
2630
0
{
2631
0
  const struct control_info *ci;
2632
2633
0
  fprintf (e, "  ");
2634
2635
0
  if (control->class.named)
2636
0
    ci = NULL;
2637
0
  else
2638
0
    {
2639
0
      for (ci = control_info; ci->name != NULL; ++ci)
2640
0
  if (ci->class == control->class.u.id
2641
0
      && (ci->style == (unsigned long) -1
2642
0
    || ci->style == (control->style & 0xff)))
2643
0
    break;
2644
0
    }
2645
0
  if (ci == NULL)
2646
0
    fprintf (e, "CONTROL");
2647
0
  else if (ci->name != NULL)
2648
0
    fprintf (e, "%s", ci->name);
2649
0
  else
2650
0
    {
2651
0
    fprintf (e, "CONTROL");
2652
0
      ci = NULL;
2653
0
    }
2654
2655
  /* For EDITTEXT, COMBOBOX, LISTBOX, and SCROLLBAR don't dump text.  */
2656
0
  if ((control->text.named || control->text.u.id != 0)
2657
0
      && (!ci
2658
0
          || (ci->class != CTL_EDIT
2659
0
              && ci->class != CTL_COMBOBOX
2660
0
              && ci->class != CTL_LISTBOX
2661
0
              && ci->class != CTL_SCROLLBAR)))
2662
0
    {
2663
0
      fprintf (e, " ");
2664
0
      res_id_print (e, control->text, 1);
2665
0
      fprintf (e, ",");
2666
0
    }
2667
2668
0
  fprintf (e, " %d, ", (int) control->id);
2669
2670
0
  if (ci == NULL)
2671
0
    {
2672
0
      if (control->class.named)
2673
0
  fprintf (e, "\"");
2674
0
      res_id_print (e, control->class, 0);
2675
0
      if (control->class.named)
2676
0
  fprintf (e, "\"");
2677
0
      fprintf (e, ", 0x%x, ", (unsigned int) control->style);
2678
0
    }
2679
2680
0
  fprintf (e, "%d, %d", (int) control->x, (int) control->y);
2681
2682
0
  if (control->style != SS_ICON
2683
0
      || control->exstyle != 0
2684
0
      || control->width != 0
2685
0
      || control->height != 0
2686
0
      || control->help != 0)
2687
0
    {
2688
0
      fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
2689
2690
      /* FIXME: We don't need to print the style if it is the default.
2691
   More importantly, in certain cases we actually need to turn
2692
   off parts of the forced style, by using NOT.  */
2693
0
      if (ci != NULL)
2694
0
  fprintf (e, ", 0x%x", (unsigned int) control->style);
2695
2696
0
      if (control->exstyle != 0 || control->help != 0)
2697
0
  fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2698
0
     (unsigned int) control->help);
2699
0
    }
2700
2701
0
  fprintf (e, "\n");
2702
2703
0
  if (control->data != NULL)
2704
0
    write_rc_rcdata (e, control->data, 2);
2705
0
}
2706
2707
/* Write out font directory data.  This would normally be built from
2708
   the font data.  */
2709
2710
static void
2711
write_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
2712
0
{
2713
0
  const rc_fontdir *fc;
2714
0
  int c;
2715
2716
0
  for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2717
0
    ;
2718
0
  fprintf (e, "BEGIN\n");
2719
0
  indent (e, 2);
2720
0
  fprintf (e, "%d%s\t /* Has %d elements.  */\n", c, (c != 0 ? "," : ""), c);
2721
0
  for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
2722
0
    {
2723
0
      indent (e, 4);
2724
0
      fprintf (e, "%d,\t/* Font no %d with index %d.  */\n",
2725
0
  (int) fc->index, c, (int) fc->index);
2726
0
      write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2727
0
        (const bfd_byte *) fc->data + 4,fc->next != NULL,
2728
0
        0, 0);
2729
0
    }
2730
0
  fprintf (e, "END\n");
2731
0
}
2732
2733
/* Write out group icon data.  This would normally be built from the
2734
   icon data.  */
2735
2736
static void
2737
write_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
2738
0
{
2739
0
  const rc_group_icon *gi;
2740
0
  int c;
2741
2742
0
  for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2743
0
    ;
2744
2745
0
  fprintf (e, "BEGIN\n");
2746
0
  indent (e, 2);
2747
0
  fprintf (e, " 0, 1, %d%s\t /* Has %d elements.  */\n", c, (c != 0 ? "," : ""), c);
2748
2749
0
  indent (e, 4);
2750
0
  fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index.  */\n");
2751
0
  for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
2752
0
    {
2753
0
      indent (e, 4);
2754
0
      fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d.  */\n",
2755
0
  gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2756
0
  (unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
2757
0
    }
2758
0
  fprintf (e, "END\n");
2759
0
}
2760
2761
/* Write out a menu resource.  */
2762
2763
static void
2764
write_rc_menu (FILE *e, const rc_menu *menu, int menuex)
2765
0
{
2766
0
  if (menu->help != 0)
2767
0
    fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
2768
0
  write_rc_menuitems (e, menu->items, menuex, 0);
2769
0
}
2770
2771
static void
2772
write_rc_toolbar (FILE *e, const rc_toolbar *tb)
2773
0
{
2774
0
  rc_toolbar_item *it;
2775
0
  indent (e, 0);
2776
0
  fprintf (e, "BEGIN\n");
2777
0
  it = tb->items;
2778
0
  while(it != NULL)
2779
0
  {
2780
0
    indent (e, 2);
2781
0
    if (it->id.u.id == 0)
2782
0
      fprintf (e, "SEPARATOR\n");
2783
0
    else
2784
0
      fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2785
0
    it = it->next;
2786
0
  }
2787
0
  indent (e, 0);
2788
0
  fprintf (e, "END\n");
2789
0
}
2790
2791
/* Write out menuitems.  */
2792
2793
static void
2794
write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2795
        int ind)
2796
0
{
2797
0
  const rc_menuitem *mi;
2798
2799
0
  indent (e, ind);
2800
0
  fprintf (e, "BEGIN\n");
2801
2802
0
  for (mi = menuitems; mi != NULL; mi = mi->next)
2803
0
    {
2804
0
      indent (e, ind + 2);
2805
2806
0
      if (mi->popup == NULL)
2807
0
  fprintf (e, "MENUITEM");
2808
0
      else
2809
0
  fprintf (e, "POPUP");
2810
2811
0
      if (! menuex
2812
0
    && mi->popup == NULL
2813
0
    && mi->text == NULL
2814
0
    && mi->type == 0
2815
0
    && mi->id == 0)
2816
0
  {
2817
0
    fprintf (e, " SEPARATOR\n");
2818
0
    continue;
2819
0
  }
2820
2821
0
      if (mi->text == NULL)
2822
0
  fprintf (e, " \"\"");
2823
0
      else
2824
0
  {
2825
0
    fprintf (e, " ");
2826
0
    unicode_print_quoted (e, mi->text, -1);
2827
0
  }
2828
2829
0
      if (! menuex)
2830
0
  {
2831
0
    if (mi->popup == NULL)
2832
0
      fprintf (e, ", %d", (int) mi->id);
2833
2834
0
    if ((mi->type & MENUITEM_CHECKED) != 0)
2835
0
      fprintf (e, ", CHECKED");
2836
0
    if ((mi->type & MENUITEM_GRAYED) != 0)
2837
0
      fprintf (e, ", GRAYED");
2838
0
    if ((mi->type & MENUITEM_HELP) != 0)
2839
0
      fprintf (e, ", HELP");
2840
0
    if ((mi->type & MENUITEM_INACTIVE) != 0)
2841
0
      fprintf (e, ", INACTIVE");
2842
0
    if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2843
0
      fprintf (e, ", MENUBARBREAK");
2844
0
    if ((mi->type & MENUITEM_MENUBREAK) != 0)
2845
0
      fprintf (e, ", MENUBREAK");
2846
0
    if ((mi->type & MENUITEM_OWNERDRAW) != 0)
2847
0
      fprintf (e, ", OWNERDRAW");
2848
0
    if ((mi->type & MENUITEM_BITMAP) != 0)
2849
0
      fprintf (e, ", BITMAP");
2850
0
  }
2851
0
      else
2852
0
  {
2853
0
    if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2854
0
      {
2855
0
        fprintf (e, ", %d", (int) mi->id);
2856
0
        if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2857
0
    {
2858
0
      fprintf (e, ", %u", (unsigned int) mi->type);
2859
0
      if (mi->state != 0 || mi->help != 0)
2860
0
        {
2861
0
          fprintf (e, ", %u", (unsigned int) mi->state);
2862
0
          if (mi->help != 0)
2863
0
      fprintf (e, ", %u", (unsigned int) mi->help);
2864
0
        }
2865
0
    }
2866
0
      }
2867
0
  }
2868
2869
0
      fprintf (e, "\n");
2870
2871
0
      if (mi->popup != NULL)
2872
0
  write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2873
0
    }
2874
2875
0
  indent (e, ind);
2876
0
  fprintf (e, "END\n");
2877
0
}
2878
2879
static int
2880
test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2881
0
{
2882
0
  rc_uint_type i;
2883
0
  if ((length & 1) != 0)
2884
0
    return 0;
2885
2886
0
  for (i = 0; i < length; i += 2)
2887
0
    {
2888
0
      if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2889
0
  return 0;
2890
0
      if (data[i] == 0xff && data[i + 1] == 0xff)
2891
0
  return 0;
2892
0
    }
2893
0
  return 1;
2894
0
}
2895
2896
static int
2897
test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2898
0
{
2899
0
  int has_nl;
2900
0
  rc_uint_type c;
2901
0
  rc_uint_type i;
2902
2903
0
  if (length <= 1)
2904
0
    return 0;
2905
2906
0
  has_nl = 0;
2907
0
  for (i = 0, c = 0; i < length; i++)
2908
0
    {
2909
0
      if (! ISPRINT (data[i]) && data[i] != '\n'
2910
0
          && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2911
0
          && data[i] != '\t'
2912
0
    && ! (data[i] == 0 && (i + 1) != length))
2913
0
  {
2914
0
    if (data[i] <= 7)
2915
0
      return 0;
2916
0
    c++;
2917
0
  }
2918
0
      else if (data[i] == '\n') has_nl++;
2919
0
    }
2920
0
  if (length > 80 && ! has_nl)
2921
0
    return 0;
2922
0
  c = (((c * 10000) + (i / 100) - 1)) / i;
2923
0
  if (c >= 150)
2924
0
    return 0;
2925
0
  return 1;
2926
0
}
2927
2928
static void
2929
write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2930
0
{
2931
0
  int has_error = 0;
2932
0
  const struct bin_messagetable *mt;
2933
2934
0
  fprintf (e, "BEGIN\n");
2935
2936
0
  write_rc_datablock (e, length, data, 0, 0, 0);
2937
2938
0
  fprintf (e, "\n");
2939
0
  wr_printcomment (e, "MC syntax dump");
2940
0
  if (length < BIN_MESSAGETABLE_SIZE)
2941
0
    has_error = 1;
2942
0
  else
2943
0
    do
2944
0
      {
2945
0
  rc_uint_type m, i;
2946
2947
0
  mt = (const struct bin_messagetable *) data;
2948
0
  m = windres_get_32 (&wrtarget, mt->cblocks, length);
2949
2950
0
  if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2951
0
    {
2952
0
      has_error = 1;
2953
0
      break;
2954
0
    }
2955
0
  for (i = 0; i < m; i++)
2956
0
    {
2957
0
      rc_uint_type low, high, offset;
2958
0
      const struct bin_messagetable_item *mti;
2959
2960
0
      low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2961
0
      high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2962
0
      offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2963
2964
0
      while (low <= high)
2965
0
        {
2966
0
    rc_uint_type elen, flags;
2967
0
    if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2968
0
      {
2969
0
        has_error = 1;
2970
0
        break;
2971
0
      }
2972
0
    mti = (const struct bin_messagetable_item *) &data[offset];
2973
0
    elen = windres_get_16 (&wrtarget, mti->length, 2);
2974
0
    flags = windres_get_16 (&wrtarget, mti->flags, 2);
2975
0
    if ((offset + elen) > length)
2976
0
      {
2977
0
        has_error = 1;
2978
0
        break;
2979
0
      }
2980
0
    wr_printcomment (e, "MessageId = 0x%x", low);
2981
0
    wr_printcomment (e, "");
2982
2983
0
    if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2984
0
      {
2985
        /* PR 17512: file: 5c3232dc.  */
2986
0
        if (elen > BIN_MESSAGETABLE_ITEM_SIZE * 2)
2987
0
          unicode_print (e, (const unichar *) mti->data,
2988
0
             (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2989
0
      }
2990
0
    else
2991
0
      {
2992
0
        if (elen > BIN_MESSAGETABLE_ITEM_SIZE)
2993
0
          ascii_print (e, (const char *) mti->data,
2994
0
           (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2995
0
      }
2996
2997
0
    wr_printcomment (e,"");
2998
0
    ++low;
2999
0
    offset += elen;
3000
0
        }
3001
0
    }
3002
0
      }
3003
0
    while (0);
3004
3005
0
  if (has_error)
3006
0
    wr_printcomment (e, "Illegal data");
3007
0
  wr_print_flush (e);
3008
0
  fprintf (e, "END\n");
3009
0
}
3010
3011
static void
3012
write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
3013
        int hasblock, int show_comment)
3014
0
{
3015
0
  int plen;
3016
3017
0
  if (hasblock)
3018
0
    fprintf (e, "BEGIN\n");
3019
3020
0
  if (show_comment == -1)
3021
0
    {
3022
0
      if (test_rc_datablock_text(length, data))
3023
0
  {
3024
0
    rc_uint_type i, c;
3025
0
    for (i = 0; i < length;)
3026
0
      {
3027
0
        indent (e, 2);
3028
0
        fprintf (e, "\"");
3029
3030
0
        for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
3031
0
    ;
3032
0
        if (i < length && data[i] == '\n')
3033
0
    ++i, ++c;
3034
0
        ascii_print(e, (const char *) &data[i - c], c);
3035
0
      fprintf (e, "\"");
3036
0
        if (i < length)
3037
0
    fprintf (e, "\n");
3038
0
      }
3039
3040
0
    if (i == 0)
3041
0
        {
3042
0
        indent (e, 2);
3043
0
        fprintf (e, "\"\"");
3044
0
        }
3045
0
    if (has_next)
3046
0
      fprintf (e, ",");
3047
0
    fprintf (e, "\n");
3048
0
    if (hasblock)
3049
0
      fprintf (e, "END\n");
3050
0
    return;
3051
0
    }
3052
0
      if (test_rc_datablock_unicode (length, data))
3053
0
  {
3054
0
    rc_uint_type i, c;
3055
0
    for (i = 0; i < length;)
3056
0
      {
3057
0
        const unichar *u;
3058
3059
0
        u = (const unichar *) &data[i];
3060
0
        indent (e, 2);
3061
0
    fprintf (e, "L\"");
3062
3063
0
        for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3064
0
    ;
3065
0
        if (i < length && u[c] == '\n')
3066
0
    i += 2, ++c;
3067
0
        unicode_print (e, u, c);
3068
0
    fprintf (e, "\"");
3069
0
        if (i < length)
3070
0
    fprintf (e, "\n");
3071
0
      }
3072
3073
0
    if (i == 0)
3074
0
    {
3075
0
        indent (e, 2);
3076
0
        fprintf (e, "L\"\"");
3077
0
      }
3078
0
    if (has_next)
3079
0
      fprintf (e, ",");
3080
0
    fprintf (e, "\n");
3081
0
    if (hasblock)
3082
0
      fprintf (e, "END\n");
3083
0
    return;
3084
0
  }
3085
3086
0
      show_comment = 0;
3087
0
    }
3088
3089
0
  if (length != 0)
3090
0
        {
3091
0
      rc_uint_type i, max_row;
3092
0
      int first = 1;
3093
3094
0
      max_row = (show_comment ? 4 : 8);
3095
0
      indent (e, 2);
3096
0
      for (i = 0; i + 3 < length;)
3097
0
      {
3098
0
    rc_uint_type k;
3099
0
    rc_uint_type comment_start;
3100
3101
0
    comment_start = i;
3102
3103
0
    if (! first)
3104
0
      indent (e, 2);
3105
3106
0
    for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
3107
0
          {
3108
0
        if (k == 0)
3109
0
    plen  = fprintf (e, "0x%lxL",
3110
0
         (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
3111
0
      else
3112
0
    plen = fprintf (e, " 0x%lxL",
3113
0
        (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3114
0
        if (has_next || (i + 4) < length)
3115
0
        {
3116
0
      if (plen>0 && plen < 11)
3117
0
        indent (e, 11 - plen);
3118
0
      fprintf (e, ",");
3119
0
        }
3120
0
          }
3121
0
    if (show_comment)
3122
0
      {
3123
0
        fprintf (e, "\t/* ");
3124
0
        ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3125
0
        fprintf (e, ".  */");
3126
0
      }
3127
0
    fprintf (e, "\n");
3128
0
    first = 0;
3129
0
        }
3130
3131
0
      if (i + 1 < length)
3132
0
        {
3133
0
    if (! first)
3134
0
      indent (e, 2);
3135
0
    plen = fprintf (e, "0x%x",
3136
0
          (int) windres_get_16 (&wrtarget, data + i, length - i));
3137
0
    if (has_next || i + 2 < length)
3138
0
      {
3139
0
        if (plen > 0 && plen < 11)
3140
0
    indent (e, 11 - plen);
3141
0
        fprintf (e, ",");
3142
0
          }
3143
0
    if (show_comment)
3144
0
      {
3145
0
        fprintf (e, "\t/* ");
3146
0
        ascii_print (e, (const char *) &data[i], 2);
3147
0
        fprintf (e, ".  */");
3148
0
      }
3149
0
    fprintf (e, "\n");
3150
0
    i += 2;
3151
0
    first = 0;
3152
0
        }
3153
3154
0
      if (i < length)
3155
0
        {
3156
0
    if (! first)
3157
0
      indent (e, 2);
3158
0
    fprintf (e, "\"");
3159
0
    ascii_print (e, (const char *) &data[i], 1);
3160
0
    fprintf (e, "\"");
3161
0
    if (has_next)
3162
0
      fprintf (e, ",");
3163
0
    fprintf (e, "\n");
3164
0
    first = 0;
3165
0
        }
3166
0
    }
3167
0
  if (hasblock)
3168
0
    fprintf (e, "END\n");
3169
0
}
3170
3171
/* Write out an rcdata resource.  This is also used for other types of
3172
   resources that need to print arbitrary data.  */
3173
3174
static void
3175
write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3176
0
{
3177
0
  const rc_rcdata_item *ri;
3178
3179
0
  indent (e, ind);
3180
0
  fprintf (e, "BEGIN\n");
3181
3182
0
  for (ri = rcdata; ri != NULL; ri = ri->next)
3183
0
    {
3184
0
      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3185
0
  continue;
3186
3187
0
      switch (ri->type)
3188
0
  {
3189
0
  default:
3190
0
    abort ();
3191
3192
0
  case RCDATA_WORD:
3193
0
    indent (e, ind + 2);
3194
0
    fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3195
0
    break;
3196
3197
0
  case RCDATA_DWORD:
3198
0
    indent (e, ind + 2);
3199
0
    fprintf (e, "%luL", (unsigned long) ri->u.dword);
3200
0
    break;
3201
3202
0
  case RCDATA_STRING:
3203
0
    indent (e, ind + 2);
3204
0
    fprintf (e, "\"");
3205
0
    ascii_print (e, ri->u.string.s, ri->u.string.length);
3206
0
    fprintf (e, "\"");
3207
0
    break;
3208
3209
0
  case RCDATA_WSTRING:
3210
0
    indent (e, ind + 2);
3211
0
    fprintf (e, "L\"");
3212
0
    unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3213
0
    fprintf (e, "\"");
3214
0
    break;
3215
3216
0
  case RCDATA_BUFFER:
3217
0
    write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3218
0
              (const bfd_byte *) ri->u.buffer.data,
3219
0
                ri->next != NULL, 0, -1);
3220
0
      break;
3221
0
  }
3222
3223
0
      if (ri->type != RCDATA_BUFFER)
3224
0
  {
3225
0
    if (ri->next != NULL)
3226
0
      fprintf (e, ",");
3227
0
    fprintf (e, "\n");
3228
0
  }
3229
0
    }
3230
3231
0
  indent (e, ind);
3232
0
  fprintf (e, "END\n");
3233
0
}
3234
3235
/* Write out a stringtable resource.  */
3236
3237
static void
3238
write_rc_stringtable (FILE *e, const rc_res_id *name,
3239
          const rc_stringtable *stringtable)
3240
0
{
3241
0
  rc_uint_type offset;
3242
0
  int i;
3243
3244
0
  if (name != NULL && ! name->named)
3245
0
    offset = (name->u.id - 1) << 4;
3246
0
  else
3247
0
    {
3248
0
      fprintf (e, "/* %s string table name.  */\n",
3249
0
         name == NULL ? "Missing" : "Invalid");
3250
0
      offset = 0;
3251
0
    }
3252
3253
0
  fprintf (e, "BEGIN\n");
3254
3255
0
  for (i = 0; i < 16; i++)
3256
0
    {
3257
0
      if (stringtable->strings[i].length != 0)
3258
0
  {
3259
0
    fprintf (e, "  %lu, ", (unsigned long) offset + i);
3260
0
    unicode_print_quoted (e, stringtable->strings[i].string,
3261
0
       stringtable->strings[i].length);
3262
0
    fprintf (e, "\n");
3263
0
  }
3264
0
    }
3265
3266
0
  fprintf (e, "END\n");
3267
0
}
3268
3269
/* Write out a versioninfo resource.  */
3270
3271
static void
3272
write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3273
0
{
3274
0
  const rc_fixed_versioninfo *f;
3275
0
  const rc_ver_info *vi;
3276
3277
0
  f = versioninfo->fixed;
3278
0
  if (f->file_version_ms != 0 || f->file_version_ls != 0)
3279
0
    fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3280
0
       (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3281
0
       (unsigned int) (f->file_version_ms & 0xffff),
3282
0
       (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3283
0
       (unsigned int) (f->file_version_ls & 0xffff));
3284
0
  if (f->product_version_ms != 0 || f->product_version_ls != 0)
3285
0
    fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3286
0
       (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3287
0
       (unsigned int) (f->product_version_ms & 0xffff),
3288
0
       (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3289
0
       (unsigned int) (f->product_version_ls & 0xffff));
3290
0
  if (f->file_flags_mask != 0)
3291
0
    fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3292
0
  if (f->file_flags != 0)
3293
0
    fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3294
0
  if (f->file_os != 0)
3295
0
    fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3296
0
  if (f->file_type != 0)
3297
0
    fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3298
0
  if (f->file_subtype != 0)
3299
0
    fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3300
0
  if (f->file_date_ms != 0 || f->file_date_ls != 0)
3301
0
    fprintf (e, "/* Date: %u, %u.  */\n",
3302
0
           (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3303
3304
0
  fprintf (e, "BEGIN\n");
3305
3306
0
  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3307
0
    {
3308
0
      switch (vi->type)
3309
0
  {
3310
0
  case VERINFO_STRING:
3311
0
    {
3312
0
      const rc_ver_stringtable *vst;
3313
0
      const rc_ver_stringinfo *vs;
3314
3315
0
      fprintf (e, "  BLOCK \"StringFileInfo\"\n");
3316
0
      fprintf (e, "  BEGIN\n");
3317
3318
0
      for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
3319
0
        {
3320
0
    fprintf (e, "    BLOCK ");
3321
0
    unicode_print_quoted (e, vst->language, -1);
3322
3323
0
    fprintf (e, "\n");
3324
0
    fprintf (e, "    BEGIN\n");
3325
3326
0
    for (vs = vst->strings; vs != NULL; vs = vs->next)
3327
0
      {
3328
0
        fprintf (e, "      VALUE ");
3329
0
        unicode_print_quoted (e, vs->key, -1);
3330
0
        fprintf (e, ", ");
3331
0
        unicode_print_quoted (e, vs->value, -1);
3332
0
        fprintf (e, "\n");
3333
0
      }
3334
3335
0
    fprintf (e, "    END\n");
3336
0
        }
3337
0
      fprintf (e, "  END\n");
3338
0
      break;
3339
0
    }
3340
3341
0
  case VERINFO_VAR:
3342
0
    {
3343
0
      const rc_ver_varinfo *vv;
3344
3345
0
      fprintf (e, "  BLOCK \"VarFileInfo\"\n");
3346
0
      fprintf (e, "  BEGIN\n");
3347
0
      fprintf (e, "    VALUE ");
3348
0
      unicode_print_quoted (e, vi->u.var.key, -1);
3349
3350
0
      for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3351
0
        fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3352
0
           (int) vv->charset);
3353
3354
0
      fprintf (e, "\n  END\n");
3355
3356
0
      break;
3357
0
    }
3358
0
  }
3359
0
    }
3360
3361
0
  fprintf (e, "END\n");
3362
0
}
3363
3364
static rc_uint_type
3365
rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3366
0
{
3367
0
  if (! src)
3368
0
    return 0;
3369
0
  switch (src->type)
3370
0
  {
3371
0
    case RCDATA_WORD:
3372
0
      if (dst)
3373
0
  windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3374
0
      return 2;
3375
0
    case RCDATA_DWORD:
3376
0
      if (dst)
3377
0
  windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3378
0
      return 4;
3379
0
    case RCDATA_STRING:
3380
0
      if (dst && src->u.string.length)
3381
0
  memcpy (dst, src->u.string.s, src->u.string.length);
3382
0
      return (rc_uint_type) src->u.string.length;
3383
0
    case RCDATA_WSTRING:
3384
0
      if (dst && src->u.wstring.length)
3385
0
  memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3386
0
      return (rc_uint_type) (src->u.wstring.length  * sizeof (unichar));
3387
0
    case RCDATA_BUFFER:
3388
0
      if (dst && src->u.buffer.length)
3389
0
  memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3390
0
      return (rc_uint_type) src->u.buffer.length;
3391
0
    default:
3392
0
      abort ();
3393
0
    }
3394
  /* Never reached.  */
3395
0
  return 0;
3396
0
}