From ecd144b40dc5b06c42e77a7f7d88c023397e89eb Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 18 Jan 2011 16:55:37 +0100 Subject: [PATCH] wmc: Add support for creating resource and plain binary files. --- tools/wmc/utils.c | 73 ++++++++++++++++++++++++++++++ tools/wmc/utils.h | 15 +++++++ tools/wmc/wmc.c | 38 ++++++++++++++-- tools/wmc/wmc.man.in | 30 +++++++------ tools/wmc/write.c | 104 ++++++++++++++++++++++++++++++++++++++++++- tools/wmc/write.h | 1 + 6 files changed, 243 insertions(+), 18 deletions(-) diff --git a/tools/wmc/utils.c b/tools/wmc/utils.c index 2b29db9bb1..88dd45fa40 100644 --- a/tools/wmc/utils.c +++ b/tools/wmc/utils.c @@ -243,3 +243,76 @@ int unistrcmp(const WCHAR *s1, const WCHAR *s2) return *s1 - *s2; } + +/******************************************************************* + * buffer management + * + * Function for writing to a memory buffer. + */ + +int byte_swapped = 0; +unsigned char *output_buffer; +size_t output_buffer_pos; +size_t output_buffer_size; + +static void check_output_buffer_space( size_t size ) +{ + if (output_buffer_pos + size >= output_buffer_size) + { + output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size ); + output_buffer = xrealloc( output_buffer, output_buffer_size ); + } +} + +void init_output_buffer(void) +{ + output_buffer_size = 1024; + output_buffer_pos = 0; + output_buffer = xmalloc( output_buffer_size ); +} + +void flush_output_buffer( const char *name ) +{ + int fd = open( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666 ); + if (fd == -1) error( "Error creating %s\n", name ); + if (write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos) + error( "Error writing to %s\n", name ); + close( fd ); + free( output_buffer ); +} + +void put_data( const void *data, size_t size ) +{ + check_output_buffer_space( size ); + memcpy( output_buffer + output_buffer_pos, data, size ); + output_buffer_pos += size; +} + +void put_byte( unsigned char val ) +{ + check_output_buffer_space( 1 ); + output_buffer[output_buffer_pos++] = val; +} + +void put_word( unsigned short val ) +{ + if (byte_swapped) val = (val << 8) | (val >> 8); + put_data( &val, sizeof(val) ); +} + +void put_dword( unsigned int val ) +{ + if (byte_swapped) + val = ((val << 24) | ((val << 8) & 0x00ff0000) | ((val >> 8) & 0x0000ff00) | (val >> 24)); + put_data( &val, sizeof(val) ); +} + +void align_output( unsigned int align ) +{ + size_t size = align - (output_buffer_pos % align); + + if (size == align) return; + check_output_buffer_space( size ); + memset( output_buffer + output_buffer_pos, 0, size ); + output_buffer_pos += size; +} diff --git a/tools/wmc/utils.h b/tools/wmc/utils.h index 5a1faf143a..bef1abf6a7 100644 --- a/tools/wmc/utils.h +++ b/tools/wmc/utils.h @@ -48,4 +48,19 @@ int unistrlen(const WCHAR *s); int unistricmp(const WCHAR *s1, const WCHAR *s2); int unistrcmp(const WCHAR *s1, const WCHAR *s2); +/* buffer management */ + +extern int byte_swapped; +extern unsigned char *output_buffer; +extern size_t output_buffer_pos; +extern size_t output_buffer_size; + +extern void init_output_buffer(void); +extern void flush_output_buffer( const char *name ); +extern void put_data( const void *data, size_t size ); +extern void put_byte( unsigned char val ); +extern void put_word( unsigned short val ); +extern void put_dword( unsigned int val ); +extern void align_output( unsigned int align ); + #endif diff --git a/tools/wmc/wmc.c b/tools/wmc/wmc.c index 4c4ba28585..17dfd1b464 100644 --- a/tools/wmc/wmc.c +++ b/tools/wmc/wmc.c @@ -48,6 +48,7 @@ static const char usage[] = " -H file Write headerfile to file (default is inputfile.h)\n" " -i Inline messagetable(s)\n" " -o file Output to file (default is inputfile.rc)\n" + " -O fmt Set output format (rc, res)\n" " -u Inputfile is in unicode\n" " -U Output unicode messagetable(s)\n" " -v Show supported codepages and languages\n" @@ -117,6 +118,12 @@ int mcy_debug; FILE *yyin; +static enum +{ + FORMAT_RC, + FORMAT_RES +} output_format; + int getopt (int argc, char *const *argv, const char *optstring); static void segvhandler(int sig); @@ -165,7 +172,7 @@ int main(int argc,char *argv[]) strcat(cmdline, " "); } - while((optc = getopt(argc, argv, "B:cdDhH:io:p:uUvVW")) != EOF) + while((optc = getopt(argc, argv, "B:cdDhH:io:O:p:uUvVW")) != EOF) { switch(optc) { @@ -211,6 +218,15 @@ int main(int argc,char *argv[]) case 'o': output_name = xstrdup(optarg); break; + case 'O': + if (!strcmp( optarg, "rc" )) output_format = FORMAT_RC; + else if (!strcmp( optarg, "res" )) output_format = FORMAT_RES; + else + { + fprintf(stderr, "Output format must be rc or res\n" ); + lose++; + } + break; case 'u': unicodein = 1; break; @@ -286,10 +302,24 @@ int main(int argc,char *argv[]) exit(1); } - write_h_file(header_name); - write_rc_file(output_name); - if(!rcinline) +#ifdef WORDS_BIGENDIAN + byte_swapped = (byteorder == WMC_BO_LITTLE); +#else + byte_swapped = (byteorder == WMC_BO_BIG); +#endif + + switch (output_format) + { + case FORMAT_RC: + write_h_file(header_name); + write_rc_file(output_name); + if(!rcinline) write_bin_files(); + break; + case FORMAT_RES: + write_res_file( output_name ); + break; + } output_name = NULL; header_name = NULL; return 0; diff --git a/tools/wmc/wmc.man.in b/tools/wmc/wmc.man.in index 349112556b..517ac2335c 100644 --- a/tools/wmc/wmc.man.in +++ b/tools/wmc/wmc.man.in @@ -22,45 +22,49 @@ with \fI-o\fR, then \fBwmc\fR will write the output to \fBinputfile.{rc,h}\fR. The outputfile is named \fBwmc.tab.{rc,h}\fR if no inputfile was given. .SH OPTIONS .TP -.I \-B x +.BI \-B\ x Set output byte-order x={n[ative], l[ittle], b[ig]}. Default is n[ative]. .TP -.I \-c +.B \-c Set 'custom-bit' in message-code values. .TP -.I \-d +.B \-d NON-FUNCTIONAL; Use decimal values in output .TP -.I \-D +.B \-D Set debug flag. This results is a parser trace and a lot of extra messages. .TP -.I \-h +.B \-h Print an informative usage message. .TP -.I \-H file +.BI \-H\ file Write headerfile to \fIfile\fR. Default is \fIinputfile.h\fR. .TP -.I \-i +.B \-i Inline messagetable(s). This option skips the generation of all \fI.bin\fR files and writes all output into the \fI.rc\fR file. This encoding is parsable with wrc(1). .TP -.I \-o file +.BI \-o\ file Output to \fIfile\fR. Default is \fIinputfile.rc\fR. .TP -.I \-u +.BI \-O\ format +Set the output format. Supported formats are \fBrc\fR (the default) +and \fBres\fR. +.TP +.B \-u Assume that the inputfile is in unicode. .TP -.I \-U +.B \-U Write resource output in unicode formatted messagetable(s). .TP -.I \-v +.B \-v Show all supported codepages and languages. .TP -.I \-V +.B \-V Print version end exit. .TP -.I \-W +.B \-W Enable pedantic warnings. .SH EXTENSIONS The original syntax is extended to support codepages more smoothly. Normally, diff --git a/tools/wmc/write.c b/tools/wmc/write.c index 7f9784f843..f6e6d524f5 100644 --- a/tools/wmc/write.c +++ b/tools/wmc/write.c @@ -521,7 +521,109 @@ void write_rc_file(const char *fname) fclose(fp); } +static void output_bin_data( lan_blk_t *lbp ) +{ + unsigned int offs = 4 * (lbp->nblk * 3 + 1); + int i, j, k; + + put_dword( lbp->nblk ); /* NBlocks */ + for (i = 0; i < lbp->nblk; i++) + { + put_dword( lbp->blks[i].idlo ); /* Lo */ + put_dword( lbp->blks[i].idhi ); /* Hi */ + put_dword( offs ); /* Offs */ + offs += lbp->blks[i].size; + } + for (i = 0; i < lbp->nblk; i++) + { + block_t *blk = &lbp->blks[i]; + for (j = 0; j < blk->nmsg; j++) + { + int len = (2 * blk->msgs[j]->len + 3) & ~3; + put_word( len + 4 ); + put_word( 1 ); + for (k = 0; k < blk->msgs[j]->len; k++) put_word( blk->msgs[j]->msg[k] ); + align_output( 4 ); + } + } +} + void write_bin_files(void) { - assert(rcinline == 0); + lan_blk_t *lbp; + token_t *ttab; + int ntab; + int i; + + get_tokentable(&ttab, &ntab); + + for (lbp = lanblockhead; lbp; lbp = lbp->next) + { + char *cptr = NULL; + + for (i = 0; i < ntab; i++) + { + if (ttab[i].type == tok_language && ttab[i].token == lbp->lan) + { + if (ttab[i].alias) cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias); + break; + } + } + if(!cptr) + internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x\n", lbp->lan); + init_output_buffer(); + output_bin_data( lbp ); + cptr = xrealloc( cptr, strlen(cptr) + 5 ); + strcat( cptr, ".bin" ); + flush_output_buffer( cptr ); + free(cptr); + } +} + +void write_res_file( const char *name ) +{ + lan_blk_t *lbp; + int i, j; + + init_output_buffer(); + + put_dword( 0 ); /* ResSize */ + put_dword( 32 ); /* HeaderSize */ + put_word( 0xffff ); /* ResType */ + put_word( 0x0000 ); + put_word( 0xffff ); /* ResName */ + put_word( 0x0000 ); + put_dword( 0 ); /* DataVersion */ + put_word( 0 ); /* Memory options */ + put_word( 0 ); /* Language */ + put_dword( 0 ); /* Version */ + put_dword( 0 ); /* Characteristics */ + + for (lbp = lanblockhead; lbp; lbp = lbp->next) + { + unsigned int data_size = 4 * (lbp->nblk * 3 + 1); + unsigned int header_size = 5 * sizeof(unsigned int) + 6 * sizeof(unsigned short); + + for (i = 0; i < lbp->nblk; i++) + { + block_t *blk = &lbp->blks[i]; + for (j = 0; j < blk->nmsg; j++) data_size += 4 + ((blk->msgs[j]->len * 2 + 3) & ~3); + } + + put_dword( data_size ); /* ResSize */ + put_dword( header_size ); /* HeaderSize */ + put_word( 0xffff ); /* ResType */ + put_word( 0x000b /*RT_MESSAGETABLE*/ ); + put_word( 0xffff ); /* ResName */ + put_word( 0x0001 ); + align_output( 4 ); + put_dword( 0 ); /* DataVersion */ + put_word( 0x30 ); /* Memory options */ + put_word( lbp->lan ); /* Language */ + put_dword( 0 ); /* Version */ + put_dword( 0 ); /* Characteristics */ + + output_bin_data( lbp ); + } + flush_output_buffer( name ); } diff --git a/tools/wmc/write.h b/tools/wmc/write.h index 57ce65517e..33b8eb5c99 100644 --- a/tools/wmc/write.h +++ b/tools/wmc/write.h @@ -23,5 +23,6 @@ void write_h_file(const char *fname); void write_rc_file(const char *fname); void write_bin_files(void); +void write_res_file( const char *name ); #endif -- 2.32.0.93.g670b81a890