windmc.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  1. /* windmc.c -- a program to compile Windows message files.
  2. Copyright (C) 2007-2022 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. bool 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: %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 %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.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, h->id_typecast);
  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 %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 %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, h->id_typecast, 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 (end[-1] != '/' && end[-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. #ifdef HAVE_LC_MESSAGES
  831. setlocale (LC_MESSAGES, "");
  832. #endif
  833. setlocale (LC_CTYPE, "");
  834. bindtextdomain (PACKAGE, LOCALEDIR);
  835. textdomain (PACKAGE);
  836. program_name = argv[0];
  837. xmalloc_set_program_name (program_name);
  838. bfd_set_error_program_name (program_name);
  839. expandargv (&argc, &argv);
  840. if (bfd_init () != BFD_INIT_MAGIC)
  841. fatal (_("fatal error: libbfd ABI mismatch"));
  842. set_default_bfd_target ();
  843. target = NULL;
  844. verbose = 0;
  845. input_filename = NULL;
  846. res_init ();
  847. while ((c = getopt_long (argc, argv, "C:F:O:h:e:m:r:x:aAbcdHunoUvV", long_options,
  848. (int *) 0)) != EOF)
  849. {
  850. switch (c)
  851. {
  852. case 'b':
  853. mcset_prefix_bin = 1;
  854. break;
  855. case 'e':
  856. {
  857. mcset_header_ext = optarg;
  858. if (mcset_header_ext[0] != '.' && mcset_header_ext[0] != 0)
  859. {
  860. char *hsz = xmalloc (strlen (mcset_header_ext) + 2);
  861. sprintf (hsz, ".%s", mcset_header_ext);
  862. mcset_header_ext = hsz;
  863. }
  864. }
  865. break;
  866. case 'h':
  867. mcset_header_dir = mc_unify_path (optarg);
  868. break;
  869. case 'r':
  870. mcset_rc_dir = mc_unify_path (optarg);
  871. break;
  872. case 'a':
  873. mcset_text_in_is_unicode = 0;
  874. break;
  875. case 'x':
  876. if (*optarg != 0)
  877. mcset_dbg_dir = mc_unify_path (optarg);
  878. break;
  879. case 'A':
  880. mcset_bin_out_is_unicode = 0;
  881. break;
  882. case 'd':
  883. mcset_out_values_are_decimal = 1;
  884. break;
  885. case 'u':
  886. mcset_text_in_is_unicode = 1;
  887. break;
  888. case 'U':
  889. mcset_bin_out_is_unicode = 1;
  890. break;
  891. case 'c':
  892. mcset_custom_bit = 1;
  893. break;
  894. case 'n':
  895. mcset_automatic_null_termination = 1;
  896. break;
  897. case 'o':
  898. mcset_use_hresult = 1;
  899. fatal ("option -o is not implemented until yet.\n");
  900. break;
  901. case 'F':
  902. target = optarg;
  903. break;
  904. case 'v':
  905. verbose ++;
  906. break;
  907. case 'm':
  908. mcset_max_message_length = strtol (optarg, (char **) NULL, 10);
  909. break;
  910. case 'C':
  911. mcset_codepage_in = strtol (optarg, (char **) NULL, 10);
  912. break;
  913. case 'O':
  914. mcset_codepage_out = strtol (optarg, (char **) NULL, 10);
  915. break;
  916. case '?':
  917. case 'H':
  918. usage (stdout, 0);
  919. break;
  920. case 'V':
  921. print_version ("windmc");
  922. break;
  923. default:
  924. usage (stderr, 1);
  925. break;
  926. }
  927. }
  928. if (input_filename == NULL && optind < argc)
  929. {
  930. input_filename = argv[optind];
  931. ++optind;
  932. }
  933. set_endianness (NULL, target);
  934. if (input_filename == NULL)
  935. {
  936. fprintf (stderr, "Error: No input file was specified.\n");
  937. usage (stderr, 1);
  938. }
  939. mc_set_inputfile (input_filename);
  940. if (!probe_codepage (&mcset_codepage_in, &mcset_text_in_is_unicode, "codepage_in", 0))
  941. usage (stderr, 1);
  942. if (mcset_codepage_out == 0)
  943. mcset_codepage_out = 1252;
  944. if (! unicode_is_valid_codepage (mcset_codepage_out))
  945. fatal ("Code page 0x%x is unknown.", (unsigned int) mcset_codepage_out);
  946. if (mcset_codepage_out == CP_UTF16)
  947. fatal ("UTF16 is no valid text output code page.");
  948. if (verbose)
  949. {
  950. fprintf (stderr, "// Default target is %s and it is %s endian.\n",
  951. def_target_arch, (target_is_bigendian ? "big" : "little"));
  952. fprintf (stderr, "// Input codepage: 0x%x\n", (unsigned int) mcset_codepage_in);
  953. fprintf (stderr, "// Output codepage: 0x%x\n", (unsigned int) mcset_codepage_out);
  954. }
  955. if (argc != optind)
  956. usage (stderr, 1);
  957. /* Initialize mcset_mc_basename. */
  958. {
  959. const char *bn, *bn2;
  960. char *hsz;
  961. bn = strrchr (input_filename, '/');
  962. bn2 = strrchr (input_filename, '\\');
  963. if (! bn)
  964. bn = bn2;
  965. if (bn && bn2 && bn < bn2)
  966. bn = bn2;
  967. if (! bn)
  968. bn = input_filename;
  969. else
  970. bn++;
  971. mcset_mc_basename = hsz = xstrdup (bn);
  972. /* Cut of right-hand extension. */
  973. if ((hsz = strrchr (hsz, '.')) != NULL)
  974. *hsz = 0;
  975. }
  976. /* Load the input file and do code page transformations to UTF16. */
  977. {
  978. unichar *u;
  979. rc_uint_type ul;
  980. char *buff;
  981. bfd_size_type flen;
  982. FILE *fp = fopen (input_filename, "rb");
  983. if (!fp)
  984. fatal (_("unable to open file `%s' for input.\n"), input_filename);
  985. fseek (fp, 0, SEEK_END);
  986. flen = ftell (fp);
  987. fseek (fp, 0, SEEK_SET);
  988. buff = malloc (flen + 3);
  989. memset (buff, 0, flen + 3);
  990. if (fread (buff, 1, flen, fp) < flen)
  991. fatal (_("unable to read contents of %s"), input_filename);
  992. fclose (fp);
  993. if (mcset_text_in_is_unicode != 1)
  994. {
  995. unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
  996. if (! u)
  997. fatal ("Failed to convert input to UFT16\n");
  998. mc_set_content (u);
  999. }
  1000. else
  1001. {
  1002. if ((flen & 1) != 0)
  1003. fatal (_("input file does not seems to be UFT16.\n"));
  1004. mc_set_content ((unichar *) buff);
  1005. }
  1006. free (buff);
  1007. }
  1008. while (yyparse ())
  1009. ;
  1010. do_sorts ();
  1011. h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
  1012. write_header (h_fp);
  1013. fclose (h_fp);
  1014. h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
  1015. write_rc (h_fp);
  1016. fclose (h_fp);
  1017. if (mcset_dbg_dir != NULL)
  1018. {
  1019. h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
  1020. write_dbg (h_fp);
  1021. fclose (h_fp);
  1022. }
  1023. write_bin ();
  1024. free (mc_nodes_lang);
  1025. free (mc_severity_codes);
  1026. free (mc_facility_codes);
  1027. xexit (0);
  1028. return 0;
  1029. }