PageRenderTime 60ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/freebsd/contrib/binutils/binutils/resrc.c

https://bitbucket.org/killerpenguinassassins/open_distrib_devel
C | 1987 lines | 1891 code | 44 blank | 52 comment | 24 complexity | 07ff8350f237a6b91627bc270b7253d2 MD5 | raw file
Possible License(s): CC0-1.0, MIT, LGPL-2.0, LGPL-3.0, WTFPL, GPL-2.0, BSD-2-Clause, AGPL-3.0, CC-BY-SA-3.0, MPL-2.0, JSON, BSD-3-Clause-No-Nuclear-License-2014, LGPL-2.1, CPL-1.0, AGPL-1.0, 0BSD, ISC, Apache-2.0, GPL-3.0, IPL-1.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* 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. This file is part of GNU Binutils.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
  18. 02110-1301, USA. */
  19. /* This file contains functions that read and write Windows rc files.
  20. These are text files that represent resources. */
  21. #include "sysdep.h"
  22. #include "bfd.h"
  23. #include "bucomm.h"
  24. #include "libiberty.h"
  25. #include "safe-ctype.h"
  26. #include "windres.h"
  27. #include <assert.h>
  28. #include <errno.h>
  29. #include <sys/stat.h>
  30. #ifdef HAVE_UNISTD_H
  31. #include <unistd.h>
  32. #endif
  33. #ifdef HAVE_SYS_WAIT_H
  34. #include <sys/wait.h>
  35. #else /* ! HAVE_SYS_WAIT_H */
  36. #if ! defined (_WIN32) || defined (__CYGWIN__)
  37. #ifndef WIFEXITED
  38. #define WIFEXITED(w) (((w)&0377) == 0)
  39. #endif
  40. #ifndef WIFSIGNALED
  41. #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
  42. #endif
  43. #ifndef WTERMSIG
  44. #define WTERMSIG(w) ((w) & 0177)
  45. #endif
  46. #ifndef WEXITSTATUS
  47. #define WEXITSTATUS(w) (((w) >> 8) & 0377)
  48. #endif
  49. #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
  50. #ifndef WIFEXITED
  51. #define WIFEXITED(w) (((w) & 0xff) == 0)
  52. #endif
  53. #ifndef WIFSIGNALED
  54. #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
  55. #endif
  56. #ifndef WTERMSIG
  57. #define WTERMSIG(w) ((w) & 0x7f)
  58. #endif
  59. #ifndef WEXITSTATUS
  60. #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
  61. #endif
  62. #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
  63. #endif /* ! HAVE_SYS_WAIT_H */
  64. #ifndef STDOUT_FILENO
  65. #define STDOUT_FILENO 1
  66. #endif
  67. #if defined (_WIN32) && ! defined (__CYGWIN__)
  68. #define popen _popen
  69. #define pclose _pclose
  70. #endif
  71. /* The default preprocessor. */
  72. #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
  73. /* We read the directory entries in a cursor or icon file into
  74. instances of this structure. */
  75. struct icondir
  76. {
  77. /* Width of image. */
  78. bfd_byte width;
  79. /* Height of image. */
  80. bfd_byte height;
  81. /* Number of colors in image. */
  82. bfd_byte colorcount;
  83. union
  84. {
  85. struct
  86. {
  87. /* Color planes. */
  88. unsigned short planes;
  89. /* Bits per pixel. */
  90. unsigned short bits;
  91. } icon;
  92. struct
  93. {
  94. /* X coordinate of hotspot. */
  95. unsigned short xhotspot;
  96. /* Y coordinate of hotspot. */
  97. unsigned short yhotspot;
  98. } cursor;
  99. } u;
  100. /* Bytes in image. */
  101. unsigned long bytes;
  102. /* File offset of image. */
  103. unsigned long offset;
  104. };
  105. /* The name of the rc file we are reading. */
  106. char *rc_filename;
  107. /* The line number in the rc file. */
  108. int rc_lineno;
  109. /* The pipe we are reading from, so that we can close it if we exit. */
  110. FILE *cpp_pipe;
  111. /* The temporary file used if we're not using popen, so we can delete it
  112. if we exit. */
  113. static char *cpp_temp_file;
  114. /* Input stream is either a file or a pipe. */
  115. static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
  116. /* As we read the rc file, we attach information to this structure. */
  117. static rc_res_directory *resources;
  118. /* The number of cursor resources we have written out. */
  119. static int cursors;
  120. /* The number of font resources we have written out. */
  121. static int fonts;
  122. /* Font directory information. */
  123. rc_fontdir *fontdirs;
  124. /* Resource info to use for fontdirs. */
  125. rc_res_res_info fontdirs_resinfo;
  126. /* The number of icon resources we have written out. */
  127. static int icons;
  128. /* The windres target bfd . */
  129. static windres_bfd wrtarget =
  130. {
  131. (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
  132. };
  133. /* Local functions for rcdata based resource definitions. */
  134. static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
  135. rc_rcdata_item *);
  136. static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
  137. rc_rcdata_item *);
  138. static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
  139. rc_rcdata_item *);
  140. static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
  141. rc_rcdata_item *);
  142. static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
  143. rc_rcdata_item *);
  144. static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
  145. rc_rcdata_item *);
  146. static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
  147. static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
  148. static int run_cmd (char *, const char *);
  149. static FILE *open_input_stream (char *);
  150. static FILE *look_for_default
  151. (char *, const char *, int, const char *, const char *);
  152. static void close_input_stream (void);
  153. static void unexpected_eof (const char *);
  154. static int get_word (FILE *, const char *);
  155. static unsigned long get_long (FILE *, const char *);
  156. static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
  157. static void define_fontdirs (void);
  158. /* Run `cmd' and redirect the output to `redir'. */
  159. static int
  160. run_cmd (char *cmd, const char *redir)
  161. {
  162. char *s;
  163. int pid, wait_status, retcode;
  164. int i;
  165. const char **argv;
  166. char *errmsg_fmt, *errmsg_arg;
  167. char *temp_base = choose_temp_base ();
  168. int in_quote;
  169. char sep;
  170. int redir_handle = -1;
  171. int stdout_save = -1;
  172. /* Count the args. */
  173. i = 0;
  174. for (s = cmd; *s; s++)
  175. if (*s == ' ')
  176. i++;
  177. i++;
  178. argv = alloca (sizeof (char *) * (i + 3));
  179. i = 0;
  180. s = cmd;
  181. while (1)
  182. {
  183. while (*s == ' ' && *s != 0)
  184. s++;
  185. if (*s == 0)
  186. break;
  187. in_quote = (*s == '\'' || *s == '"');
  188. sep = (in_quote) ? *s++ : ' ';
  189. argv[i++] = s;
  190. while (*s != sep && *s != 0)
  191. s++;
  192. if (*s == 0)
  193. break;
  194. *s++ = 0;
  195. if (in_quote)
  196. s++;
  197. }
  198. argv[i++] = NULL;
  199. /* Setup the redirection. We can't use the usual fork/exec and redirect
  200. since we may be running on non-POSIX Windows host. */
  201. fflush (stdout);
  202. fflush (stderr);
  203. /* Open temporary output file. */
  204. redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
  205. if (redir_handle == -1)
  206. fatal (_("can't open temporary file `%s': %s"), redir,
  207. strerror (errno));
  208. /* Duplicate the stdout file handle so it can be restored later. */
  209. stdout_save = dup (STDOUT_FILENO);
  210. if (stdout_save == -1)
  211. fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
  212. /* Redirect stdout to our output file. */
  213. dup2 (redir_handle, STDOUT_FILENO);
  214. pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
  215. &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
  216. /* Restore stdout to its previous setting. */
  217. dup2 (stdout_save, STDOUT_FILENO);
  218. /* Close response file. */
  219. close (redir_handle);
  220. if (pid == -1)
  221. {
  222. fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
  223. return 1;
  224. }
  225. retcode = 0;
  226. pid = pwait (pid, &wait_status, 0);
  227. if (pid == -1)
  228. {
  229. fatal (_("wait: %s"), strerror (errno));
  230. retcode = 1;
  231. }
  232. else if (WIFSIGNALED (wait_status))
  233. {
  234. fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
  235. retcode = 1;
  236. }
  237. else if (WIFEXITED (wait_status))
  238. {
  239. if (WEXITSTATUS (wait_status) != 0)
  240. {
  241. fatal (_("%s exited with status %d"), cmd,
  242. WEXITSTATUS (wait_status));
  243. retcode = 1;
  244. }
  245. }
  246. else
  247. retcode = 1;
  248. return retcode;
  249. }
  250. static FILE *
  251. open_input_stream (char *cmd)
  252. {
  253. if (istream_type == ISTREAM_FILE)
  254. {
  255. char *fileprefix;
  256. fileprefix = choose_temp_base ();
  257. cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
  258. sprintf (cpp_temp_file, "%s.irc", fileprefix);
  259. free (fileprefix);
  260. if (run_cmd (cmd, cpp_temp_file))
  261. fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
  262. cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
  263. if (cpp_pipe == NULL)
  264. fatal (_("can't open temporary file `%s': %s"),
  265. cpp_temp_file, strerror (errno));
  266. if (verbose)
  267. fprintf (stderr,
  268. _("Using temporary file `%s' to read preprocessor output\n"),
  269. cpp_temp_file);
  270. }
  271. else
  272. {
  273. cpp_pipe = popen (cmd, FOPEN_RT);
  274. if (cpp_pipe == NULL)
  275. fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
  276. if (verbose)
  277. fprintf (stderr, _("Using popen to read preprocessor output\n"));
  278. }
  279. xatexit (close_input_stream);
  280. return cpp_pipe;
  281. }
  282. /* Determine if FILENAME contains special characters that
  283. can cause problems unless the entire filename is quoted. */
  284. static int
  285. filename_need_quotes (const char *filename)
  286. {
  287. if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
  288. return 0;
  289. while (*filename != 0)
  290. {
  291. switch (*filename)
  292. {
  293. case '&':
  294. case ' ':
  295. case '<':
  296. case '>':
  297. case '|':
  298. case '%':
  299. return 1;
  300. }
  301. ++filename;
  302. }
  303. return 0;
  304. }
  305. /* Look for the preprocessor program. */
  306. static FILE *
  307. look_for_default (char *cmd, const char *prefix, int end_prefix,
  308. const char *preprocargs, const char *filename)
  309. {
  310. char *space;
  311. int found;
  312. struct stat s;
  313. const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
  314. strcpy (cmd, prefix);
  315. sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
  316. space = strchr (cmd + end_prefix, ' ');
  317. if (space)
  318. *space = 0;
  319. if (
  320. #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
  321. strchr (cmd, '\\') ||
  322. #endif
  323. strchr (cmd, '/'))
  324. {
  325. found = (stat (cmd, &s) == 0
  326. #ifdef HAVE_EXECUTABLE_SUFFIX
  327. || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
  328. #endif
  329. );
  330. if (! found)
  331. {
  332. if (verbose)
  333. fprintf (stderr, _("Tried `%s'\n"), cmd);
  334. return NULL;
  335. }
  336. }
  337. strcpy (cmd, prefix);
  338. sprintf (cmd + end_prefix, "%s %s %s%s%s",
  339. DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
  340. if (verbose)
  341. fprintf (stderr, _("Using `%s'\n"), cmd);
  342. cpp_pipe = open_input_stream (cmd);
  343. return cpp_pipe;
  344. }
  345. /* Read an rc file. */
  346. rc_res_directory *
  347. read_rc_file (const char *filename, const char *preprocessor,
  348. const char *preprocargs, int language, int use_temp_file)
  349. {
  350. char *cmd;
  351. const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
  352. istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
  353. if (preprocargs == NULL)
  354. preprocargs = "";
  355. if (filename == NULL)
  356. filename = "-";
  357. if (preprocessor)
  358. {
  359. cmd = xmalloc (strlen (preprocessor)
  360. + strlen (preprocargs)
  361. + strlen (filename)
  362. + strlen (fnquotes) * 2
  363. + 10);
  364. sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
  365. fnquotes, filename, fnquotes);
  366. cpp_pipe = open_input_stream (cmd);
  367. }
  368. else
  369. {
  370. char *dash, *slash, *cp;
  371. preprocessor = DEFAULT_PREPROCESSOR;
  372. cmd = xmalloc (strlen (program_name)
  373. + strlen (preprocessor)
  374. + strlen (preprocargs)
  375. + strlen (filename)
  376. + strlen (fnquotes) * 2
  377. #ifdef HAVE_EXECUTABLE_SUFFIX
  378. + strlen (EXECUTABLE_SUFFIX)
  379. #endif
  380. + 10);
  381. dash = slash = 0;
  382. for (cp = program_name; *cp; cp++)
  383. {
  384. if (*cp == '-')
  385. dash = cp;
  386. if (
  387. #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
  388. *cp == ':' || *cp == '\\' ||
  389. #endif
  390. *cp == '/')
  391. {
  392. slash = cp;
  393. dash = 0;
  394. }
  395. }
  396. cpp_pipe = 0;
  397. if (dash)
  398. {
  399. /* First, try looking for a prefixed gcc in the windres
  400. directory, with the same prefix as windres */
  401. cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
  402. preprocargs, filename);
  403. }
  404. if (slash && ! cpp_pipe)
  405. {
  406. /* Next, try looking for a gcc in the same directory as
  407. that windres */
  408. cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
  409. preprocargs, filename);
  410. }
  411. if (! cpp_pipe)
  412. {
  413. /* Sigh, try the default */
  414. cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
  415. }
  416. }
  417. free (cmd);
  418. rc_filename = xstrdup (filename);
  419. rc_lineno = 1;
  420. if (language != -1)
  421. rcparse_set_language (language);
  422. yyparse ();
  423. rcparse_discard_strings ();
  424. close_input_stream ();
  425. if (fontdirs != NULL)
  426. define_fontdirs ();
  427. free (rc_filename);
  428. rc_filename = NULL;
  429. return resources;
  430. }
  431. /* Close the input stream if it is open. */
  432. static void
  433. close_input_stream (void)
  434. {
  435. if (istream_type == ISTREAM_FILE)
  436. {
  437. if (cpp_pipe != NULL)
  438. fclose (cpp_pipe);
  439. if (cpp_temp_file != NULL)
  440. {
  441. int errno_save = errno;
  442. unlink (cpp_temp_file);
  443. errno = errno_save;
  444. free (cpp_temp_file);
  445. }
  446. }
  447. else
  448. {
  449. if (cpp_pipe != NULL)
  450. pclose (cpp_pipe);
  451. }
  452. /* Since this is also run via xatexit, safeguard. */
  453. cpp_pipe = NULL;
  454. cpp_temp_file = NULL;
  455. }
  456. /* Report an error while reading an rc file. */
  457. void
  458. yyerror (const char *msg)
  459. {
  460. fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
  461. }
  462. /* Issue a warning while reading an rc file. */
  463. void
  464. rcparse_warning (const char *msg)
  465. {
  466. fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
  467. }
  468. /* Die if we get an unexpected end of file. */
  469. static void
  470. unexpected_eof (const char *msg)
  471. {
  472. fatal (_("%s: unexpected EOF"), msg);
  473. }
  474. /* Read a 16 bit word from a file. The data is assumed to be little
  475. endian. */
  476. static int
  477. get_word (FILE *e, const char *msg)
  478. {
  479. int b1, b2;
  480. b1 = getc (e);
  481. b2 = getc (e);
  482. if (feof (e))
  483. unexpected_eof (msg);
  484. return ((b2 & 0xff) << 8) | (b1 & 0xff);
  485. }
  486. /* Read a 32 bit word from a file. The data is assumed to be little
  487. endian. */
  488. static unsigned long
  489. get_long (FILE *e, const char *msg)
  490. {
  491. int b1, b2, b3, b4;
  492. b1 = getc (e);
  493. b2 = getc (e);
  494. b3 = getc (e);
  495. b4 = getc (e);
  496. if (feof (e))
  497. unexpected_eof (msg);
  498. return (((((((b4 & 0xff) << 8)
  499. | (b3 & 0xff)) << 8)
  500. | (b2 & 0xff)) << 8)
  501. | (b1 & 0xff));
  502. }
  503. /* Read data from a file. This is a wrapper to do error checking. */
  504. static void
  505. get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
  506. {
  507. rc_uint_type got; // $$$d
  508. got = (rc_uint_type) fread (p, 1, c, e);
  509. if (got == c)
  510. return;
  511. fatal (_("%s: read of %lu returned %lu"), msg, (long) c, (long) got);
  512. }
  513. /* Define an accelerator resource. */
  514. void
  515. define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
  516. rc_accelerator *data)
  517. {
  518. rc_res_resource *r;
  519. r = define_standard_resource (&resources, RT_ACCELERATOR, id,
  520. resinfo->language, 0);
  521. r->type = RES_TYPE_ACCELERATOR;
  522. r->u.acc = data;
  523. r->res_info = *resinfo;
  524. }
  525. /* Define a bitmap resource. Bitmap data is stored in a file. The
  526. first 14 bytes of the file are a standard header, which is not
  527. included in the resource data. */
  528. #define BITMAP_SKIP (14)
  529. void
  530. define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
  531. const char *filename)
  532. {
  533. FILE *e;
  534. char *real_filename;
  535. struct stat s;
  536. bfd_byte *data;
  537. rc_uint_type i;
  538. rc_res_resource *r;
  539. e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
  540. if (stat (real_filename, &s) < 0)
  541. fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
  542. strerror (errno));
  543. data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
  544. for (i = 0; i < BITMAP_SKIP; i++)
  545. getc (e);
  546. get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
  547. fclose (e);
  548. free (real_filename);
  549. r = define_standard_resource (&resources, RT_BITMAP, id,
  550. resinfo->language, 0);
  551. r->type = RES_TYPE_BITMAP;
  552. r->u.data.length = s.st_size - BITMAP_SKIP;
  553. r->u.data.data = data;
  554. r->res_info = *resinfo;
  555. }
  556. /* Define a cursor resource. A cursor file may contain a set of
  557. bitmaps, each representing the same cursor at various different
  558. resolutions. They each get written out with a different ID. The
  559. real cursor resource is then a group resource which can be used to
  560. select one of the actual cursors. */
  561. void
  562. define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
  563. const char *filename)
  564. {
  565. FILE *e;
  566. char *real_filename;
  567. int type, count, i;
  568. struct icondir *icondirs;
  569. int first_cursor;
  570. rc_res_resource *r;
  571. rc_group_cursor *first, **pp;
  572. e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
  573. /* A cursor file is basically an icon file. The start of the file
  574. is a three word structure. The first word is ignored. The
  575. second word is the type of data. The third word is the number of
  576. entries. */
  577. get_word (e, real_filename);
  578. type = get_word (e, real_filename);
  579. count = get_word (e, real_filename);
  580. if (type != 2)
  581. fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
  582. /* Read in the icon directory entries. */
  583. icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
  584. for (i = 0; i < count; i++)
  585. {
  586. icondirs[i].width = getc (e);
  587. icondirs[i].height = getc (e);
  588. icondirs[i].colorcount = getc (e);
  589. getc (e);
  590. icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
  591. icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
  592. icondirs[i].bytes = get_long (e, real_filename);
  593. icondirs[i].offset = get_long (e, real_filename);
  594. if (feof (e))
  595. unexpected_eof (real_filename);
  596. }
  597. /* Define each cursor as a unique resource. */
  598. first_cursor = cursors;
  599. for (i = 0; i < count; i++)
  600. {
  601. bfd_byte *data;
  602. rc_res_id name;
  603. rc_cursor *c;
  604. if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
  605. fatal (_("%s: fseek to %lu failed: %s"), real_filename,
  606. icondirs[i].offset, strerror (errno));
  607. data = (bfd_byte *) res_alloc (icondirs[i].bytes);
  608. get_data (e, data, icondirs[i].bytes, real_filename);
  609. c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
  610. c->xhotspot = icondirs[i].u.cursor.xhotspot;
  611. c->yhotspot = icondirs[i].u.cursor.yhotspot;
  612. c->length = icondirs[i].bytes;
  613. c->data = data;
  614. ++cursors;
  615. name.named = 0;
  616. name.u.id = cursors;
  617. r = define_standard_resource (&resources, RT_CURSOR, name,
  618. resinfo->language, 0);
  619. r->type = RES_TYPE_CURSOR;
  620. r->u.cursor = c;
  621. r->res_info = *resinfo;
  622. }
  623. fclose (e);
  624. free (real_filename);
  625. /* Define a cursor group resource. */
  626. first = NULL;
  627. pp = &first;
  628. for (i = 0; i < count; i++)
  629. {
  630. rc_group_cursor *cg;
  631. cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
  632. cg->next = NULL;
  633. cg->width = icondirs[i].width;
  634. cg->height = 2 * icondirs[i].height;
  635. /* FIXME: What should these be set to? */
  636. cg->planes = 1;
  637. cg->bits = 1;
  638. cg->bytes = icondirs[i].bytes + 4;
  639. cg->index = first_cursor + i + 1;
  640. *pp = cg;
  641. pp = &(*pp)->next;
  642. }
  643. free (icondirs);
  644. r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
  645. resinfo->language, 0);
  646. r->type = RES_TYPE_GROUP_CURSOR;
  647. r->u.group_cursor = first;
  648. r->res_info = *resinfo;
  649. }
  650. /* Define a dialog resource. */
  651. void
  652. define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
  653. const rc_dialog *dialog)
  654. {
  655. rc_dialog *copy;
  656. rc_res_resource *r;
  657. copy = (rc_dialog *) res_alloc (sizeof *copy);
  658. *copy = *dialog;
  659. r = define_standard_resource (&resources, RT_DIALOG, id,
  660. resinfo->language, 0);
  661. r->type = RES_TYPE_DIALOG;
  662. r->u.dialog = copy;
  663. r->res_info = *resinfo;
  664. }
  665. /* Define a dialog control. This does not define a resource, but
  666. merely allocates and fills in a structure. */
  667. rc_dialog_control *
  668. define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
  669. rc_uint_type y, rc_uint_type width, rc_uint_type height,
  670. const rc_res_id class, rc_uint_type style,
  671. rc_uint_type exstyle)
  672. {
  673. rc_dialog_control *n;
  674. n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
  675. n->next = NULL;
  676. n->id = id;
  677. n->style = style;
  678. n->exstyle = exstyle;
  679. n->x = x;
  680. n->y = y;
  681. n->width = width;
  682. n->height = height;
  683. n->class = class;
  684. n->text = iid;
  685. n->data = NULL;
  686. n->help = 0;
  687. return n;
  688. }
  689. rc_dialog_control *
  690. define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
  691. rc_uint_type y, rc_uint_type style,
  692. rc_uint_type exstyle, rc_uint_type help,
  693. rc_rcdata_item *data, rc_dialog_ex *ex)
  694. {
  695. rc_dialog_control *n;
  696. rc_res_id tid;
  697. rc_res_id cid;
  698. if (style == 0)
  699. style = SS_ICON | WS_CHILD | WS_VISIBLE;
  700. res_string_to_id (&tid, "");
  701. cid.named = 0;
  702. cid.u.id = CTL_STATIC;
  703. n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
  704. n->text = iid;
  705. if (help && ! ex)
  706. rcparse_warning (_("help ID requires DIALOGEX"));
  707. if (data && ! ex)
  708. rcparse_warning (_("control data requires DIALOGEX"));
  709. n->help = help;
  710. n->data = data;
  711. return n;
  712. }
  713. /* Define a font resource. */
  714. void
  715. define_font (rc_res_id id, const rc_res_res_info *resinfo,
  716. const char *filename)
  717. {
  718. FILE *e;
  719. char *real_filename;
  720. struct stat s;
  721. bfd_byte *data;
  722. rc_res_resource *r;
  723. long offset;
  724. long fontdatalength;
  725. bfd_byte *fontdata;
  726. rc_fontdir *fd;
  727. const char *device, *face;
  728. rc_fontdir **pp;
  729. e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
  730. if (stat (real_filename, &s) < 0)
  731. fatal (_("stat failed on font file `%s': %s"), real_filename,
  732. strerror (errno));
  733. data = (bfd_byte *) res_alloc (s.st_size);
  734. get_data (e, data, s.st_size, real_filename);
  735. fclose (e);
  736. free (real_filename);
  737. r = define_standard_resource (&resources, RT_FONT, id,
  738. resinfo->language, 0);
  739. r->type = RES_TYPE_FONT;
  740. r->u.data.length = s.st_size;
  741. r->u.data.data = data;
  742. r->res_info = *resinfo;
  743. /* For each font resource, we must add an entry in the FONTDIR
  744. resource. The FONTDIR resource includes some strings in the font
  745. file. To find them, we have to do some magic on the data we have
  746. read. */
  747. offset = ((((((data[47] << 8)
  748. | data[46]) << 8)
  749. | data[45]) << 8)
  750. | data[44]);
  751. if (offset > 0 && offset < s.st_size)
  752. device = (char *) data + offset;
  753. else
  754. device = "";
  755. offset = ((((((data[51] << 8)
  756. | data[50]) << 8)
  757. | data[49]) << 8)
  758. | data[48]);
  759. if (offset > 0 && offset < s.st_size)
  760. face = (char *) data + offset;
  761. else
  762. face = "";
  763. ++fonts;
  764. fontdatalength = 58 + strlen (device) + strlen (face);
  765. fontdata = (bfd_byte *) res_alloc (fontdatalength);
  766. memcpy (fontdata, data, 56);
  767. strcpy ((char *) fontdata + 56, device);
  768. strcpy ((char *) fontdata + 57 + strlen (device), face);
  769. fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
  770. fd->next = NULL;
  771. fd->index = fonts;
  772. fd->length = fontdatalength;
  773. fd->data = fontdata;
  774. for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
  775. ;
  776. *pp = fd;
  777. /* For the single fontdirs resource, we always use the resource
  778. information of the last font. I don't know what else to do. */
  779. fontdirs_resinfo = *resinfo;
  780. }
  781. static void
  782. define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
  783. rc_rcdata_item *data)
  784. {
  785. rc_res_resource *r;
  786. rc_uint_type len_data;
  787. bfd_byte *pb_data;
  788. r = define_standard_resource (&resources, RT_FONT, id,
  789. resinfo->language, 0);
  790. pb_data = rcdata_render_as_buffer (data, &len_data);
  791. r->type = RES_TYPE_FONT;
  792. r->u.data.length = len_data;
  793. r->u.data.data = pb_data;
  794. r->res_info = *resinfo;
  795. }
  796. /* Define the fontdirs resource. This is called after the entire rc
  797. file has been parsed, if any font resources were seen. */
  798. static void
  799. define_fontdirs (void)
  800. {
  801. rc_res_resource *r;
  802. rc_res_id id;
  803. id.named = 0;
  804. id.u.id = 1;
  805. r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
  806. r->type = RES_TYPE_FONTDIR;
  807. r->u.fontdir = fontdirs;
  808. r->res_info = fontdirs_resinfo;
  809. }
  810. static bfd_byte *
  811. rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
  812. {
  813. const rc_rcdata_item *d;
  814. bfd_byte *ret = NULL, *pret;
  815. rc_uint_type len = 0;
  816. for (d = data; d != NULL; d = d->next)
  817. len += rcdata_copy (d, NULL);
  818. if (len != 0)
  819. {
  820. ret = pret = (bfd_byte *) res_alloc (len);
  821. for (d = data; d != NULL; d = d->next)
  822. pret += rcdata_copy (d, pret);
  823. }
  824. if (plen)
  825. *plen = len;
  826. return ret;
  827. }
  828. static void
  829. define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
  830. rc_rcdata_item *data)
  831. {
  832. rc_res_resource *r;
  833. rc_fontdir *fd, *fd_first, *fd_cur;
  834. rc_uint_type len_data;
  835. bfd_byte *pb_data;
  836. rc_uint_type c;
  837. fd_cur = fd_first = NULL;
  838. r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
  839. pb_data = rcdata_render_as_buffer (data, &len_data);
  840. if (pb_data)
  841. {
  842. rc_uint_type off = 2;
  843. c = windres_get_16 (&wrtarget, pb_data, len_data);
  844. for (; c > 0; c--)
  845. {
  846. size_t len;
  847. rc_uint_type safe_pos = off;
  848. const struct bin_fontdir_item *bfi;
  849. bfi = (const struct bin_fontdir_item *) pb_data + off;
  850. fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
  851. fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
  852. fd->data = pb_data + off;
  853. off += 56;
  854. len = strlen ((char *) bfi->device_name) + 1;
  855. off += (rc_uint_type) len;
  856. off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
  857. fd->length = (off - safe_pos);
  858. fd->next = NULL;
  859. if (fd_first == NULL)
  860. fd_first = fd;
  861. else
  862. fd_cur->next = fd;
  863. fd_cur = fd;
  864. }
  865. }
  866. r->type = RES_TYPE_FONTDIR;
  867. r->u.fontdir = fd_first;
  868. r->res_info = *resinfo;
  869. }
  870. static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
  871. rc_rcdata_item *data)
  872. {
  873. rc_res_resource *r;
  874. rc_uint_type len_data;
  875. bfd_byte *pb_data;
  876. r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
  877. pb_data = rcdata_render_as_buffer (data, &len_data);
  878. r->type = RES_TYPE_MESSAGETABLE;
  879. r->u.data.length = len_data;
  880. r->u.data.data = pb_data;
  881. r->res_info = *resinfo;
  882. }
  883. /* Define an icon resource. An icon file may contain a set of
  884. bitmaps, each representing the same icon at various different
  885. resolutions. They each get written out with a different ID. The
  886. real icon resource is then a group resource which can be used to
  887. select one of the actual icon bitmaps. */
  888. void
  889. define_icon (rc_res_id id, const rc_res_res_info *resinfo,
  890. const char *filename)
  891. {
  892. FILE *e;
  893. char *real_filename;
  894. int type, count, i;
  895. struct icondir *icondirs;
  896. int first_icon;
  897. rc_res_resource *r;
  898. rc_group_icon *first, **pp;
  899. e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
  900. /* The start of an icon file is a three word structure. The first
  901. word is ignored. The second word is the type of data. The third
  902. word is the number of entries. */
  903. get_word (e, real_filename);
  904. type = get_word (e, real_filename);
  905. count = get_word (e, real_filename);
  906. if (type != 1)
  907. fatal (_("icon file `%s' does not contain icon data"), real_filename);
  908. /* Read in the icon directory entries. */
  909. icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
  910. for (i = 0; i < count; i++)
  911. {
  912. icondirs[i].width = getc (e);
  913. icondirs[i].height = getc (e);
  914. icondirs[i].colorcount = getc (e);
  915. getc (e);
  916. icondirs[i].u.icon.planes = get_word (e, real_filename);
  917. icondirs[i].u.icon.bits = get_word (e, real_filename);
  918. icondirs[i].bytes = get_long (e, real_filename);
  919. icondirs[i].offset = get_long (e, real_filename);
  920. if (feof (e))
  921. unexpected_eof (real_filename);
  922. }
  923. /* Define each icon as a unique resource. */
  924. first_icon = icons;
  925. for (i = 0; i < count; i++)
  926. {
  927. bfd_byte *data;
  928. rc_res_id name;
  929. if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
  930. fatal (_("%s: fseek to %lu failed: %s"), real_filename,
  931. icondirs[i].offset, strerror (errno));
  932. data = (bfd_byte *) res_alloc (icondirs[i].bytes);
  933. get_data (e, data, icondirs[i].bytes, real_filename);
  934. ++icons;
  935. name.named = 0;
  936. name.u.id = icons;
  937. r = define_standard_resource (&resources, RT_ICON, name,
  938. resinfo->language, 0);
  939. r->type = RES_TYPE_ICON;
  940. r->u.data.length = icondirs[i].bytes;
  941. r->u.data.data = data;
  942. r->res_info = *resinfo;
  943. }
  944. fclose (e);
  945. free (real_filename);
  946. /* Define an icon group resource. */
  947. first = NULL;
  948. pp = &first;
  949. for (i = 0; i < count; i++)
  950. {
  951. rc_group_icon *cg;
  952. /* For some reason, at least in some files the planes and bits
  953. are zero. We instead set them from the color. This is
  954. copied from rcl. */
  955. cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
  956. cg->next = NULL;
  957. cg->width = icondirs[i].width;
  958. cg->height = icondirs[i].height;
  959. cg->colors = icondirs[i].colorcount;
  960. if (icondirs[i].u.icon.planes)
  961. cg->planes = icondirs[i].u.icon.planes;
  962. else
  963. cg->planes = 1;
  964. if (icondirs[i].u.icon.bits)
  965. cg->bits = icondirs[i].u.icon.bits;
  966. else
  967. {
  968. cg->bits = 0;
  969. while ((1L << cg->bits) < cg->colors)
  970. ++cg->bits;
  971. }
  972. cg->bytes = icondirs[i].bytes;
  973. cg->index = first_icon + i + 1;
  974. *pp = cg;
  975. pp = &(*pp)->next;
  976. }
  977. free (icondirs);
  978. r = define_standard_resource (&resources, RT_GROUP_ICON, id,
  979. resinfo->language, 0);
  980. r->type = RES_TYPE_GROUP_ICON;
  981. r->u.group_icon = first;
  982. r->res_info = *resinfo;
  983. }
  984. static void
  985. define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
  986. rc_rcdata_item *data)
  987. {
  988. rc_res_resource *r;
  989. rc_group_icon *cg, *first, *cur;
  990. rc_uint_type len_data;
  991. bfd_byte *pb_data;
  992. pb_data = rcdata_render_as_buffer (data, &len_data);
  993. cur = NULL;
  994. first = NULL;
  995. while (len_data >= 6)
  996. {
  997. int c, i;
  998. unsigned short type;
  999. type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
  1000. if (type != 1)
  1001. fatal (_("unexpected group icon type %d"), type);
  1002. c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
  1003. len_data -= 6;
  1004. pb_data += 6;
  1005. for (i = 0; i < c; i++)
  1006. {
  1007. if (len_data < 14)
  1008. fatal ("too small group icon rcdata");
  1009. cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
  1010. cg->next = NULL;
  1011. cg->width = pb_data[0];
  1012. cg->height = pb_data[1];
  1013. cg->colors = pb_data[2];
  1014. cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
  1015. cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
  1016. cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
  1017. cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
  1018. if (! first)
  1019. first = cg;
  1020. else
  1021. cur->next = cg;
  1022. cur = cg;
  1023. pb_data += 14;
  1024. len_data -= 14;
  1025. }
  1026. }
  1027. r = define_standard_resource (&resources, RT_GROUP_ICON, id,
  1028. resinfo->language, 0);
  1029. r->type = RES_TYPE_GROUP_ICON;
  1030. r->u.group_icon = first;
  1031. r->res_info = *resinfo;
  1032. }
  1033. static void
  1034. define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
  1035. rc_rcdata_item *data)
  1036. {
  1037. rc_res_resource *r;
  1038. rc_group_cursor *cg, *first, *cur;
  1039. rc_uint_type len_data;
  1040. bfd_byte *pb_data;
  1041. pb_data = rcdata_render_as_buffer (data, &len_data);
  1042. first = cur = NULL;
  1043. while (len_data >= 6)
  1044. {
  1045. int c, i;
  1046. unsigned short type;
  1047. type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
  1048. if (type != 2)
  1049. fatal (_("unexpected group cursor type %d"), type);
  1050. c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
  1051. len_data -= 6;
  1052. pb_data += 6;
  1053. for (i = 0; i < c; i++)
  1054. {
  1055. if (len_data < 14)
  1056. fatal ("too small group icon rcdata");
  1057. cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
  1058. cg->next = NULL;
  1059. cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
  1060. cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
  1061. cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
  1062. cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
  1063. cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
  1064. cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
  1065. if (! first)
  1066. first = cg;
  1067. else
  1068. cur->next = cg;
  1069. cur = cg;
  1070. pb_data += 14;
  1071. len_data -= 14;
  1072. }
  1073. }
  1074. r = define_standard_resource (&resources, RT_GROUP_ICON, id,
  1075. resinfo->language, 0);
  1076. r->type = RES_TYPE_GROUP_CURSOR;
  1077. r->u.group_cursor = first;
  1078. r->res_info = *resinfo;
  1079. }
  1080. static void
  1081. define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
  1082. rc_rcdata_item *data)
  1083. {
  1084. rc_cursor *c;
  1085. rc_res_resource *r;
  1086. rc_uint_type len_data;
  1087. bfd_byte *pb_data;
  1088. pb_data = rcdata_render_as_buffer (data, &len_data);
  1089. c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
  1090. c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
  1091. c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
  1092. c->length = len_data - BIN_CURSOR_SIZE;
  1093. c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
  1094. r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
  1095. r->type = RES_TYPE_CURSOR;
  1096. r->u.cursor = c;
  1097. r->res_info = *resinfo;
  1098. }
  1099. static void
  1100. define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
  1101. rc_rcdata_item *data)
  1102. {
  1103. rc_res_resource *r;
  1104. rc_uint_type len_data;
  1105. bfd_byte *pb_data;
  1106. pb_data = rcdata_render_as_buffer (data, &len_data);
  1107. r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
  1108. r->type = RES_TYPE_BITMAP;
  1109. r->u.data.length = len_data;
  1110. r->u.data.data = pb_data;
  1111. r->res_info = *resinfo;
  1112. }
  1113. static void
  1114. define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
  1115. rc_rcdata_item *data)
  1116. {
  1117. rc_res_resource *r;
  1118. rc_uint_type len_data;
  1119. bfd_byte *pb_data;
  1120. pb_data = rcdata_render_as_buffer (data, &len_data);
  1121. r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
  1122. r->type = RES_TYPE_ICON;
  1123. r->u.data.length = len_data;
  1124. r->u.data.data = pb_data;
  1125. r->res_info = *resinfo;
  1126. }
  1127. /* Define a menu resource. */
  1128. void
  1129. define_menu (rc_res_id id, const rc_res_res_info *resinfo,
  1130. rc_menuitem *menuitems)
  1131. {
  1132. rc_menu *m;
  1133. rc_res_resource *r;
  1134. m = (rc_menu *) res_alloc (sizeof (rc_menu));
  1135. m->items = menuitems;
  1136. m->help = 0;
  1137. r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
  1138. r->type = RES_TYPE_MENU;
  1139. r->u.menu = m;
  1140. r->res_info = *resinfo;
  1141. }
  1142. /* Define a menu item. This does not define a resource, but merely
  1143. allocates and fills in a structure. */
  1144. rc_menuitem *
  1145. define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
  1146. rc_uint_type state, rc_uint_type help,
  1147. rc_menuitem *menuitems)
  1148. {
  1149. rc_menuitem *mi;
  1150. mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
  1151. mi->next = NULL;
  1152. mi->type = type;
  1153. mi->state = state;
  1154. mi->id = menuid;
  1155. mi->text = unichar_dup (text);
  1156. mi->help = help;
  1157. mi->popup = menuitems;
  1158. return mi;
  1159. }
  1160. /* Define a messagetable resource. */
  1161. void
  1162. define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
  1163. const char *filename)
  1164. {
  1165. FILE *e;
  1166. char *real_filename;
  1167. struct stat s;
  1168. bfd_byte *data;
  1169. rc_res_resource *r;
  1170. e = open_file_search (filename, FOPEN_RB, "messagetable file",
  1171. &real_filename);
  1172. if (stat (real_filename, &s) < 0)
  1173. fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
  1174. strerror (errno));
  1175. data = (bfd_byte *) res_alloc (s.st_size);
  1176. get_data (e, data, s.st_size, real_filename);
  1177. fclose (e);
  1178. free (real_filename);
  1179. r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
  1180. resinfo->language, 0);
  1181. r->type = RES_TYPE_MESSAGETABLE;
  1182. r->u.data.length = s.st_size;
  1183. r->u.data.data = data;
  1184. r->res_info = *resinfo;
  1185. }
  1186. /* Define an rcdata resource. */
  1187. void
  1188. define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
  1189. rc_rcdata_item *data)
  1190. {
  1191. rc_res_resource *r;
  1192. r = define_standard_resource (&resources, RT_RCDATA, id,
  1193. resinfo->language, 0);
  1194. r->type = RES_TYPE_RCDATA;
  1195. r->u.rcdata = data;
  1196. r->res_info = *resinfo;
  1197. }
  1198. /* Create an rcdata item holding a string. */
  1199. rc_rcdata_item *
  1200. define_rcdata_string (const char *string, rc_uint_type len)
  1201. {
  1202. rc_rcdata_item *ri;
  1203. char *s;
  1204. ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
  1205. ri->next = NULL;
  1206. ri->type = RCDATA_STRING;
  1207. ri->u.string.length = len;
  1208. s = (char *) res_alloc (len);
  1209. memcpy (s, string, len);
  1210. ri->u.string.s = s;
  1211. return ri;
  1212. }
  1213. /* Create an rcdata item holding a unicode string. */
  1214. rc_rcdata_item *
  1215. define_rcdata_unistring (const unichar *string, rc_uint_type len)
  1216. {
  1217. rc_rcdata_item *ri;
  1218. unichar *s;
  1219. ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
  1220. ri->next = NULL;
  1221. ri->type = RCDATA_WSTRING;
  1222. ri->u.wstring.length = len;
  1223. s = (unichar *) res_alloc (len * sizeof (unichar));
  1224. memcpy (s, string, len * sizeof (unichar));
  1225. ri->u.wstring.w = s;
  1226. return ri;
  1227. }
  1228. /* Create an rcdata item holding a number. */
  1229. rc_rcdata_item *
  1230. define_rcdata_number (rc_uint_type val, int dword)
  1231. {
  1232. rc_rcdata_item *ri;
  1233. ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
  1234. ri->next = NULL;
  1235. ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
  1236. ri->u.word = val;
  1237. return ri;
  1238. }
  1239. /* Define a stringtable resource. This is called for each string
  1240. which appears in a STRINGTABLE statement. */
  1241. void
  1242. define_stringtable (const rc_res_res_info *resinfo,
  1243. rc_uint_type stringid, const unichar *string)
  1244. {
  1245. rc_res_id id;
  1246. rc_res_resource *r;
  1247. id.named = 0;
  1248. id.u.id = (stringid >> 4) + 1;
  1249. r = define_standard_resource (&resources, RT_STRING, id,
  1250. resinfo->language, 1);
  1251. if (r->type == RES_TYPE_UNINITIALIZED)
  1252. {
  1253. int i;
  1254. r->type = RES_TYPE_STRINGTABLE;
  1255. r->u.stringtable = ((rc_stringtable *)
  1256. res_alloc (sizeof (rc_stringtable)));
  1257. for (i = 0; i < 16; i++)
  1258. {
  1259. r->u.stringtable->strings[i].length = 0;
  1260. r->u.stringtable->strings[i].string = NULL;
  1261. }
  1262. r->res_info = *resinfo;
  1263. }
  1264. r->u.stringtable->strings[stringid & 0xf].length = unichar_len (string);
  1265. r->u.stringtable->strings[stringid & 0xf].string = unichar_dup (string);
  1266. }
  1267. void
  1268. define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
  1269. rc_toolbar_item *items)
  1270. {
  1271. rc_toolbar *t;
  1272. rc_res_resource *r;
  1273. t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
  1274. t->button_width = width;
  1275. t->button_height = height;
  1276. t->nitems = 0;
  1277. t->items = items;
  1278. while (items != NULL)
  1279. {
  1280. t->nitems+=1;
  1281. items = items->next;
  1282. }
  1283. r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
  1284. r->type = RES_TYPE_TOOLBAR;
  1285. r->u.toolbar = t;
  1286. r->res_info = *resinfo;
  1287. }
  1288. /* Define a user data resource where the data is in the rc file. */
  1289. void
  1290. define_user_data (rc_res_id id, rc_res_id type,
  1291. const rc_res_res_info *resinfo,
  1292. rc_rcdata_item *data)
  1293. {
  1294. rc_res_id ids[3];
  1295. rc_res_resource *r;
  1296. bfd_byte *pb_data;
  1297. rc_uint_type len_data;
  1298. /* We have to check if the binary data is parsed specially. */
  1299. if (type.named == 0)
  1300. {
  1301. switch (type.u.id)
  1302. {
  1303. case RT_FONTDIR:
  1304. define_fontdir_rcdata (id, resinfo, data);
  1305. return;
  1306. case RT_FONT:
  1307. define_font_rcdata (id, resinfo, data);
  1308. return;
  1309. case RT_ICON:
  1310. define_icon_rcdata (id, resinfo, data);
  1311. return;
  1312. case RT_BITMAP:
  1313. define_bitmap_rcdata (id, resinfo, data);
  1314. return;
  1315. case RT_CURSOR:
  1316. define_cursor_rcdata (id, resinfo, data);
  1317. return;
  1318. case RT_GROUP_ICON:
  1319. define_group_icon_rcdata (id, resinfo, data);
  1320. return;
  1321. case RT_GROUP_CURSOR:
  1322. define_group_cursor_rcdata (id, resinfo, data);
  1323. return;
  1324. case RT_MESSAGETABLE:
  1325. define_messagetable_rcdata (id, resinfo, data);
  1326. return;
  1327. default:
  1328. /* Treat as normal user-data. */
  1329. break;
  1330. }
  1331. }
  1332. ids[0] = type;
  1333. ids[1] = id;
  1334. ids[2].named = 0;
  1335. ids[2].u.id = resinfo->language;
  1336. r = define_resource (& resources, 3, ids, 0);
  1337. r->type = RES_TYPE_USERDATA;
  1338. r->u.userdata = ((rc_rcdata_item *)
  1339. res_alloc (sizeof (rc_rcdata_item)));
  1340. r->u.userdata->next = NULL;
  1341. r->u.userdata->type = RCDATA_BUFFER;
  1342. pb_data = rcdata_render_as_buffer (data, &len_data);
  1343. r->u.userdata->u.buffer.length = len_data;
  1344. r->u.userdata->u.buffer.data = pb_data;
  1345. r->res_info = *resinfo;
  1346. }
  1347. void
  1348. define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
  1349. const char *filename)
  1350. {
  1351. rc_rcdata_item *ri;
  1352. FILE *e;
  1353. char *real_filename;
  1354. struct stat s;
  1355. bfd_byte *data;
  1356. e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
  1357. if (stat (real_filename, &s) < 0)
  1358. fatal (_("stat failed on file `%s': %s"), real_filename,
  1359. strerror (errno));
  1360. data = (bfd_byte *) res_alloc (s.st_size);
  1361. get_data (e, data, s.st_size, real_filename);
  1362. fclose (e);
  1363. free (real_filename);
  1364. ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
  1365. ri->next = NULL;
  1366. ri->type = RCDATA_BUFFER;
  1367. ri->u.buffer.length = s.st_size;
  1368. ri->u.buffer.data = data;
  1369. define_rcdata (id, resinfo, ri);
  1370. }
  1371. /* Define a user data resource where the data is in a file. */
  1372. void
  1373. define_user_file (rc_res_id id, rc_res_id type,
  1374. const rc_res_res_info *resinfo, const char *filename)
  1375. {
  1376. FILE *e;
  1377. char *real_filename;
  1378. struct stat s;
  1379. bfd_byte *data;
  1380. rc_res_id ids[3];
  1381. rc_res_resource *r;
  1382. e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
  1383. if (stat (real_filename, &s) < 0)
  1384. fatal (_("stat failed on file `%s': %s"), real_filename,
  1385. strerror (errno));
  1386. data = (bfd_byte *) res_alloc (s.st_size);
  1387. get_data (e, data, s.st_size, real_filename);
  1388. fclose (e);
  1389. free (real_filename);
  1390. ids[0] = type;
  1391. ids[1] = id;
  1392. ids[2].named = 0;
  1393. ids[2].u.id = resinfo->language;
  1394. r = define_resource (&resources, 3, ids, 0);
  1395. r->type = RES_TYPE_USERDATA;
  1396. r->u.userdata = ((rc_rcdata_item *)
  1397. res_alloc (sizeof (rc_rcdata_item)));
  1398. r->u.userdata->next = NULL;
  1399. r->u.userdata->type = RCDATA_BUFFER;
  1400. r->u.userdata->u.buffer.length = s.st_size;
  1401. r->u.userdata->u.buffer.data = data;
  1402. r->res_info = *resinfo;
  1403. }
  1404. /* Define a versioninfo resource. */
  1405. void
  1406. define_versioninfo (rc_res_id id, rc_uint_type language,
  1407. rc_fixed_versioninfo *fixedverinfo,
  1408. rc_ver_info *verinfo)
  1409. {
  1410. rc_res_resource *r;
  1411. r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
  1412. r->type = RES_TYPE_VERSIONINFO;
  1413. r->u.versioninfo = ((rc_versioninfo *)
  1414. res_alloc (sizeof (rc_versioninfo)));
  1415. r->u.versioninfo->fixed = fixedverinfo;
  1416. r->u.versioninfo->var = verinfo;
  1417. r->res_info.language = language;
  1418. }
  1419. /* Add string version info to a list of version information. */
  1420. rc_ver_info *
  1421. append_ver_stringfileinfo (rc_ver_info *verinfo, const char *language,
  1422. rc_ver_stringinfo *strings)
  1423. {
  1424. rc_ver_info *vi, **pp;
  1425. vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
  1426. vi->next = NULL;
  1427. vi->type = VERINFO_STRING;
  1428. unicode_from_ascii ((rc_uint_type *) NULL, &vi->u.string.language, language);
  1429. vi->u.string.strings = strings;
  1430. for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
  1431. ;
  1432. *pp = vi;
  1433. return verinfo;
  1434. }
  1435. /* Add variable version info to a list of version information. */
  1436. rc_ver_info *
  1437. append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
  1438. rc_ver_varinfo *var)
  1439. {
  1440. rc_ver_info *vi, **pp;
  1441. vi = (rc_ver_info *) res_alloc (sizeof *vi);
  1442. vi->next = NULL;
  1443. vi->type = VERINFO_VAR;
  1444. vi->u.var.key = unichar_dup (key);
  1445. vi->u.var.var = var;
  1446. for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
  1447. ;
  1448. *pp = vi;
  1449. return verinfo;
  1450. }
  1451. /* Append version string information to a list. */
  1452. rc_ver_stringinfo *
  1453. append_verval (rc_ver_stringinfo *strings, const unichar *key,
  1454. const unichar *value)
  1455. {
  1456. rc_ver_stringinfo *vs, **pp;
  1457. vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
  1458. vs->next = NULL;
  1459. vs->key = unichar_dup (key);
  1460. vs->value = unichar_dup (value);
  1461. for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
  1462. ;
  1463. *pp = vs;
  1464. return strings;
  1465. }
  1466. /* Append version variable information to a list. */
  1467. rc_ver_varinfo *
  1468. append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
  1469. rc_uint_type charset)
  1470. {
  1471. rc_ver_varinfo *vv, **pp;
  1472. vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
  1473. vv->next = NULL;
  1474. vv->language = language;
  1475. vv->charset = charset;
  1476. for (pp = &var; *pp != NULL; pp = &(*pp)->next)
  1477. ;
  1478. *pp = vv;
  1479. return var;
  1480. }
  1481. /* Local functions used to write out an rc file. */
  1482. static void indent (FILE *, int);
  1483. static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
  1484. const rc_res_id *, rc_uint_type *, int);
  1485. static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
  1486. const rc_res_id *, rc_uint_type *, int);
  1487. static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
  1488. const rc_res_resource *, rc_uint_type *);
  1489. static void write_rc_accelerators (FILE *, const rc_accelerator *);
  1490. static void write_rc_cursor (FILE *, const rc_cursor *);
  1491. static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
  1492. static void write_rc_dialog (FILE *, const rc_dialog *);
  1493. static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
  1494. static void write_rc_fontdir (FILE *, const rc_fontdir *);
  1495. static void write_rc_group_icon (FILE *, const rc_group_icon *);
  1496. static void write_rc_menu (FILE *, const rc_menu *, int);
  1497. static void write_rc_toolbar (FILE *, const rc_toolbar *);
  1498. static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
  1499. static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
  1500. static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
  1501. static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
  1502. static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
  1503. static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
  1504. /* Indent a given number of spaces. */
  1505. static void
  1506. indent (FILE *e, int c)
  1507. {
  1508. int i;
  1509. for (i = 0; i < c; i++)
  1510. putc (' ', e);
  1511. }
  1512. /* Dump the resources we have read in the format of an rc file.
  1513. Reasoned by the fact, that some resources need to be stored into file and
  1514. refer to that file, we use the user-data model for that to express it binary
  1515. without the need to store it somewhere externally. */
  1516. void
  1517. write_rc_file (const char *filename, const rc_res_directory *resources)
  1518. {
  1519. FILE *e;
  1520. rc_uint_type language;
  1521. if (filename == NULL)
  1522. e = stdout;
  1523. else
  1524. {
  1525. e = fopen (filename, FOPEN_WT);
  1526. if (e == NULL)
  1527. fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
  1528. }
  1529. language = (rc_uint_type) ((bfd_signed_vma) -1);
  1530. write_rc_directory (e, resources, (const rc_res_id *) NULL,
  1531. (const rc_res_id *) NULL, &language, 1);
  1532. }
  1533. /* Write out a directory. E is the file to write to. RD is the
  1534. directory. TYPE is a pointer to the level 1 ID which serves as the
  1535. resource type. NAME is a pointer to the level 2 ID which serves as
  1536. an individual resource name. LANGUAGE is a pointer to the current
  1537. language. LEVEL is the level in the tree. */
  1538. static void
  1539. write_rc_directory (FILE *e, const rc_res_directory *rd,
  1540. const rc_res_id *type, const rc_res_id *name,
  1541. rc_uint_type *language, int level)
  1542. {
  1543. const rc_res_entry *re;
  1544. /* Print out some COFF information that rc files can't represent. */
  1545. if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
  1546. {
  1547. wr_printcomment (e, "COFF information not part of RC");
  1548. if (rd->time != 0)
  1549. wr_printcomment (e, "Time stamp: %u", rd->time);
  1550. if (rd->characteristics != 0)
  1551. wr_printcomment (e, "Characteristics: %u", rd->characteristics);
  1552. if (rd->major != 0 || rd->minor != 0)
  1553. wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
  1554. }
  1555. for (re = rd->entries; re != NULL; re = re->next)
  1556. {
  1557. switch (level)
  1558. {
  1559. case 1:
  1560. /* If we're at level 1, the key of this resource is the
  1561. type. This normally duplicates the information we have
  1562. stored with the resource itself, but we need to remember
  1563. the type if this is a user define resource type. */
  1564. type = &re->id;
  1565. break;
  1566. case 2:
  1567. /* If we're at level 2, the key of this resource is the name
  1568. we are going to use in the rc printout. */
  1569. name = &re->id;
  1570. break;
  1571. case 3:
  1572. /* If we're at level 3, then this key represents a language.
  1573. Use it to update the current language. */
  1574. if (! re->id.named
  1575. && re->id.u.id != (unsigned long) (unsigned int) *language
  1576. && (re->id.u.id & 0xffff) == re->id.u.id)
  1577. {
  1578. wr_print (e, "LANGUAGE %u, %u\n",
  1579. re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
  1580. (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
  1581. *language = re->id.u.id;
  1582. }
  1583. break;
  1584. default:
  1585. break;
  1586. }
  1587. if (re->subdir)
  1588. write_rc_subdir (e, re, type, name, language, level);
  1589. else
  1590. {
  1591. if (level == 3)
  1592. {
  1593. /* This is the normal case: the three levels are
  1594. TYPE/NAME/LANGUAGE. NAME will have been set at level
  1595. 2, and represents the name to use. We probably just
  1596. set LANGUAGE, and it will probably match what the
  1597. resource itself records if anything. */
  1598. write_rc_resource (e, type, name, re->u.res, language);
  1599. }
  1600. else
  1601. {
  1602. wr_printcomment (e, "Resource at unexpected level %d", level);
  1603. write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
  1604. language);
  1605. }
  1606. }
  1607. }
  1608. if (rd->entries == NULL)
  1609. {
  1610. wr_print_flush (e);
  1611. }
  1612. }
  1613. /* Write out a subdire