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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [binutils-2.18.50/] [binutils/] [resrc.c] - Blame information for rev 297

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

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

powered by: WebSVN 2.1.0

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