123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173 |
- /* windmc.c -- a program to compile Windows message files.
- Copyright (C) 2007-2015 Free Software Foundation, Inc.
- Written by Kai Tietz, Onevision.
- This file is part of GNU Binutils.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
- /* This program can read and comile Windows message format.
- It is based on information taken from the following sources:
- * Microsoft documentation.
- * The wmc program, written by Bertho A. Stultiens (BS). */
- #include "sysdep.h"
- #include <assert.h>
- #include <time.h>
- #include "bfd.h"
- #include "getopt.h"
- #include "bucomm.h"
- #include "libiberty.h"
- #include "safe-ctype.h"
- #include "obstack.h"
- #include "windmc.h"
- #include "windint.h"
- /* Defines a message compiler element item with length and offset
- information. */
- typedef struct mc_msg_item
- {
- rc_uint_type res_len;
- rc_uint_type res_off;
- struct bin_messagetable_item *res;
- } mc_msg_item;
- int target_is_bigendian = 0;
- const char *def_target_arch;
- /* Globals and static variable definitions. */
- /* bfd global helper struct variable. */
- static struct
- {
- bfd *abfd;
- asection *sec;
- } mc_bfd;
- /* Memory list. */
- mc_node *mc_nodes = NULL;
- static mc_node_lang **mc_nodes_lang = NULL;
- static int mc_nodes_lang_count = 0;
- static mc_keyword **mc_severity_codes = NULL;
- static int mc_severity_codes_count = 0;
- static mc_keyword **mc_facility_codes = NULL;
- static int mc_facility_codes_count = 0;
- /* When we are building a resource tree, we allocate everything onto
- an obstack, so that we can free it all at once if we want. */
- #define obstack_chunk_alloc xmalloc
- #define obstack_chunk_free free
- /* The resource building obstack. */
- static struct obstack res_obstack;
- /* Flag variables. */
- /* Set by -C. Set the default code page to be used for input text file. */
- static rc_uint_type mcset_codepage_in = 0;
- /* Set by -O. Set the default code page to be used for output text files. */
- static rc_uint_type mcset_codepage_out = 0;
- /* Set by -b. .BIN filename should have .mc filename_ included for uniqueness. */
- static int mcset_prefix_bin = 0;
- /* The base name of the .mc file. */
- static const char *mcset_mc_basename = "unknown";
- /* Set by -e <ext>. Specify the extension for the header file. */
- static const char *mcset_header_ext = ".h";
- /* Set by -h <path>. Gives the path of where to create the C include file. */
- static const char *mcset_header_dir = "./";
- /* Set by -r <path>. Gives the path of where to create the RC include file
- and the binary message resource files it includes. */
- static const char *mcset_rc_dir = "./";
- /* Modified by -a & -u. By -u input file is unicode, by -a is ASCII (default). */
- static int mcset_text_in_is_unicode = 0;
- /* Modified by -A & -U. By -U bin file is unicode (default), by -A is ASCII. */
- static int mcset_bin_out_is_unicode = 1;
- /* Set by -c. Sets the Customer bit in all the message ID's. */
- int mcset_custom_bit = 0;
- /* Set by -o. Generate OLE2 header file. Use HRESULT definition instead of
- status code definition. */
- static int mcset_use_hresult = 0;
- /* Set by -m <msglen>. Generate a warning if the size of any message exceeds
- maxmsglen characters. */
- rc_uint_type mcset_max_message_length = 0;
- /* Set by -d. Sets message values in header to decimal initially. */
- int mcset_out_values_are_decimal = 0;
- /* Set by -n. terminates all strings with null's in the message tables. */
- static int mcset_automatic_null_termination = 0;
- /* The type used for message id output in header. */
- unichar *mcset_msg_id_typedef = NULL;
- /* Set by -x path. Geberated debug C file for mapping ID's to text. */
- static const char *mcset_dbg_dir = NULL;
- /* getopt long name definitions. */
- static const struct option long_options[] =
- {
- {"binprefix", no_argument, 0, 'b'},
- {"target", required_argument, 0, 'F'},
- {"extension", required_argument, 0, 'e'},
- {"headerdir", required_argument, 0, 'h'},
- {"rcdir", required_argument, 0, 'r'},
- {"verbose", no_argument, 0, 'v'},
- {"codepage_in", required_argument, 0, 'C'},
- {"codepage_out", required_argument, 0, 'O'},
- {"maxlength", required_argument, 0, 'm'},
- {"ascii_in", no_argument, 0, 'a'},
- {"ascii_out", no_argument, 0, 'A'},
- {"unicode_in", no_argument, 0, 'u'},
- {"unicode_out", no_argument, 0, 'U'},
- {"customflag", no_argument, 0, 'c'},
- {"decimal_values", no_argument, 0, 'd'},
- {"hresult_use", no_argument, 0, 'o'},
- {"nullterminate", no_argument, 0, 'n'},
- {"xdbg", required_argument, 0, 'x'},
- {"version", no_argument, 0, 'V'},
- {"help", no_argument, 0, 'H'},
- {0, no_argument, 0, 0}
- };
- /* Initialize the resource building obstack. */
- static void
- res_init (void)
- {
- obstack_init (&res_obstack);
- }
- /* Allocate space on the resource building obstack. */
- void *
- res_alloc (rc_uint_type bytes)
- {
- return obstack_alloc (&res_obstack, (size_t) bytes);
- }
- static FILE *
- mc_create_path_text_file (const char *path, const char *ext)
- {
- FILE *ret;
- size_t len = 1;
- char *hsz;
- len += (path != NULL ? strlen (path) : 0);
- len += strlen (mcset_mc_basename);
- len += (ext != NULL ? strlen (ext) : 0);
- hsz = xmalloc (len);
- sprintf (hsz, "%s%s%s", (path != NULL ? path : ""), mcset_mc_basename,
- (ext != NULL ? ext : ""));
- if ((ret = fopen (hsz, "wb")) == NULL)
- fatal (_("can't create %s file `%s' for output.\n"), (ext ? ext : "text"), hsz);
- free (hsz);
- return ret;
- }
- static void
- usage (FILE *stream, int status)
- {
- fprintf (stream, _("Usage: %s [option(s)] [input-file]\n"),
- program_name);
- fprintf (stream, _(" The options are:\n\
- -a --ascii_in Read input file as ASCII file\n\
- -A --ascii_out Write binary messages as ASCII\n\
- -b --binprefix .bin filename is prefixed by .mc filename_ for uniqueness.\n\
- -c --customflag Set custom flags for messages\n\
- -C --codepage_in=<val> Set codepage when reading mc text file\n\
- -d --decimal_values Print values to text files decimal\n\
- -e --extension=<extension> Set header extension used on export header file\n\
- -F --target <target> Specify output target for endianness.\n\
- -h --headerdir=<directory> Set the export directory for headers\n\
- -u --unicode_in Read input file as UTF16 file\n\
- -U --unicode_out Write binary messages as UFT16\n\
- -m --maxlength=<val> Set the maximal allowed message length\n\
- -n --nullterminate Automatic add a zero termination to strings\n\
- -o --hresult_use Use HRESULT definition instead of status code definition\n\
- -O --codepage_out=<val> Set codepage used for writing text file\n\
- -r --rcdir=<directory> Set the export directory for rc files\n\
- -x --xdbg=<directory> Where to create the .dbg C include file\n\
- that maps message ID's to their symbolic name.\n\
- "));
- fprintf (stream, _("\
- -H --help Print this help message\n\
- -v --verbose Verbose - tells you what it's doing\n\
- -V --version Print version information\n"));
- list_supported_targets (program_name, stream);
- if (REPORT_BUGS_TO[0] && status == 0)
- fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
- exit (status);
- }
- static void
- set_endianness (bfd *abfd, const char *target)
- {
- const bfd_target *target_vec;
- def_target_arch = NULL;
- target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
- &def_target_arch);
- if (! target_vec)
- fatal ("Can't detect target endianness and architecture.");
- if (! def_target_arch)
- fatal ("Can't detect architecture.");
- }
- static int
- probe_codepage (rc_uint_type *cp, int *is_uni, const char *pswitch, int defmode)
- {
- if (*is_uni == -1)
- {
- if (*cp != CP_UTF16)
- *is_uni = defmode;
- else
- *is_uni = 1;
- }
- if (*is_uni)
- {
- if (*cp != 0 && *cp != CP_UTF16)
- {
- fprintf (stderr, _("%s: warning: "), program_name);
- fprintf (stderr, _("A codepage was specified switch `%s' and UTF16.\n"), pswitch);
- fprintf (stderr, _("\tcodepage settings are ignored.\n"));
- }
- *cp = CP_UTF16;
- return 1;
- }
- if (*cp == CP_UTF16)
- {
- *is_uni = 1;
- return 1;
- }
- if (*cp == 0)
- *cp = 1252;
- if (! unicode_is_valid_codepage (*cp))
- fatal ("Code page 0x%x is unknown.", (unsigned int) *cp);
- *is_uni = 0;
- return 1;
- }
- mc_node *
- mc_add_node (void)
- {
- mc_node *ret;
- ret = res_alloc (sizeof (mc_node));
- memset (ret, 0, sizeof (mc_node));
- if (! mc_nodes)
- mc_nodes = ret;
- else
- {
- mc_node *h = mc_nodes;
- while (h->next != NULL)
- h = h->next;
- h->next = ret;
- }
- return ret;
- }
- mc_node_lang *
- mc_add_node_lang (mc_node *root, const mc_keyword *lang, rc_uint_type vid)
- {
- mc_node_lang *ret, *h, *p;
- if (! lang || ! root)
- fatal (_("try to add a ill language."));
- ret = res_alloc (sizeof (mc_node_lang));
- memset (ret, 0, sizeof (mc_node_lang));
- ret->lang = lang;
- ret->vid = vid;
- if ((h = root->sub) == NULL)
- root->sub = ret;
- else
- {
- p = NULL;
- while (h != NULL)
- {
- if (h->lang->nval > lang->nval)
- break;
- if (h->lang->nval == lang->nval)
- {
- if (h->vid > vid)
- break;
- if (h->vid == vid)
- fatal ("double defined message id %ld.\n", (long) vid);
- }
- h = (p = h)->next;
- }
- ret->next = h;
- if (! p)
- root->sub = ret;
- else
- p->next = ret;
- }
- return ret;
- }
- static char *
- convert_unicode_to_ACP (const unichar *usz)
- {
- char *s;
- rc_uint_type l;
- if (! usz)
- return NULL;
- codepage_from_unicode (&l, usz, &s, mcset_codepage_out);
- if (! s)
- fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n",
- (unsigned long) mcset_codepage_out);
- return s;
- }
- static void
- write_dbg_define (FILE *fp, const unichar *sym_name, const unichar *typecast)
- {
- char *sym;
- if (!sym_name || sym_name[0] == 0)
- return;
- sym = convert_unicode_to_ACP (sym_name);
- fprintf (fp, " {(");
- if (typecast)
- unicode_print (fp, typecast, unichar_len (typecast));
- else
- fprintf (fp, "DWORD");
- fprintf (fp, ") %s, \"%s\" },\n", sym, sym);
- }
- static void
- write_header_define (FILE *fp, const unichar *sym_name, rc_uint_type vid, const unichar *typecast, mc_node_lang *nl)
- {
- char *sym;
- char *tdef = NULL;
- if (!sym_name || sym_name[0] == 0)
- {
- if (nl != NULL)
- {
- if (mcset_out_values_are_decimal)
- fprintf (fp, "//\n// MessageId: 0x%lu\n//\n", (unsigned long) vid);
- else
- fprintf (fp, "//\n// MessageId: 0x%lx\n//\n", (unsigned long) vid);
- }
- return;
- }
- sym = convert_unicode_to_ACP (sym_name);
- if (typecast && typecast[0] != 0)
- tdef = convert_unicode_to_ACP (typecast);
- fprintf (fp, "//\n// MessageId: %s\n//\n", sym);
- if (! mcset_out_values_are_decimal)
- fprintf (fp, "#define %s %s%s%s 0x%lx\n\n", sym,
- (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
- (unsigned long) vid);
- else
- fprintf (fp, "#define %s %s%s%s 0x%lu\n\n", sym,
- (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
- (unsigned long) vid);
- }
- static int
- sort_mc_node_lang (const void *l, const void *r)
- {
- const mc_node_lang *l1 = *((const mc_node_lang **)l);
- const mc_node_lang *r1 = *((const mc_node_lang **)r);
- if (l == r)
- return 0;
- if (l1->lang != r1->lang)
- {
- if (l1->lang->nval < r1->lang->nval)
- return -1;
- return 1;
- }
- if (l1->vid == r1->vid)
- return 0;
- if (l1->vid < r1->vid)
- return -1;
- return 1;
- }
- static int
- sort_keyword_by_nval (const void *l, const void *r)
- {
- const mc_keyword *l1 = *((const mc_keyword **)l);
- const mc_keyword *r1 = *((const mc_keyword **)r);
- rc_uint_type len1, len2;
- int e;
- if (l == r)
- return 0;
- if (l1->nval != r1->nval)
- {
- if (l1->nval < r1->nval)
- return -1;
- return 1;
- }
- len1 = unichar_len (l1->usz);
- len2 = unichar_len (r1->usz);
- if (len1 <= len2)
- e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len1);
- else
- e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len2);
- if (e)
- return e;
- if (len1 < len2)
- return -1;
- else if (len1 > len2)
- return 1;
- return 0;
- }
- static void
- do_sorts (void)
- {
- mc_node *h;
- mc_node_lang *n;
- const mc_keyword *k;
- int i;
- /* Sort message by their language and id ascending. */
- mc_nodes_lang_count = 0;
- h = mc_nodes;
- while (h != NULL)
- {
- n = h->sub;
- while (n != NULL)
- {
- mc_nodes_lang_count +=1;
- n = n->next;
- }
- h = h->next;
- }
- if (mc_nodes_lang_count != 0)
- {
- h = mc_nodes;
- i = 0;
- mc_nodes_lang = xmalloc (sizeof (mc_node_lang *) * mc_nodes_lang_count);
- while (h != NULL)
- {
- n = h->sub;
- while (n != NULL)
- {
- mc_nodes_lang[i++] = n;
- n = n->next;
- }
- h = h->next;
- }
- qsort (mc_nodes_lang, (size_t) mc_nodes_lang_count, sizeof (mc_node_lang *), sort_mc_node_lang);
- }
- /* Sort facility code definitions by there id ascending. */
- i = 0;
- while ((k = enum_facility (i)) != NULL)
- ++i;
- mc_facility_codes_count = i;
- if (i != 0)
- {
- mc_facility_codes = xmalloc (sizeof (mc_keyword *) * i);
- i = 0;
- while ((k = enum_facility (i)) != NULL)
- mc_facility_codes[i++] = (mc_keyword *) k;
- qsort (mc_facility_codes, (size_t) mc_facility_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
- }
- /* Sort severity code definitions by there id ascending. */
- i = 0;
- while ((k = enum_severity (i)) != NULL)
- ++i;
- mc_severity_codes_count = i;
- if (i != 0)
- {
- mc_severity_codes = xmalloc (sizeof (mc_keyword *) * i);
- i = 0;
- while ((k = enum_severity (i)) != NULL)
- mc_severity_codes[i++] = (mc_keyword *) k;
- qsort (mc_severity_codes, (size_t) mc_severity_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
- }
- }
- static int
- mc_get_block_count (mc_node_lang **nl, int elems)
- {
- rc_uint_type exid;
- int i, ret;
- if (! nl)
- return 0;
- i = 0;
- ret = 0;
- while (i < elems)
- {
- ret++;
- exid = nl[i++]->vid;
- while (i < elems && nl[i]->vid == exid + 1)
- exid = nl[i++]->vid;
- }
- return ret;
- }
- static bfd *
- windmc_open_as_binary (const char *filename)
- {
- bfd *abfd;
- abfd = bfd_openw (filename, "binary");
- if (! abfd)
- fatal ("can't open `%s' for output", filename);
- return abfd;
- }
- static void
- target_put_16 (void *p, rc_uint_type value)
- {
- assert (!! p);
- if (target_is_bigendian)
- bfd_putb16 (value, p);
- else
- bfd_putl16 (value, p);
- }
- static void
- target_put_32 (void *p, rc_uint_type value)
- {
- assert (!! p);
- if (target_is_bigendian)
- bfd_putb32 (value, p);
- else
- bfd_putl32 (value, p);
- }
- static struct bin_messagetable_item *
- mc_generate_bin_item (mc_node_lang *n, rc_uint_type *res_len)
- {
- struct bin_messagetable_item *ret = NULL;
- rc_uint_type len;
- *res_len = 0;
- if (mcset_bin_out_is_unicode == 1)
- {
- unichar *ht = n->message;
- rc_uint_type txt_len;
- txt_len = unichar_len (n->message);
- if (mcset_automatic_null_termination && txt_len != 0)
- {
- while (txt_len > 0 && ht[txt_len - 1] > 0 && ht[txt_len - 1] < 0x20)
- ht[--txt_len] = 0;
- }
- txt_len *= sizeof (unichar);
- len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + sizeof (unichar);
- ret = res_alloc ((len + 3) & ~3);
- memset (ret, 0, (len + 3) & ~3);
- target_put_16 (ret->length, (len + 3) & ~3);
- target_put_16 (ret->flags, MESSAGE_RESOURCE_UNICODE);
- txt_len = 0;
- while (*ht != 0)
- {
- target_put_16 (ret->data + txt_len, *ht++);
- txt_len += 2;
- }
- }
- else
- {
- rc_uint_type txt_len, l;
- char *cvt_txt;
- codepage_from_unicode( &l, n->message, &cvt_txt, n->lang->lang_info.wincp);
- if (! cvt_txt)
- fatal ("Failed to convert message to language codepage.\n");
- txt_len = strlen (cvt_txt);
- if (mcset_automatic_null_termination && txt_len > 0)
- {
- while (txt_len > 0 && cvt_txt[txt_len - 1] > 0 && cvt_txt[txt_len - 1] < 0x20)
- cvt_txt[--txt_len] = 0;
- }
- len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + 1;
- ret = res_alloc ((len + 3) & ~3);
- memset (ret, 0, (len + 3) & ~3);
- target_put_16 (ret->length, (len + 3) & ~3);
- target_put_16 (ret->flags, 0);
- strcpy ((char *) ret->data, cvt_txt);
- }
- *res_len = (len + 3) & ~3;
- return ret;
- }
- static void
- mc_write_blocks (struct bin_messagetable *mtbl, mc_node_lang **nl, mc_msg_item *ml, int elems)
- {
- int i, idx = 0;
- rc_uint_type exid;
- if (! nl)
- return;
- i = 0;
- while (i < elems)
- {
- target_put_32 (mtbl->items[idx].lowid, nl[i]->vid);
- target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
- target_put_32 (mtbl->items[idx].offset, ml[i].res_off);
- exid = nl[i++]->vid;
- while (i < elems && nl[i]->vid == exid + 1)
- {
- target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
- exid = nl[i++]->vid;
- }
- ++idx;
- }
- }
- static void
- set_windmc_bfd_content (const void *data, rc_uint_type off, rc_uint_type length)
- {
- if (! bfd_set_section_contents (mc_bfd.abfd, mc_bfd.sec, data, off, length))
- bfd_fatal ("bfd_set_section_contents");
- }
- static void
- windmc_write_bin (const char *filename, mc_node_lang **nl, int elems)
- {
- unsigned long sec_length = 1;
- int block_count, i;
- mc_msg_item *mi;
- struct bin_messagetable *mtbl;
- rc_uint_type dta_off, dta_start;
- if (elems <= 0)
- return;
- mc_bfd.abfd = windmc_open_as_binary (filename);
- mc_bfd.sec = bfd_make_section_with_flags (mc_bfd.abfd, ".data",
- (SEC_HAS_CONTENTS | SEC_ALLOC
- | SEC_LOAD | SEC_DATA));
- if (mc_bfd.sec == NULL)
- bfd_fatal ("bfd_make_section");
- /* Requiring this is probably a bug in BFD. */
- mc_bfd.sec->output_section = mc_bfd.sec;
- block_count = mc_get_block_count (nl, elems);
- dta_off = (rc_uint_type) ((BIN_MESSAGETABLE_BLOCK_SIZE * block_count) + BIN_MESSAGETABLE_SIZE - 4);
- dta_start = dta_off = (dta_off + 3) & ~3;
- mi = xmalloc (sizeof (mc_msg_item) * elems);
- mtbl = xmalloc (dta_start);
- /* Clear header region. */
- memset (mtbl, 0, dta_start);
- target_put_32 (mtbl->cblocks, block_count);
- /* Prepare items section for output. */
- for (i = 0; i < elems; i++)
- {
- mi[i].res_off = dta_off;
- mi[i].res = mc_generate_bin_item (nl[i], &mi[i].res_len);
- dta_off += mi[i].res_len;
- }
- sec_length = (dta_off + 3) & ~3;
- if (! bfd_set_section_size (mc_bfd.abfd, mc_bfd.sec, sec_length))
- bfd_fatal ("bfd_set_section_size");
- /* Make sure we write the complete block. */
- set_windmc_bfd_content ("\0", sec_length - 1, 1);
- /* Write block information. */
- mc_write_blocks (mtbl, nl, mi, elems);
- set_windmc_bfd_content (mtbl, 0, dta_start);
- /* Write items. */
- for (i = 0; i < elems; i++)
- set_windmc_bfd_content (mi[i].res, mi[i].res_off, mi[i].res_len);
- free (mtbl);
- free (mi);
- bfd_close (mc_bfd.abfd);
- mc_bfd.abfd = NULL;
- mc_bfd.sec = NULL;
- }
- static void
- write_bin (void)
- {
- mc_node_lang *n = NULL;
- int i, c;
- if (! mc_nodes_lang_count)
- return;
- i = 0;
- while (i < mc_nodes_lang_count)
- {
- char *nd;
- char *filename;
- if (n && n->lang == mc_nodes_lang[i]->lang)
- {
- i++;
- continue;
- }
- n = mc_nodes_lang[i];
- c = i + 1;
- while (c < mc_nodes_lang_count && n->lang == mc_nodes_lang[c]->lang)
- c++;
- nd = convert_unicode_to_ACP (n->lang->sval);
- /* Prepare filename for binary output. */
- filename = xmalloc (strlen (nd) + 4 + 1 + strlen (mcset_mc_basename) + 1 + strlen (mcset_rc_dir));
- strcpy (filename, mcset_rc_dir);
- if (mcset_prefix_bin)
- sprintf (filename + strlen (filename), "%s_", mcset_mc_basename);
- strcat (filename, nd);
- strcat (filename, ".bin");
- /* Write message file. */
- windmc_write_bin (filename, &mc_nodes_lang[i], (c - i));
- free (filename);
- i = c;
- }
- }
- static void
- write_rc (FILE *fp)
- {
- mc_node_lang *n;
- int i, l;
- fprintf (fp,
- "/* Do not edit this file manually.\n"
- " This file is autogenerated by windmc. */\n\n");
- if (! mc_nodes_lang_count)
- return;
- n = NULL;
- i = 0;
- for (l = 0; l < mc_nodes_lang_count; l++)
- {
- if (n && n->lang == mc_nodes_lang[l]->lang)
- continue;
- ++i;
- n = mc_nodes_lang[l];
- fprintf (fp, "\n// Country: %s\n// Language: %s\n#pragma code_page(%u)\n",
- n->lang->lang_info.country, n->lang->lang_info.name,
- (unsigned) n->lang->lang_info.wincp);
- fprintf (fp, "LANGUAGE 0x%lx, 0x%lx\n",
- (unsigned long) (n->lang->nval & 0x3ff),
- (unsigned long) ((n->lang->nval & 0xffff) >> 10));
- fprintf (fp, "1 MESSAGETABLE \"");
- if (mcset_prefix_bin)
- fprintf (fp, "%s_", mcset_mc_basename);
- unicode_print (fp, n->lang->sval, unichar_len (n->lang->sval));
- fprintf (fp, ".bin\"\n");
- }
- }
- static void
- write_dbg (FILE *fp)
- {
- mc_node *h;
- fprintf (fp,
- "/* Do not edit this file manually.\n"
- " This file is autogenerated by windmc.\n\n"
- " This file maps each message ID value in to a text string that contains\n"
- " the symbolic name used for it. */\n\n");
- fprintf (fp,
- "struct %sSymbolicName\n"
- "{\n ", mcset_mc_basename);
- if (mcset_msg_id_typedef)
- unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
- else
- fprintf (fp, "DWORD");
- fprintf (fp,
- " MessageId;\n"
- " char *SymbolicName;\n"
- "} %sSymbolicNames[] =\n"
- "{\n", mcset_mc_basename);
- h = mc_nodes;
- while (h != NULL)
- {
- if (h->symbol)
- write_dbg_define (fp, h->symbol, mcset_msg_id_typedef);
- h = h->next;
- }
- fprintf (fp, " { (");
- if (mcset_msg_id_typedef)
- unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
- else
- fprintf (fp, "DWORD");
- fprintf (fp,
- ") 0xffffffff, NULL }\n"
- "};\n");
- }
- static void
- write_header (FILE *fp)
- {
- char *s;
- int i;
- const mc_keyword *key;
- mc_node *h;
- fprintf (fp,
- "/* Do not edit this file manually.\n"
- " This file is autogenerated by windmc. */\n\n"
- "//\n// The values are 32 bit layed out as follows:\n//\n"
- "// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n"
- "// 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"
- "// +---+-+-+-----------------------+-------------------------------+\n"
- "// |Sev|C|R| Facility | Code |\n"
- "// +---+-+-+-----------------------+-------------------------------+\n//\n"
- "// where\n//\n"
- "// C - is the Customer code flag\n//\n"
- "// R - is a reserved bit\n//\n"
- "// Code - is the facility's status code\n//\n");
- h = mc_nodes;
- fprintf (fp, "// Sev - is the severity code\n//\n");
- if (mc_severity_codes_count != 0)
- {
- for (i = 0; i < mc_severity_codes_count; i++)
- {
- key = mc_severity_codes[i];
- fprintf (fp, "// %s - %02lx\n", convert_unicode_to_ACP (key->usz),
- (unsigned long) key->nval);
- if (key->sval && key->sval[0] != 0)
- {
- if (! mcset_out_values_are_decimal)
- fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
- (unsigned long) key->nval);
- else
- fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
- (unsigned long) key->nval);
- }
- }
- fprintf (fp, "//\n");
- }
- fprintf (fp, "// Facility - is the facility code\n//\n");
- if (mc_facility_codes_count != 0)
- {
- for (i = 0; i < mc_facility_codes_count; i++)
- {
- key = mc_facility_codes[i];
- fprintf (fp, "// %s - %04lx\n", convert_unicode_to_ACP (key->usz),
- (unsigned long) key->nval);
- if (key->sval && key->sval[0] != 0)
- {
- if (! mcset_out_values_are_decimal)
- fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
- (unsigned long) key->nval);
- else
- fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
- (unsigned long) key->nval);
- }
- }
- fprintf (fp, "//\n");
- }
- fprintf (fp, "\n");
- while (h != NULL)
- {
- if (h->user_text)
- {
- s = convert_unicode_to_ACP (h->user_text);
- if (s)
- fprintf (fp, "%s", s);
- }
- if (h->symbol)
- write_header_define (fp, h->symbol, h->vid, mcset_msg_id_typedef, h->sub);
- h = h->next;
- }
- }
- static const char *
- mc_unify_path (const char *path)
- {
- char *end;
- char *hsz;
- if (! path || *path == 0)
- return "./";
- hsz = xmalloc (strlen (path) + 2);
- strcpy (hsz, path);
- end = hsz + strlen (hsz);
- if (hsz[-1] != '/' && hsz[-1] != '\\')
- strcpy (end, "/");
- while ((end = strchr (hsz, '\\')) != NULL)
- *end = '/';
- return hsz;
- }
- int main (int, char **);
- int
- main (int argc, char **argv)
- {
- FILE *h_fp;
- int c;
- char *target, *input_filename;
- int verbose;
- #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
- setlocale (LC_MESSAGES, "");
- #endif
- #if defined (HAVE_SETLOCALE)
- setlocale (LC_CTYPE, "");
- #endif
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
- program_name = argv[0];
- xmalloc_set_program_name (program_name);
- bfd_set_error_program_name (program_name);
- expandargv (&argc, &argv);
- bfd_init ();
- set_default_bfd_target ();
- target = NULL;
- verbose = 0;
- input_filename = NULL;
- res_init ();
- while ((c = getopt_long (argc, argv, "C:F:O:h:e:m:r:x:aAbcdHunoUvV", long_options,
- (int *) 0)) != EOF)
- {
- switch (c)
- {
- case 'b':
- mcset_prefix_bin = 1;
- break;
- case 'e':
- {
- mcset_header_ext = optarg;
- if (mcset_header_ext[0] != '.' && mcset_header_ext[0] != 0)
- {
- char *hsz = xmalloc (strlen (mcset_header_ext) + 2);
- sprintf (hsz, ".%s", mcset_header_ext);
- mcset_header_ext = hsz;
- }
- }
- break;
- case 'h':
- mcset_header_dir = mc_unify_path (optarg);
- break;
- case 'r':
- mcset_rc_dir = mc_unify_path (optarg);
- break;
- case 'a':
- mcset_text_in_is_unicode = 0;
- break;
- case 'x':
- if (*optarg != 0)
- mcset_dbg_dir = mc_unify_path (optarg);
- break;
- case 'A':
- mcset_bin_out_is_unicode = 0;
- break;
- case 'd':
- mcset_out_values_are_decimal = 1;
- break;
- case 'u':
- mcset_text_in_is_unicode = 1;
- break;
- case 'U':
- mcset_bin_out_is_unicode = 1;
- break;
- case 'c':
- mcset_custom_bit = 1;
- break;
- case 'n':
- mcset_automatic_null_termination = 1;
- break;
- case 'o':
- mcset_use_hresult = 1;
- fatal ("option -o is not implemented until yet.\n");
- break;
- case 'F':
- target = optarg;
- break;
- case 'v':
- verbose ++;
- break;
- case 'm':
- mcset_max_message_length = strtol (optarg, (char **) NULL, 10);
- break;
- case 'C':
- mcset_codepage_in = strtol (optarg, (char **) NULL, 10);
- break;
- case 'O':
- mcset_codepage_out = strtol (optarg, (char **) NULL, 10);
- break;
- case '?':
- case 'H':
- usage (stdout, 0);
- break;
- case 'V':
- print_version ("windmc");
- break;
- default:
- usage (stderr, 1);
- break;
- }
- }
- if (input_filename == NULL && optind < argc)
- {
- input_filename = argv[optind];
- ++optind;
- }
- set_endianness (NULL, target);
- if (input_filename == NULL)
- {
- fprintf (stderr, "Error: No input file was specified.\n");
- usage (stderr, 1);
- }
- mc_set_inputfile (input_filename);
- if (!probe_codepage (&mcset_codepage_in, &mcset_text_in_is_unicode, "codepage_in", 0))
- usage (stderr, 1);
- if (mcset_codepage_out == 0)
- mcset_codepage_out = 1252;
- if (! unicode_is_valid_codepage (mcset_codepage_out))
- fatal ("Code page 0x%x is unknown.", (unsigned int) mcset_codepage_out);
- if (mcset_codepage_out == CP_UTF16)
- fatal ("UTF16 is no valid text output code page.");
- if (verbose)
- {
- fprintf (stderr, "// Default target is %s and it is %s endian.\n",
- def_target_arch, (target_is_bigendian ? "big" : "little"));
- fprintf (stderr, "// Input codepage: 0x%x\n", (unsigned int) mcset_codepage_in);
- fprintf (stderr, "// Output codepage: 0x%x\n", (unsigned int) mcset_codepage_out);
- }
- if (argc != optind)
- usage (stderr, 1);
- /* Initialize mcset_mc_basename. */
- {
- const char *bn, *bn2;
- char *hsz;
- bn = strrchr (input_filename, '/');
- bn2 = strrchr (input_filename, '\\');
- if (! bn)
- bn = bn2;
- if (bn && bn2 && bn < bn2)
- bn = bn2;
- if (! bn)
- bn = input_filename;
- else
- bn++;
- mcset_mc_basename = hsz = xstrdup (bn);
- /* Cut of right-hand extension. */
- if ((hsz = strrchr (hsz, '.')) != NULL)
- *hsz = 0;
- }
- /* Load the input file and do code page transformations to UTF16. */
- {
- unichar *u;
- rc_uint_type ul;
- char *buff;
- bfd_size_type flen;
- FILE *fp = fopen (input_filename, "rb");
- if (!fp)
- fatal (_("unable to open file `%s' for input.\n"), input_filename);
- fseek (fp, 0, SEEK_END);
- flen = ftell (fp);
- fseek (fp, 0, SEEK_SET);
- buff = malloc (flen + 3);
- memset (buff, 0, flen + 3);
- if (fread (buff, 1, flen, fp) < flen)
- fatal (_("unable to read contents of %s"), input_filename);
- fclose (fp);
- if (mcset_text_in_is_unicode != 1)
- {
- unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
- if (! u)
- fatal ("Failed to convert input to UFT16\n");
- mc_set_content (u);
- }
- else
- {
- if ((flen & 1) != 0)
- fatal (_("input file does not seems to be UFT16.\n"));
- mc_set_content ((unichar *) buff);
- }
- free (buff);
- }
- while (yyparse ())
- ;
- do_sorts ();
- h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
- write_header (h_fp);
- fclose (h_fp);
- h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
- write_rc (h_fp);
- fclose (h_fp);
- if (mcset_dbg_dir != NULL)
- {
- h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
- write_dbg (h_fp);
- fclose (h_fp);
- }
- write_bin ();
- if (mc_nodes_lang)
- free (mc_nodes_lang);
- if (mc_severity_codes)
- free (mc_severity_codes);
- if (mc_facility_codes)
- free (mc_facility_codes);
- xexit (0);
- return 0;
- }
|