Coverage Report

Created: 2025-07-08 11:15

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