File indexing completed on 2023-02-02 23:38:35
e6a824d5f… Dyla*0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include "config.h"
0022
31ad5fe6a… Alex*0023 #include <stdarg.h>
e6a824d5f… Dyla*0024 #include <stdio.h>
0025 #include <stdlib.h>
0026
0027 #include "windef.h"
0028 #include "guiddef.h"
97ca9f8a3… Alex*0029 #include "tools.h"
e6a824d5f… Dyla*0030
0031 #define TOKEN_NAME 1
0032 #define TOKEN_STRING 2
0033 #define TOKEN_INTEGER 3
0034 #define TOKEN_GUID 5
0035 #define TOKEN_INTEGER_LIST 6
0036 #define TOKEN_FLOAT_LIST 7
0037 #define TOKEN_OBRACE 10
0038 #define TOKEN_CBRACE 11
0039 #define TOKEN_OPAREN 12
0040 #define TOKEN_CPAREN 13
0041 #define TOKEN_OBRACKET 14
0042 #define TOKEN_CBRACKET 15
0043 #define TOKEN_OANGLE 16
0044 #define TOKEN_CANGLE 17
0045 #define TOKEN_DOT 18
0046 #define TOKEN_COMMA 19
0047 #define TOKEN_SEMICOLON 20
0048 #define TOKEN_TEMPLATE 31
0049 #define TOKEN_WORD 40
0050 #define TOKEN_DWORD 41
0051 #define TOKEN_FLOAT 42
0052 #define TOKEN_DOUBLE 43
0053 #define TOKEN_CHAR 44
0054 #define TOKEN_UCHAR 45
0055 #define TOKEN_SWORD 46
0056 #define TOKEN_SDWORD 47
0057 #define TOKEN_VOID 48
0058 #define TOKEN_LPSTR 49
0059 #define TOKEN_UNICODE 50
0060 #define TOKEN_CSTRING 51
0061 #define TOKEN_ARRAY 52
0062
0063 struct keyword
0064 {
0065 const char *word;
0066 WORD token;
0067 };
0068
0069 static const struct keyword reserved_words[] = {
0070 {"ARRAY", TOKEN_ARRAY},
0071 {"CHAR", TOKEN_CHAR},
0072 {"CSTRING", TOKEN_CSTRING},
0073 {"DOUBLE", TOKEN_DOUBLE},
0074 {"DWORD", TOKEN_DWORD},
0075 {"FLOAT", TOKEN_FLOAT},
0076 {"SDWORD", TOKEN_SDWORD},
0077 {"STRING", TOKEN_LPSTR},
0078 {"SWORD", TOKEN_SWORD},
0079 {"TEMPLATE", TOKEN_TEMPLATE},
0080 {"UCHAR", TOKEN_UCHAR},
0081 {"UNICODE", TOKEN_UNICODE},
0082 {"VOID", TOKEN_VOID},
0083 {"WORD", TOKEN_WORD}
0084 };
0085
166ad9696… Alex*0086 static BOOL option_header;
0087 static char *option_inc_var_name = NULL;
0088 static char *option_inc_size_name = NULL;
0089 static const char *option_outfile_name = "-";
e6a824d5f… Dyla*0090 static char *program_name;
3b2859a61… Alex*0091 static FILE *infile;
0092 static int line_no;
31ad5fe6a… Alex*0093 static const char *infile_name;
3b2859a61… Alex*0094 static FILE *outfile;
7d3938e81… Alex*0095
0096 unsigned char *output_buffer = NULL;
0097 size_t output_buffer_pos = 0;
0098 size_t output_buffer_size = 0;
31ad5fe6a… Alex*0099
3b2859a61… Alex*0100 static void fatal_error( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
31ad5fe6a… Alex*0101
3b2859a61… Alex*0102 static void fatal_error( const char *msg, ... )
31ad5fe6a… Alex*0103 {
0104 va_list valist;
0105 va_start( valist, msg );
0106 if (infile_name)
0107 {
3b2859a61… Alex*0108 fprintf( stderr, "%s:%d:", infile_name, line_no );
31ad5fe6a… Alex*0109 fprintf( stderr, " error: " );
0110 }
0111 else fprintf( stderr, "%s: error: ", program_name );
0112 vfprintf( stderr, msg, valist );
0113 va_end( valist );
0114 exit( 1 );
0115 }
0116
e6a824d5f… Dyla*0117
3b2859a61… Alex*0118 static inline BOOL read_byte( char *byte )
e6a824d5f… Dyla*0119 {
3b2859a61… Alex*0120 int c = fgetc(infile);
e6a824d5f… Dyla*0121 *byte = c;
3b2859a61… Alex*0122 if (c == '\n') line_no++;
e6a824d5f… Dyla*0123 return c != EOF;
0124 }
0125
3b2859a61… Alex*0126 static inline BOOL unread_byte( char last_byte )
e6a824d5f… Dyla*0127 {
3b2859a61… Alex*0128 if (last_byte == '\n') line_no--;
0129 return ungetc(last_byte, infile) != EOF;
e6a824d5f… Dyla*0130 }
0131
3b2859a61… Alex*0132 static inline BOOL read_bytes( void *data, DWORD size )
e6a824d5f… Dyla*0133 {
3b2859a61… Alex*0134 return fread(data, size, 1, infile) > 0;
e6a824d5f… Dyla*0135 }
0136
3b2859a61… Alex*0137 static BOOL write_c_hex_bytes(void)
e6a824d5f… Dyla*0138 {
166ad9696… Alex*0139 UINT i;
7d3938e81… Alex*0140 for (i = 0; i < output_buffer_pos; i++)
e6a824d5f… Dyla*0141 {
166ad9696… Alex*0142 if (i % 12 == 0)
3b2859a61… Alex*0143 fprintf(outfile, "\n ");
7d3938e81… Alex*0144 fprintf(outfile, " 0x%02x,", output_buffer[i]);
e6a824d5f… Dyla*0145 }
0146 return TRUE;
0147 }
0148
3b2859a61… Alex*0149 static BOOL write_raw_bytes(void)
e6a824d5f… Dyla*0150 {
7d3938e81… Alex*0151 return fwrite(output_buffer, output_buffer_pos, 1, outfile) > 0;
e6a824d5f… Dyla*0152 }
0153
7d3938e81… Alex*0154 static inline void put_float(float value)
b8ad360bb… Alex*0155 {
0156 DWORD val;
0157 memcpy( &val, &value, sizeof(value) );
7d3938e81… Alex*0158 return put_dword( val );
b8ad360bb… Alex*0159 }
0160
7d3938e81… Alex*0161 static inline void put_guid(const GUID *guid)
b8ad360bb… Alex*0162 {
7d3938e81… Alex*0163 put_dword( guid->Data1 );
0164 put_word( guid->Data2 );
0165 put_word( guid->Data3 );
0166 put_data( guid->Data4, sizeof(guid->Data4) );
e6a824d5f… Dyla*0167 }
0168
0169 static int compare_names(const void *a, const void *b)
0170 {
0171 return strcasecmp(*(const char **)a, *(const char **)b);
0172 }
0173
3b2859a61… Alex*0174 static BOOL parse_keyword( const char *name )
e6a824d5f… Dyla*0175 {
0176 const struct keyword *keyword;
0177
0178 keyword = bsearch(&name, reserved_words, ARRAY_SIZE(reserved_words),
0179 sizeof(reserved_words[0]), compare_names);
0180 if (!keyword)
0181 return FALSE;
0182
7d3938e81… Alex*0183 put_word(keyword->token);
0184 return TRUE;
e6a824d5f… Dyla*0185 }
0186
7d3938e81… Alex*0187 static void parse_guid(void)
e6a824d5f… Dyla*0188 {
0189 char buf[39];
0190 GUID guid;
0191 DWORD tab[10];
0192 BOOL ret;
0193 static const char *guidfmt = "<%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>";
0194
0195 buf[0] = '<';
3b2859a61… Alex*0196 if (!read_bytes(buf + 1, 37)) fatal_error( "truncated GUID\n" );
e6a824d5f… Dyla*0197 buf[38] = 0;
0198
0199 ret = sscanf(buf, guidfmt, &guid.Data1, tab, tab+1, tab+2, tab+3, tab+4, tab+5, tab+6, tab+7, tab+8, tab+9);
3b2859a61… Alex*0200 if (ret != 11) fatal_error( "invalid GUID '%s'\n", buf );
e6a824d5f… Dyla*0201
0202 guid.Data2 = tab[0];
0203 guid.Data3 = tab[1];
0204 guid.Data4[0] = tab[2];
0205 guid.Data4[1] = tab[3];
0206 guid.Data4[2] = tab[4];
0207 guid.Data4[3] = tab[5];
0208 guid.Data4[4] = tab[6];
0209 guid.Data4[5] = tab[7];
0210 guid.Data4[6] = tab[8];
0211 guid.Data4[7] = tab[9];
0212
7d3938e81… Alex*0213 put_word(TOKEN_GUID);
0214 put_guid(&guid);
e6a824d5f… Dyla*0215 }
0216
7d3938e81… Alex*0217 static void parse_name(void)
e6a824d5f… Dyla*0218 {
0219 char c;
0220 int len = 0;
0221 char name[512];
0222
3b2859a61… Alex*0223 while (read_byte(&c) && len < sizeof(name) &&
e6a824d5f… Dyla*0224 (isalnum(c) || c == '_' || c == '-'))
0225 {
0226 if (len + 1 < sizeof(name))
0227 name[len++] = c;
0228 }
3b2859a61… Alex*0229 unread_byte(c);
e6a824d5f… Dyla*0230 name[len] = 0;
0231
7d3938e81… Alex*0232 if (!parse_keyword(name))
0233 {
0234 put_word(TOKEN_NAME);
0235 put_dword(len);
0236 put_data(name, len);
e6a824d5f… Dyla*0237 }
0238 }
0239
7d3938e81… Alex*0240 static void parse_number(void)
e6a824d5f… Dyla*0241 {
0242 int len = 0;
0243 char c;
0244 char buffer[512];
0245 BOOL dot = FALSE;
0246 BOOL ret;
0247
3b2859a61… Alex*0248 while (read_byte(&c) &&
e6a824d5f… Dyla*0249 ((!len && c == '-') || (!dot && c == '.') || isdigit(c)))
0250 {
0251 if (len + 1 < sizeof(buffer))
0252 buffer[len++] = c;
0253 if (c == '.')
0254 dot = TRUE;
0255 }
3b2859a61… Alex*0256 unread_byte(c);
e6a824d5f… Dyla*0257 buffer[len] = 0;
0258
0259 if (dot) {
0260 float value;
0261 ret = sscanf(buffer, "%f", &value);
3b2859a61… Alex*0262 if (!ret) fatal_error( "invalid float token\n" );
7d3938e81… Alex*0263 put_word(TOKEN_FLOAT);
0264 put_float(value);
e6a824d5f… Dyla*0265 } else {
0266 int value;
0267 ret = sscanf(buffer, "%d", &value);
3b2859a61… Alex*0268 if (!ret) fatal_error( "invalid integer token\n" );
7d3938e81… Alex*0269 put_word(TOKEN_INTEGER);
0270 put_dword(value);
e6a824d5f… Dyla*0271 }
0272 }
0273
3b2859a61… Alex*0274 static BOOL parse_token(void)
e6a824d5f… Dyla*0275 {
0276 char c;
166ad9696… Alex*0277 int len;
0278 char *tok, buffer[512];
e6a824d5f… Dyla*0279
3b2859a61… Alex*0280 if (!read_byte(&c))
e6a824d5f… Dyla*0281 return FALSE;
0282
0283 switch (c)
0284 {
0285 case '\n':
0286 case '\r':
0287 case ' ':
0288 case '\t':
7d3938e81… Alex*0289 break;
0290
0291 case '{': put_word(TOKEN_OBRACE); break;
0292 case '}': put_word(TOKEN_CBRACE); break;
0293 case '[': put_word(TOKEN_OBRACKET); break;
0294 case ']': put_word(TOKEN_CBRACKET); break;
0295 case '(': put_word(TOKEN_OPAREN); break;
0296 case ')': put_word(TOKEN_CPAREN); break;
0297 case ',': put_word(TOKEN_COMMA); break;
0298 case ';': put_word(TOKEN_SEMICOLON); break;
0299 case '.': put_word(TOKEN_DOT); break;
e6a824d5f… Dyla*0300
0301 case '/':
3b2859a61… Alex*0302 if (!read_byte(&c) || c != '/')
0303 fatal_error( "invalid single '/' comment token\n" );
0304 while (read_byte(&c) && c != '\n');
e6a824d5f… Dyla*0305 return c == '\n';
0306
166ad9696… Alex*0307 case '#':
0308 len = 0;
3b2859a61… Alex*0309 while (read_byte(&c) && c != '\n')
166ad9696… Alex*0310 if (len + 1 < sizeof(buffer)) buffer[len++] = c;
3b2859a61… Alex*0311 if (c != '\n') fatal_error( "line too long\n" );
166ad9696… Alex*0312 buffer[len] = 0;
0313 tok = strtok( buffer, " \t" );
7d3938e81… Alex*0314 if (!tok || strcmp( tok, "pragma" )) break;
166ad9696… Alex*0315 tok = strtok( NULL, " \t" );
7d3938e81… Alex*0316 if (!tok || strcmp( tok, "xftmpl" )) break;
166ad9696… Alex*0317 tok = strtok( NULL, " \t" );
7d3938e81… Alex*0318 if (!tok) break;
166ad9696… Alex*0319 if (!strcmp( tok, "name" ))
0320 {
0321 tok = strtok( NULL, " \t" );
97ca9f8a3… Alex*0322 if (tok && !option_inc_var_name) option_inc_var_name = xstrdup( tok );
166ad9696… Alex*0323 }
0324 else if (!strcmp( tok, "size" ))
0325 {
0326 tok = strtok( NULL, " \t" );
97ca9f8a3… Alex*0327 if (tok && !option_inc_size_name) option_inc_size_name = xstrdup( tok );
166ad9696… Alex*0328 }
7d3938e81… Alex*0329 break;
166ad9696… Alex*0330
e6a824d5f… Dyla*0331 case '<':
7d3938e81… Alex*0332 parse_guid();
0333 break;
e6a824d5f… Dyla*0334
0335 case '"':
166ad9696… Alex*0336 len = 0;
e6a824d5f… Dyla*0337
0338
3b2859a61… Alex*0339 while (read_byte(&c) && c != '"') {
e6a824d5f… Dyla*0340 if (len + 1 < sizeof(buffer))
0341 buffer[len++] = c;
0342 }
3b2859a61… Alex*0343 if (c != '"') fatal_error( "unterminated string\n" );
7d3938e81… Alex*0344 put_word(TOKEN_STRING);
0345 put_dword(len);
0346 put_data(buffer, len);
0347 break;
e6a824d5f… Dyla*0348
0349 default:
3b2859a61… Alex*0350 unread_byte(c);
7d3938e81… Alex*0351 if (isdigit(c) || c == '-') parse_number();
0352 else if (isalpha(c) || c == '_') parse_name();
0353 else fatal_error( "invalid character '%c' to start token\n", c );
e6a824d5f… Dyla*0354 }
0355
0356 return TRUE;
0357 }
0358
0359 static const char *output_file;
0360
0361 static void cleanup_files(void)
0362 {
0363 if (output_file) unlink(output_file);
0364 }
0365
0366 static void exit_on_signal( int sig )
0367 {
0368 exit(1);
0369 }
0370
0371 static void usage(void)
0372 {
0373 fprintf(stderr, "Usage: %s [OPTIONS] INFILE\n"
0374 "Options:\n"
166ad9696… Alex*0375 " -H Output to a c header file instead of a binary file\n"
e6a824d5f… Dyla*0376 " -i NAME Output to a c header file, data in variable NAME\n"
0377 " -s NAME In a c header file, define NAME to be the data size\n"
0378 " -o FILE Write output to FILE\n",
0379 program_name);
0380 }
0381
5f921c7f1… Alex*0382 static void option_callback( int optc, char *optarg )
e6a824d5f… Dyla*0383 {
5f921c7f1… Alex*0384 switch (optc)
e6a824d5f… Dyla*0385 {
5f921c7f1… Alex*0386 case 'h':
0387 usage();
0388 exit(0);
0389 case 'H':
0390 option_header = TRUE;
0391 break;
0392 case 'i':
0393 option_header = TRUE;
0394 option_inc_var_name = xstrdup(optarg);
0395 break;
0396 case 'o':
0397 option_outfile_name = xstrdup(optarg);
0398 break;
0399 case 's':
0400 option_inc_size_name = xstrdup(optarg);
0401 break;
0402 case '?':
0403 fprintf( stderr, "%s: %s\n", program_name, optarg );
0404 exit(1);
e6a824d5f… Dyla*0405 }
0406 }
0407
0408 int main(int argc, char **argv)
0409 {
0410 char header[16];
5f921c7f1… Alex*0411 struct strarray args;
e6a824d5f… Dyla*0412 char *header_name = NULL;
0413
0414 program_name = argv[0];
0415
5f921c7f1… Alex*0416 args = parse_options(argc, argv, "hHi:o:s:", NULL, 0, option_callback );
0417 if (!args.count)
e6a824d5f… Dyla*0418 {
0419 usage();
0420 return 1;
0421 }
5f921c7f1… Alex*0422 infile_name = args.str[0];
e6a824d5f… Dyla*0423
3b2859a61… Alex*0424 infile = stdin;
0425 outfile = NULL;
e6a824d5f… Dyla*0426
0427 if (!strcmp(infile_name, "-")) {
0428 infile_name = "stdin";
3b2859a61… Alex*0429 } else if (!(infile = fopen(infile_name, "rb"))) {
e6a824d5f… Dyla*0430 perror(infile_name);
0431 goto error;
0432 }
0433
3b2859a61… Alex*0434 if (!read_bytes(header, sizeof(header))) {
e6a824d5f… Dyla*0435 fprintf(stderr, "%s: Failed to read file header\n", program_name);
0436 goto error;
0437 }
0438 if (strncmp(header, "xof ", 4))
0439 {
0440 fprintf(stderr, "%s: Invalid magic value '%.4s'\n", program_name, header);
0441 goto error;
0442 }
0443 if (strncmp(header + 4, "0302", 4) && strncmp(header + 4, "0303", 4))
0444 {
0445 fprintf(stderr, "%s: Unsupported version '%.4s'\n", program_name, header + 4);
0446 goto error;
0447 }
0448 if (strncmp(header + 8, "txt ", 4))
0449 {
0450 fprintf(stderr, "%s: Only support conversion from text encoded X files.",
0451 program_name);
0452 goto error;
0453 }
0454 if (strncmp(header + 12, "0032", 4) && strncmp(header + 12, "0064", 4))
0455 {
0456 fprintf(stderr, "%s: Only 32-bit or 64-bit float format supported, not '%.4s'.\n",
0457 program_name, header + 12);
0458 goto error;
0459 }
0460
7d3938e81… Alex*0461 init_output_buffer();
0462 put_data("xof 0302bin 0064", 16);
0463
0464 line_no = 1;
0465 while (parse_token());
0466
0467 if (ferror(infile))
0468 {
0469 perror(infile_name);
0470 return 1;
0471 }
0472 fclose(infile);
0473
e6a824d5f… Dyla*0474 if (!strcmp(option_outfile_name, "-")) {
0475 option_outfile_name = "stdout";
3b2859a61… Alex*0476 outfile = stdout;
e6a824d5f… Dyla*0477 } else {
0478 output_file = option_outfile_name;
0479 atexit(cleanup_files);
ae8797c8e… Alex*0480 init_signals( exit_on_signal );
3b2859a61… Alex*0481 if (!(outfile = fopen(output_file, "wb"))) {
e6a824d5f… Dyla*0482 perror(option_outfile_name);
0483 goto error;
0484 }
0485 }
0486
7d3938e81… Alex*0487 if (ferror(outfile))
166ad9696… Alex*0488 goto error;
0489
0490 if (option_header)
e6a824d5f… Dyla*0491 {
0492 char *str_ptr;
0493
166ad9696… Alex*0494 if (!option_inc_var_name)
3b2859a61… Alex*0495 fatal_error( "variable name must be specified with -i or #pragma name\n" );
166ad9696… Alex*0496
9e3959bd9… Alex*0497 header_name = get_basename( option_outfile_name );
e6a824d5f… Dyla*0498 str_ptr = header_name;
0499 while (*str_ptr) {
0500 if (*str_ptr == '.')
0501 *str_ptr = '_';
0502 else
0503 *str_ptr = toupper(*str_ptr);
0504 str_ptr++;
0505 }
0506
3b2859a61… Alex*0507 fprintf(outfile,
e6a824d5f… Dyla*0508 "/* File generated automatically from %s; do not edit */\n"
0509 "\n"
0510 "#ifndef __WINE_%s\n"
0511 "#define __WINE_%s\n"
0512 "\n"
0513 "unsigned char %s[] = {",
0514 infile_name, header_name, header_name, option_inc_var_name);
3b2859a61… Alex*0515 write_c_hex_bytes();
0516 fprintf(outfile, "\n};\n\n");
e6a824d5f… Dyla*0517 if (option_inc_size_name)
7d3938e81… Alex*0518 fprintf(outfile, "#define %s %u\n\n", option_inc_size_name, (unsigned int)output_buffer_pos);
3b2859a61… Alex*0519 fprintf(outfile, "#endif /* __WINE_%s */\n", header_name);
0520 if (ferror(outfile))
e6a824d5f… Dyla*0521 goto error;
0522 }
3b2859a61… Alex*0523 else write_raw_bytes();
e6a824d5f… Dyla*0524
3b2859a61… Alex*0525 fclose(outfile);
e6a824d5f… Dyla*0526 output_file = NULL;
0527
0528 return 0;
0529 error:
3b2859a61… Alex*0530 if (outfile) {
0531 if (ferror(outfile))
e6a824d5f… Dyla*0532 perror(option_outfile_name);
3b2859a61… Alex*0533 fclose(outfile);
e6a824d5f… Dyla*0534 }
0535 return 1;
0536 }