OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [binutils/] [resrc.c] - Blame information for rev 54

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.