windmc.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. /* windmc.c -- a program to compile Windows message files.
  2. Copyright (C) 2007-2015 Free Software Foundation, Inc.
  3. Written by Kai Tietz, Onevision.
  4. This file is part of GNU Binutils.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
  16. 02110-1301, USA. */
  17. /* This program can read and comile Windows message format.
  18. It is based on information taken from the following sources:
  19. * Microsoft documentation.
  20. * The wmc program, written by Bertho A. Stultiens (BS). */
  21. #include "sysdep.h"
  22. #include <assert.h>
  23. #include <time.h>
  24. #include "bfd.h"
  25. #include "getopt.h"
  26. #include "bucomm.h"
  27. #include "libiberty.h"
  28. #include "safe-ctype.h"
  29. #include "obstack.h"
  30. #include "windmc.h"
  31. #include "windint.h"
  32. /* Defines a message compiler element item with length and offset
  33. information. */
  34. typedef struct mc_msg_item
  35. {
  36. rc_uint_type res_len;
  37. rc_uint_type res_off;
  38. struct bin_messagetable_item *res;
  39. } mc_msg_item;
  40. int target_is_bigendian = 0;
  41. const char *def_target_arch;
  42. /* Globals and static variable definitions. */
  43. /* bfd global helper struct variable. */
  44. static struct
  45. {
  46. bfd *abfd;
  47. asection *sec;
  48. } mc_bfd;
  49. /* Memory list. */
  50. mc_node *mc_nodes = NULL;
  51. static mc_node_lang **mc_nodes_lang = NULL;
  52. static int mc_nodes_lang_count = 0;
  53. static mc_keyword **mc_severity_codes = NULL;
  54. static int mc_severity_codes_count = 0;
  55. static mc_keyword **mc_facility_codes = NULL;
  56. static int mc_facility_codes_count = 0;
  57. /* When we are building a resource tree, we allocate everything onto
  58. an obstack, so that we can free it all at once if we want. */
  59. #define obstack_chunk_alloc xmalloc
  60. #define obstack_chunk_free free
  61. /* The resource building obstack. */
  62. static struct obstack res_obstack;
  63. /* Flag variables. */
  64. /* Set by -C. Set the default code page to be used for input text file. */
  65. static rc_uint_type mcset_codepage_in = 0;
  66. /* Set by -O. Set the default code page to be used for output text files. */
  67. static rc_uint_type mcset_codepage_out = 0;
  68. /* Set by -b. .BIN filename should have .mc filename_ included for uniqueness. */
  69. static int mcset_prefix_bin = 0;
  70. /* The base name of the .mc file. */
  71. static const char *mcset_mc_basename = "unknown";
  72. /* Set by -e <ext>. Specify the extension for the header file. */
  73. static const char *mcset_header_ext = ".h";
  74. /* Set by -h <path>. Gives the path of where to create the C include file. */
  75. static const char *mcset_header_dir = "./";
  76. /* Set by -r <path>. Gives the path of where to create the RC include file
  77. and the binary message resource files it includes. */
  78. static const char *mcset_rc_dir = "./";
  79. /* Modified by -a & -u. By -u input file is unicode, by -a is ASCII (default). */
  80. static int mcset_text_in_is_unicode = 0;
  81. /* Modified by -A & -U. By -U bin file is unicode (default), by -A is ASCII. */
  82. static int mcset_bin_out_is_unicode = 1;
  83. /* Set by -c. Sets the Customer bit in all the message ID's. */
  84. int mcset_custom_bit = 0;
  85. /* Set by -o. Generate OLE2 header file. Use HRESULT definition instead of
  86. status code definition. */
  87. static int mcset_use_hresult = 0;
  88. /* Set by -m <msglen>. Generate a warning if the size of any message exceeds
  89. maxmsglen characters. */
  90. rc_uint_type mcset_max_message_length = 0;
  91. /* Set by -d. Sets message values in header to decimal initially. */
  92. int mcset_out_values_are_decimal = 0;
  93. /* Set by -n. terminates all strings with null's in the message tables. */
  94. static int mcset_automatic_null_termination = 0;
  95. /* The type used for message id output in header. */
  96. unichar *mcset_msg_id_typedef = NULL;
  97. /* Set by -x path. Geberated debug C file for mapping ID's to text. */
  98. static const char *mcset_dbg_dir = NULL;
  99. /* getopt long name definitions. */
  100. static const struct option long_options[] =
  101. {
  102. {"binprefix", no_argument, 0, 'b'},
  103. {"target", required_argument, 0, 'F'},
  104. {"extension", required_argument, 0, 'e'},
  105. {"headerdir", required_argument, 0, 'h'},
  106. {"rcdir", required_argument, 0, 'r'},
  107. {"verbose", no_argument, 0, 'v'},
  108. {"codepage_in", required_argument, 0, 'C'},
  109. {"codepage_out", required_argument, 0, 'O'},
  110. {"maxlength", required_argument, 0, 'm'},
  111. {"ascii_in", no_argument, 0, 'a'},
  112. {"ascii_out", no_argument, 0, 'A'},
  113. {"unicode_in", no_argument, 0, 'u'},
  114. {"unicode_out", no_argument, 0, 'U'},
  115. {"customflag", no_argument, 0, 'c'},
  116. {"decimal_values", no_argument, 0, 'd'},
  117. {"hresult_use", no_argument, 0, 'o'},
  118. {"nullterminate", no_argument, 0, 'n'},
  119. {"xdbg", required_argument, 0, 'x'},
  120. {"version", no_argument, 0, 'V'},
  121. {"help", no_argument, 0, 'H'},
  122. {0, no_argument, 0, 0}
  123. };
  124. /* Initialize the resource building obstack. */
  125. static void
  126. res_init (void)
  127. {
  128. obstack_init (&res_obstack);
  129. }
  130. /* Allocate space on the resource building obstack. */
  131. void *
  132. res_alloc (rc_uint_type bytes)
  133. {
  134. return obstack_alloc (&res_obstack, (size_t) bytes);
  135. }
  136. static FILE *
  137. mc_create_path_text_file (const char *path, const char *ext)
  138. {
  139. FILE *ret;
  140. size_t len = 1;
  141. char *hsz;
  142. len += (path != NULL ? strlen (path) : 0);
  143. len += strlen (mcset_mc_basename);
  144. len += (ext != NULL ? strlen (ext) : 0);
  145. hsz = xmalloc (len);
  146. sprintf (hsz, "%s%s%s", (path != NULL ? path : ""), mcset_mc_basename,
  147. (ext != NULL ? ext : ""));
  148. if ((ret = fopen (hsz, "wb")) == NULL)
  149. fatal (_("can't create %s file `%s' for output.\n"), (ext ? ext : "text"), hsz);
  150. free (hsz);
  151. return ret;
  152. }
  153. static void
  154. usage (FILE *stream, int status)
  155. {
  156. fprintf (stream, _("Usage: %s [option(s)] [input-file]\n"),
  157. program_name);
  158. fprintf (stream, _(" The options are:\n\
  159. -a --ascii_in Read input file as ASCII file\n\
  160. -A --ascii_out Write binary messages as ASCII\n\
  161. -b --binprefix .bin filename is prefixed by .mc filename_ for uniqueness.\n\
  162. -c --customflag Set custom flags for messages\n\
  163. -C --codepage_in=<val> Set codepage when reading mc text file\n\
  164. -d --decimal_values Print values to text files decimal\n\
  165. -e --extension=<extension> Set header extension used on export header file\n\
  166. -F --target <target> Specify output target for endianness.\n\
  167. -h --headerdir=<directory> Set the export directory for headers\n\
  168. -u --unicode_in Read input file as UTF16 file\n\
  169. -U --unicode_out Write binary messages as UFT16\n\
  170. -m --maxlength=<val> Set the maximal allowed message length\n\
  171. -n --nullterminate Automatic add a zero termination to strings\n\
  172. -o --hresult_use Use HRESULT definition instead of status code definition\n\
  173. -O --codepage_out=<val> Set codepage used for writing text file\n\
  174. -r --rcdir=<directory> Set the export directory for rc files\n\
  175. -x --xdbg=<directory> Where to create the .dbg C include file\n\
  176. that maps message ID's to their symbolic name.\n\
  177. "));
  178. fprintf (stream, _("\
  179. -H --help Print this help message\n\
  180. -v --verbose Verbose - tells you what it's doing\n\
  181. -V --version Print version information\n"));
  182. list_supported_targets (program_name, stream);
  183. if (REPORT_BUGS_TO[0] && status == 0)
  184. fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
  185. exit (status);
  186. }
  187. static void
  188. set_endianness (bfd *abfd, const char *target)
  189. {
  190. const bfd_target *target_vec;
  191. def_target_arch = NULL;
  192. target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
  193. &def_target_arch);
  194. if (! target_vec)
  195. fatal ("Can't detect target endianness and architecture.");
  196. if (! def_target_arch)
  197. fatal ("Can't detect architecture.");
  198. }
  199. static int
  200. probe_codepage (rc_uint_type *cp, int *is_uni, const char *pswitch, int defmode)
  201. {
  202. if (*is_uni == -1)
  203. {
  204. if (*cp != CP_UTF16)
  205. *is_uni = defmode;
  206. else
  207. *is_uni = 1;
  208. }
  209. if (*is_uni)
  210. {
  211. if (*cp != 0 && *cp != CP_UTF16)
  212. {
  213. fprintf (stderr, _("%s: warning: "), program_name);
  214. fprintf (stderr, _("A codepage was specified switch `%s' and UTF16.\n"), pswitch);
  215. fprintf (stderr, _("\tcodepage settings are ignored.\n"));
  216. }
  217. *cp = CP_UTF16;
  218. return 1;
  219. }
  220. if (*cp == CP_UTF16)
  221. {
  222. *is_uni = 1;
  223. return 1;
  224. }
  225. if (*cp == 0)
  226. *cp = 1252;
  227. if (! unicode_is_valid_codepage (*cp))
  228. fatal ("Code page 0x%x is unknown.", (unsigned int) *cp);
  229. *is_uni = 0;
  230. return 1;
  231. }
  232. mc_node *
  233. mc_add_node (void)
  234. {
  235. mc_node *ret;
  236. ret = res_alloc (sizeof (mc_node));
  237. memset (ret, 0, sizeof (mc_node));
  238. if (! mc_nodes)
  239. mc_nodes = ret;
  240. else
  241. {
  242. mc_node *h = mc_nodes;
  243. while (h->next != NULL)
  244. h = h->next;
  245. h->next = ret;
  246. }
  247. return ret;
  248. }
  249. mc_node_lang *
  250. mc_add_node_lang (mc_node *root, const mc_keyword *lang, rc_uint_type vid)
  251. {
  252. mc_node_lang *ret, *h, *p;
  253. if (! lang || ! root)
  254. fatal (_("try to add a ill language."));
  255. ret = res_alloc (sizeof (mc_node_lang));
  256. memset (ret, 0, sizeof (mc_node_lang));
  257. ret->lang = lang;
  258. ret->vid = vid;
  259. if ((h = root->sub) == NULL)
  260. root->sub = ret;
  261. else
  262. {
  263. p = NULL;
  264. while (h != NULL)
  265. {
  266. if (h->lang->nval > lang->nval)
  267. break;
  268. if (h->lang->nval == lang->nval)
  269. {
  270. if (h->vid > vid)
  271. break;
  272. if (h->vid == vid)
  273. fatal ("double defined message id %ld.\n", (long) vid);
  274. }
  275. h = (p = h)->next;
  276. }
  277. ret->next = h;
  278. if (! p)
  279. root->sub = ret;
  280. else
  281. p->next = ret;
  282. }
  283. return ret;
  284. }
  285. static char *
  286. convert_unicode_to_ACP (const unichar *usz)
  287. {
  288. char *s;
  289. rc_uint_type l;
  290. if (! usz)
  291. return NULL;
  292. codepage_from_unicode (&l, usz, &s, mcset_codepage_out);
  293. if (! s)
  294. fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n",
  295. (unsigned long) mcset_codepage_out);
  296. return s;
  297. }
  298. static void
  299. write_dbg_define (FILE *fp, const unichar *sym_name, const unichar *typecast)
  300. {
  301. char *sym;
  302. if (!sym_name || sym_name[0] == 0)
  303. return;
  304. sym = convert_unicode_to_ACP (sym_name);
  305. fprintf (fp, " {(");
  306. if (typecast)
  307. unicode_print (fp, typecast, unichar_len (typecast));
  308. else
  309. fprintf (fp, "DWORD");
  310. fprintf (fp, ") %s, \"%s\" },\n", sym, sym);
  311. }
  312. static void
  313. write_header_define (FILE *fp, const unichar *sym_name, rc_uint_type vid, const unichar *typecast, mc_node_lang *nl)
  314. {
  315. char *sym;
  316. char *tdef = NULL;
  317. if (!sym_name || sym_name[0] == 0)
  318. {
  319. if (nl != NULL)
  320. {
  321. if (mcset_out_values_are_decimal)
  322. fprintf (fp, "//\n// MessageId: 0x%lu\n//\n", (unsigned long) vid);
  323. else
  324. fprintf (fp, "//\n// MessageId: 0x%lx\n//\n", (unsigned long) vid);
  325. }
  326. return;
  327. }
  328. sym = convert_unicode_to_ACP (sym_name);
  329. if (typecast && typecast[0] != 0)
  330. tdef = convert_unicode_to_ACP (typecast);
  331. fprintf (fp, "//\n// MessageId: %s\n//\n", sym);
  332. if (! mcset_out_values_are_decimal)
  333. fprintf (fp, "#define %s %s%s%s 0x%lx\n\n", sym,
  334. (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
  335. (unsigned long) vid);
  336. else
  337. fprintf (fp, "#define %s %s%s%s 0x%lu\n\n", sym,
  338. (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
  339. (unsigned long) vid);
  340. }
  341. static int
  342. sort_mc_node_lang (const void *l, const void *r)
  343. {
  344. const mc_node_lang *l1 = *((const mc_node_lang **)l);
  345. const mc_node_lang *r1 = *((const mc_node_lang **)r);
  346. if (l == r)
  347. return 0;
  348. if (l1->lang != r1->lang)
  349. {
  350. if (l1->lang->nval < r1->lang->nval)
  351. return -1;
  352. return 1;
  353. }
  354. if (l1->vid == r1->vid)
  355. return 0;
  356. if (l1->vid < r1->vid)
  357. return -1;
  358. return 1;
  359. }
  360. static int
  361. sort_keyword_by_nval (const void *l, const void *r)
  362. {
  363. const mc_keyword *l1 = *((const mc_keyword **)l);
  364. const mc_keyword *r1 = *((const mc_keyword **)r);
  365. rc_uint_type len1, len2;
  366. int e;
  367. if (l == r)
  368. return 0;
  369. if (l1->nval != r1->nval)
  370. {
  371. if (l1->nval < r1->nval)
  372. return -1;
  373. return 1;
  374. }
  375. len1 = unichar_len (l1->usz);
  376. len2 = unichar_len (r1->usz);
  377. if (len1 <= len2)
  378. e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len1);
  379. else
  380. e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len2);
  381. if (e)
  382. return e;
  383. if (len1 < len2)
  384. return -1;
  385. else if (len1 > len2)
  386. return 1;
  387. return 0;
  388. }
  389. static void
  390. do_sorts (void)
  391. {
  392. mc_node *h;
  393. mc_node_lang *n;
  394. const mc_keyword *k;
  395. int i;
  396. /* Sort message by their language and id ascending. */
  397. mc_nodes_lang_count = 0;
  398. h = mc_nodes;
  399. while (h != NULL)
  400. {
  401. n = h->sub;
  402. while (n != NULL)
  403. {
  404. mc_nodes_lang_count +=1;
  405. n = n->next;
  406. }
  407. h = h->next;
  408. }
  409. if (mc_nodes_lang_count != 0)
  410. {
  411. h = mc_nodes;
  412. i = 0;
  413. mc_nodes_lang = xmalloc (sizeof (mc_node_lang *) * mc_nodes_lang_count);
  414. while (h != NULL)
  415. {
  416. n = h->sub;
  417. while (n != NULL)
  418. {
  419. mc_nodes_lang[i++] = n;
  420. n = n->next;
  421. }
  422. h = h->next;
  423. }
  424. qsort (mc_nodes_lang, (size_t) mc_nodes_lang_count, sizeof (mc_node_lang *), sort_mc_node_lang);
  425. }
  426. /* Sort facility code definitions by there id ascending. */
  427. i = 0;
  428. while ((k = enum_facility (i)) != NULL)
  429. ++i;
  430. mc_facility_codes_count = i;
  431. if (i != 0)
  432. {
  433. mc_facility_codes = xmalloc (sizeof (mc_keyword *) * i);
  434. i = 0;
  435. while ((k = enum_facility (i)) != NULL)
  436. mc_facility_codes[i++] = (mc_keyword *) k;
  437. qsort (mc_facility_codes, (size_t) mc_facility_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
  438. }
  439. /* Sort severity code definitions by there id ascending. */
  440. i = 0;
  441. while ((k = enum_severity (i)) != NULL)
  442. ++i;
  443. mc_severity_codes_count = i;
  444. if (i != 0)
  445. {
  446. mc_severity_codes = xmalloc (sizeof (mc_keyword *) * i);
  447. i = 0;
  448. while ((k = enum_severity (i)) != NULL)
  449. mc_severity_codes[i++] = (mc_keyword *) k;
  450. qsort (mc_severity_codes, (size_t) mc_severity_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
  451. }
  452. }
  453. static int
  454. mc_get_block_count (mc_node_lang **nl, int elems)
  455. {
  456. rc_uint_type exid;
  457. int i, ret;
  458. if (! nl)
  459. return 0;
  460. i = 0;
  461. ret = 0;
  462. while (i < elems)
  463. {
  464. ret++;
  465. exid = nl[i++]->vid;
  466. while (i < elems && nl[i]->vid == exid + 1)
  467. exid = nl[i++]->vid;
  468. }
  469. return ret;
  470. }
  471. static bfd *
  472. windmc_open_as_binary (const char *filename)
  473. {
  474. bfd *abfd;
  475. abfd = bfd_openw (filename, "binary");
  476. if (! abfd)
  477. fatal ("can't open `%s' for output", filename);
  478. return abfd;
  479. }
  480. static void
  481. target_put_16 (void *p, rc_uint_type value)
  482. {
  483. assert (!! p);
  484. if (target_is_bigendian)
  485. bfd_putb16 (value, p);
  486. else
  487. bfd_putl16 (value, p);
  488. }
  489. static void
  490. target_put_32 (void *p, rc_uint_type value)
  491. {
  492. assert (!! p);
  493. if (target_is_bigendian)
  494. bfd_putb32 (value, p);
  495. else
  496. bfd_putl32 (value, p);
  497. }
  498. static struct bin_messagetable_item *
  499. mc_generate_bin_item (mc_node_lang *n, rc_uint_type *res_len)
  500. {
  501. struct bin_messagetable_item *ret = NULL;
  502. rc_uint_type len;
  503. *res_len = 0;
  504. if (mcset_bin_out_is_unicode == 1)
  505. {
  506. unichar *ht = n->message;
  507. rc_uint_type txt_len;
  508. txt_len = unichar_len (n->message);
  509. if (mcset_automatic_null_termination && txt_len != 0)
  510. {
  511. while (txt_len > 0 && ht[txt_len - 1] > 0 && ht[txt_len - 1] < 0x20)
  512. ht[--txt_len] = 0;
  513. }
  514. txt_len *= sizeof (unichar);
  515. len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + sizeof (unichar);
  516. ret = res_alloc ((len + 3) & ~3);
  517. memset (ret, 0, (len + 3) & ~3);
  518. target_put_16 (ret->length, (len + 3) & ~3);
  519. target_put_16 (ret->flags, MESSAGE_RESOURCE_UNICODE);
  520. txt_len = 0;
  521. while (*ht != 0)
  522. {
  523. target_put_16 (ret->data + txt_len, *ht++);
  524. txt_len += 2;
  525. }
  526. }
  527. else
  528. {
  529. rc_uint_type txt_len, l;
  530. char *cvt_txt;
  531. codepage_from_unicode( &l, n->message, &cvt_txt, n->lang->lang_info.wincp);
  532. if (! cvt_txt)
  533. fatal ("Failed to convert message to language codepage.\n");
  534. txt_len = strlen (cvt_txt);
  535. if (mcset_automatic_null_termination && txt_len > 0)
  536. {
  537. while (txt_len > 0 && cvt_txt[txt_len - 1] > 0 && cvt_txt[txt_len - 1] < 0x20)
  538. cvt_txt[--txt_len] = 0;
  539. }
  540. len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + 1;
  541. ret = res_alloc ((len + 3) & ~3);
  542. memset (ret, 0, (len + 3) & ~3);
  543. target_put_16 (ret->length, (len + 3) & ~3);
  544. target_put_16 (ret->flags, 0);
  545. strcpy ((char *) ret->data, cvt_txt);
  546. }
  547. *res_len = (len + 3) & ~3;
  548. return ret;
  549. }
  550. static void
  551. mc_write_blocks (struct bin_messagetable *mtbl, mc_node_lang **nl, mc_msg_item *ml, int elems)
  552. {
  553. int i, idx = 0;
  554. rc_uint_type exid;
  555. if (! nl)
  556. return;
  557. i = 0;
  558. while (i < elems)
  559. {
  560. target_put_32 (mtbl->items[idx].lowid, nl[i]->vid);
  561. target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
  562. target_put_32 (mtbl->items[idx].offset, ml[i].res_off);
  563. exid = nl[i++]->vid;
  564. while (i < elems && nl[i]->vid == exid + 1)
  565. {
  566. target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
  567. exid = nl[i++]->vid;
  568. }
  569. ++idx;
  570. }
  571. }
  572. static void
  573. set_windmc_bfd_content (const void *data, rc_uint_type off, rc_uint_type length)
  574. {
  575. if (! bfd_set_section_contents (mc_bfd.abfd, mc_bfd.sec, data, off, length))
  576. bfd_fatal ("bfd_set_section_contents");
  577. }
  578. static void
  579. windmc_write_bin (const char *filename, mc_node_lang **nl, int elems)
  580. {
  581. unsigned long sec_length = 1;
  582. int block_count, i;
  583. mc_msg_item *mi;
  584. struct bin_messagetable *mtbl;
  585. rc_uint_type dta_off, dta_start;
  586. if (elems <= 0)
  587. return;
  588. mc_bfd.abfd = windmc_open_as_binary (filename);
  589. mc_bfd.sec = bfd_make_section_with_flags (mc_bfd.abfd, ".data",
  590. (SEC_HAS_CONTENTS | SEC_ALLOC
  591. | SEC_LOAD | SEC_DATA));
  592. if (mc_bfd.sec == NULL)
  593. bfd_fatal ("bfd_make_section");
  594. /* Requiring this is probably a bug in BFD. */
  595. mc_bfd.sec->output_section = mc_bfd.sec;
  596. block_count = mc_get_block_count (nl, elems);
  597. dta_off = (rc_uint_type) ((BIN_MESSAGETABLE_BLOCK_SIZE * block_count) + BIN_MESSAGETABLE_SIZE - 4);
  598. dta_start = dta_off = (dta_off + 3) & ~3;
  599. mi = xmalloc (sizeof (mc_msg_item) * elems);
  600. mtbl = xmalloc (dta_start);
  601. /* Clear header region. */
  602. memset (mtbl, 0, dta_start);
  603. target_put_32 (mtbl->cblocks, block_count);
  604. /* Prepare items section for output. */
  605. for (i = 0; i < elems; i++)
  606. {
  607. mi[i].res_off = dta_off;
  608. mi[i].res = mc_generate_bin_item (nl[i], &mi[i].res_len);
  609. dta_off += mi[i].res_len;
  610. }
  611. sec_length = (dta_off + 3) & ~3;
  612. if (! bfd_set_section_size (mc_bfd.abfd, mc_bfd.sec, sec_length))
  613. bfd_fatal ("bfd_set_section_size");
  614. /* Make sure we write the complete block. */
  615. set_windmc_bfd_content ("\0", sec_length - 1, 1);
  616. /* Write block information. */
  617. mc_write_blocks (mtbl, nl, mi, elems);
  618. set_windmc_bfd_content (mtbl, 0, dta_start);
  619. /* Write items. */
  620. for (i = 0; i < elems; i++)
  621. set_windmc_bfd_content (mi[i].res, mi[i].res_off, mi[i].res_len);
  622. free (mtbl);
  623. free (mi);
  624. bfd_close (mc_bfd.abfd);
  625. mc_bfd.abfd = NULL;
  626. mc_bfd.sec = NULL;
  627. }
  628. static void
  629. write_bin (void)
  630. {
  631. mc_node_lang *n = NULL;
  632. int i, c;
  633. if (! mc_nodes_lang_count)
  634. return;
  635. i = 0;
  636. while (i < mc_nodes_lang_count)
  637. {
  638. char *nd;
  639. char *filename;
  640. if (n && n->lang == mc_nodes_lang[i]->lang)
  641. {
  642. i++;
  643. continue;
  644. }
  645. n = mc_nodes_lang[i];
  646. c = i + 1;
  647. while (c < mc_nodes_lang_count && n->lang == mc_nodes_lang[c]->lang)
  648. c++;
  649. nd = convert_unicode_to_ACP (n->lang->sval);
  650. /* Prepare filename for binary output. */
  651. filename = xmalloc (strlen (nd) + 4 + 1 + strlen (mcset_mc_basename) + 1 + strlen (mcset_rc_dir));
  652. strcpy (filename, mcset_rc_dir);
  653. if (mcset_prefix_bin)
  654. sprintf (filename + strlen (filename), "%s_", mcset_mc_basename);
  655. strcat (filename, nd);
  656. strcat (filename, ".bin");
  657. /* Write message file. */
  658. windmc_write_bin (filename, &mc_nodes_lang[i], (c - i));
  659. free (filename);
  660. i = c;
  661. }
  662. }
  663. static void
  664. write_rc (FILE *fp)
  665. {
  666. mc_node_lang *n;
  667. int i, l;
  668. fprintf (fp,
  669. "/* Do not edit this file manually.\n"
  670. " This file is autogenerated by windmc. */\n\n");
  671. if (! mc_nodes_lang_count)
  672. return;
  673. n = NULL;
  674. i = 0;
  675. for (l = 0; l < mc_nodes_lang_count; l++)
  676. {
  677. if (n && n->lang == mc_nodes_lang[l]->lang)
  678. continue;
  679. ++i;
  680. n = mc_nodes_lang[l];
  681. fprintf (fp, "\n// Country: %s\n// Language: %s\n#pragma code_page(%u)\n",
  682. n->lang->lang_info.country, n->lang->lang_info.name,
  683. (unsigned) n->lang->lang_info.wincp);
  684. fprintf (fp, "LANGUAGE 0x%lx, 0x%lx\n",
  685. (unsigned long) (n->lang->nval & 0x3ff),
  686. (unsigned long) ((n->lang->nval & 0xffff) >> 10));
  687. fprintf (fp, "1 MESSAGETABLE \"");
  688. if (mcset_prefix_bin)
  689. fprintf (fp, "%s_", mcset_mc_basename);
  690. unicode_print (fp, n->lang->sval, unichar_len (n->lang->sval));
  691. fprintf (fp, ".bin\"\n");
  692. }
  693. }
  694. static void
  695. write_dbg (FILE *fp)
  696. {
  697. mc_node *h;
  698. fprintf (fp,
  699. "/* Do not edit this file manually.\n"
  700. " This file is autogenerated by windmc.\n\n"
  701. " This file maps each message ID value in to a text string that contains\n"
  702. " the symbolic name used for it. */\n\n");
  703. fprintf (fp,
  704. "struct %sSymbolicName\n"
  705. "{\n ", mcset_mc_basename);
  706. if (mcset_msg_id_typedef)
  707. unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
  708. else
  709. fprintf (fp, "DWORD");
  710. fprintf (fp,
  711. " MessageId;\n"
  712. " char *SymbolicName;\n"
  713. "} %sSymbolicNames[] =\n"
  714. "{\n", mcset_mc_basename);
  715. h = mc_nodes;
  716. while (h != NULL)
  717. {
  718. if (h->symbol)
  719. write_dbg_define (fp, h->symbol, mcset_msg_id_typedef);
  720. h = h->next;
  721. }
  722. fprintf (fp, " { (");
  723. if (mcset_msg_id_typedef)
  724. unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
  725. else
  726. fprintf (fp, "DWORD");
  727. fprintf (fp,
  728. ") 0xffffffff, NULL }\n"
  729. "};\n");
  730. }
  731. static void
  732. write_header (FILE *fp)
  733. {
  734. char *s;
  735. int i;
  736. const mc_keyword *key;
  737. mc_node *h;
  738. fprintf (fp,
  739. "/* Do not edit this file manually.\n"
  740. " This file is autogenerated by windmc. */\n\n"
  741. "//\n// The values are 32 bit layed out as follows:\n//\n"
  742. "// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n"
  743. "// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0\n"
  744. "// +---+-+-+-----------------------+-------------------------------+\n"
  745. "// |Sev|C|R| Facility | Code |\n"
  746. "// +---+-+-+-----------------------+-------------------------------+\n//\n"
  747. "// where\n//\n"
  748. "// C - is the Customer code flag\n//\n"
  749. "// R - is a reserved bit\n//\n"
  750. "// Code - is the facility's status code\n//\n");
  751. h = mc_nodes;
  752. fprintf (fp, "// Sev - is the severity code\n//\n");
  753. if (mc_severity_codes_count != 0)
  754. {
  755. for (i = 0; i < mc_severity_codes_count; i++)
  756. {
  757. key = mc_severity_codes[i];
  758. fprintf (fp, "// %s - %02lx\n", convert_unicode_to_ACP (key->usz),
  759. (unsigned long) key->nval);
  760. if (key->sval && key->sval[0] != 0)
  761. {
  762. if (! mcset_out_values_are_decimal)
  763. fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
  764. (unsigned long) key->nval);
  765. else
  766. fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
  767. (unsigned long) key->nval);
  768. }
  769. }
  770. fprintf (fp, "//\n");
  771. }
  772. fprintf (fp, "// Facility - is the facility code\n//\n");
  773. if (mc_facility_codes_count != 0)
  774. {
  775. for (i = 0; i < mc_facility_codes_count; i++)
  776. {
  777. key = mc_facility_codes[i];
  778. fprintf (fp, "// %s - %04lx\n", convert_unicode_to_ACP (key->usz),
  779. (unsigned long) key->nval);
  780. if (key->sval && key->sval[0] != 0)
  781. {
  782. if (! mcset_out_values_are_decimal)
  783. fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
  784. (unsigned long) key->nval);
  785. else
  786. fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
  787. (unsigned long) key->nval);
  788. }
  789. }
  790. fprintf (fp, "//\n");
  791. }
  792. fprintf (fp, "\n");
  793. while (h != NULL)
  794. {
  795. if (h->user_text)
  796. {
  797. s = convert_unicode_to_ACP (h->user_text);
  798. if (s)
  799. fprintf (fp, "%s", s);
  800. }
  801. if (h->symbol)
  802. write_header_define (fp, h->symbol, h->vid, mcset_msg_id_typedef, h->sub);
  803. h = h->next;
  804. }
  805. }
  806. static const char *
  807. mc_unify_path (const char *path)
  808. {
  809. char *end;
  810. char *hsz;
  811. if (! path || *path == 0)
  812. return "./";
  813. hsz = xmalloc (strlen (path) + 2);
  814. strcpy (hsz, path);
  815. end = hsz + strlen (hsz);
  816. if (hsz[-1] != '/' && hsz[-1] != '\\')
  817. strcpy (end, "/");
  818. while ((end = strchr (hsz, '\\')) != NULL)
  819. *end = '/';
  820. return hsz;
  821. }
  822. int main (int, char **);
  823. int
  824. main (int argc, char **argv)
  825. {
  826. FILE *h_fp;
  827. int c;
  828. char *target, *input_filename;
  829. int verbose;
  830. #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
  831. setlocale (LC_MESSAGES, "");
  832. #endif
  833. #if defined (HAVE_SETLOCALE)
  834. setlocale (LC_CTYPE, "");
  835. #endif
  836. bindtextdomain (PACKAGE, LOCALEDIR);
  837. textdomain (PACKAGE);
  838. program_name = argv[0];
  839. xmalloc_set_program_name (program_name);
  840. bfd_set_error_program_name (program_name);
  841. expandargv (&argc, &argv);
  842. bfd_init ();
  843. set_default_bfd_target ();
  844. target = NULL;
  845. verbose = 0;
  846. input_filename = NULL;
  847. res_init ();
  848. while ((c = getopt_long (argc, argv, "C:F:O:h:e:m:r:x:aAbcdHunoUvV", long_options,
  849. (int *) 0)) != EOF)
  850. {
  851. switch (c)
  852. {
  853. case 'b':
  854. mcset_prefix_bin = 1;
  855. break;
  856. case 'e':
  857. {
  858. mcset_header_ext = optarg;
  859. if (mcset_header_ext[0] != '.' && mcset_header_ext[0] != 0)
  860. {
  861. char *hsz = xmalloc (strlen (mcset_header_ext) + 2);
  862. sprintf (hsz, ".%s", mcset_header_ext);
  863. mcset_header_ext = hsz;
  864. }
  865. }
  866. break;
  867. case 'h':
  868. mcset_header_dir = mc_unify_path (optarg);
  869. break;
  870. case 'r':
  871. mcset_rc_dir = mc_unify_path (optarg);
  872. break;
  873. case 'a':
  874. mcset_text_in_is_unicode = 0;
  875. break;
  876. case 'x':
  877. if (*optarg != 0)
  878. mcset_dbg_dir = mc_unify_path (optarg);
  879. break;
  880. case 'A':
  881. mcset_bin_out_is_unicode = 0;
  882. break;
  883. case 'd':
  884. mcset_out_values_are_decimal = 1;
  885. break;
  886. case 'u':
  887. mcset_text_in_is_unicode = 1;
  888. break;
  889. case 'U':
  890. mcset_bin_out_is_unicode = 1;
  891. break;
  892. case 'c':
  893. mcset_custom_bit = 1;
  894. break;
  895. case 'n':
  896. mcset_automatic_null_termination = 1;
  897. break;
  898. case 'o':
  899. mcset_use_hresult = 1;
  900. fatal ("option -o is not implemented until yet.\n");
  901. break;
  902. case 'F':
  903. target = optarg;
  904. break;
  905. case 'v':
  906. verbose ++;
  907. break;
  908. case 'm':
  909. mcset_max_message_length = strtol (optarg, (char **) NULL, 10);
  910. break;
  911. case 'C':
  912. mcset_codepage_in = strtol (optarg, (char **) NULL, 10);
  913. break;
  914. case 'O':
  915. mcset_codepage_out = strtol (optarg, (char **) NULL, 10);
  916. break;
  917. case '?':
  918. case 'H':
  919. usage (stdout, 0);
  920. break;
  921. case 'V':
  922. print_version ("windmc");
  923. break;
  924. default:
  925. usage (stderr, 1);
  926. break;
  927. }
  928. }
  929. if (input_filename == NULL && optind < argc)
  930. {
  931. input_filename = argv[optind];
  932. ++optind;
  933. }
  934. set_endianness (NULL, target);
  935. if (input_filename == NULL)
  936. {
  937. fprintf (stderr, "Error: No input file was specified.\n");
  938. usage (stderr, 1);
  939. }
  940. mc_set_inputfile (input_filename);
  941. if (!probe_codepage (&mcset_codepage_in, &mcset_text_in_is_unicode, "codepage_in", 0))
  942. usage (stderr, 1);
  943. if (mcset_codepage_out == 0)
  944. mcset_codepage_out = 1252;
  945. if (! unicode_is_valid_codepage (mcset_codepage_out))
  946. fatal ("Code page 0x%x is unknown.", (unsigned int) mcset_codepage_out);
  947. if (mcset_codepage_out == CP_UTF16)
  948. fatal ("UTF16 is no valid text output code page.");
  949. if (verbose)
  950. {
  951. fprintf (stderr, "// Default target is %s and it is %s endian.\n",
  952. def_target_arch, (target_is_bigendian ? "big" : "little"));
  953. fprintf (stderr, "// Input codepage: 0x%x\n", (unsigned int) mcset_codepage_in);
  954. fprintf (stderr, "// Output codepage: 0x%x\n", (unsigned int) mcset_codepage_out);
  955. }
  956. if (argc != optind)
  957. usage (stderr, 1);
  958. /* Initialize mcset_mc_basename. */
  959. {
  960. const char *bn, *bn2;
  961. char *hsz;
  962. bn = strrchr (input_filename, '/');
  963. bn2 = strrchr (input_filename, '\\');
  964. if (! bn)
  965. bn = bn2;
  966. if (bn && bn2 && bn < bn2)
  967. bn = bn2;
  968. if (! bn)
  969. bn = input_filename;
  970. else
  971. bn++;
  972. mcset_mc_basename = hsz = xstrdup (bn);
  973. /* Cut of right-hand extension. */
  974. if ((hsz = strrchr (hsz, '.')) != NULL)
  975. *hsz = 0;
  976. }
  977. /* Load the input file and do code page transformations to UTF16. */
  978. {
  979. unichar *u;
  980. rc_uint_type ul;
  981. char *buff;
  982. bfd_size_type flen;
  983. FILE *fp = fopen (input_filename, "rb");
  984. if (!fp)
  985. fatal (_("unable to open file `%s' for input.\n"), input_filename);
  986. fseek (fp, 0, SEEK_END);
  987. flen = ftell (fp);
  988. fseek (fp, 0, SEEK_SET);
  989. buff = malloc (flen + 3);
  990. memset (buff, 0, flen + 3);
  991. if (fread (buff, 1, flen, fp) < flen)
  992. fatal (_("unable to read contents of %s"), input_filename);
  993. fclose (fp);
  994. if (mcset_text_in_is_unicode != 1)
  995. {
  996. unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
  997. if (! u)
  998. fatal ("Failed to convert input to UFT16\n");
  999. mc_set_content (u);
  1000. }
  1001. else
  1002. {
  1003. if ((flen & 1) != 0)
  1004. fatal (_("input file does not seems to be UFT16.\n"));
  1005. mc_set_content ((unichar *) buff);
  1006. }
  1007. free (buff);
  1008. }
  1009. while (yyparse ())
  1010. ;
  1011. do_sorts ();
  1012. h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
  1013. write_header (h_fp);
  1014. fclose (h_fp);
  1015. h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
  1016. write_rc (h_fp);
  1017. fclose (h_fp);
  1018. if (mcset_dbg_dir != NULL)
  1019. {
  1020. h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
  1021. write_dbg (h_fp);
  1022. fclose (h_fp);
  1023. }
  1024. write_bin ();
  1025. if (mc_nodes_lang)
  1026. free (mc_nodes_lang);
  1027. if (mc_severity_codes)
  1028. free (mc_severity_codes);
  1029. if (mc_facility_codes)
  1030. free (mc_facility_codes);
  1031. xexit (0);
  1032. return 0;
  1033. }