riched20/tests: Use common wine_dbgstr_guid implementation from test.h.
[wine/multimedia.git] / tools / make_xftmpl.c
blob75b47cc1f6fad9b80b663d731817abf21a59d27a
1 /*
2 * Binary encode X templates from text format.
4 * Copyright 2011 Dylan Smith
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <signal.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #ifdef HAVE_GETOPT_H
29 # include <getopt.h>
30 #endif
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
35 #include "windef.h"
36 #include "guiddef.h"
38 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
40 #define TOKEN_NAME 1
41 #define TOKEN_STRING 2
42 #define TOKEN_INTEGER 3
43 #define TOKEN_GUID 5
44 #define TOKEN_INTEGER_LIST 6
45 #define TOKEN_FLOAT_LIST 7
46 #define TOKEN_OBRACE 10
47 #define TOKEN_CBRACE 11
48 #define TOKEN_OPAREN 12
49 #define TOKEN_CPAREN 13
50 #define TOKEN_OBRACKET 14
51 #define TOKEN_CBRACKET 15
52 #define TOKEN_OANGLE 16
53 #define TOKEN_CANGLE 17
54 #define TOKEN_DOT 18
55 #define TOKEN_COMMA 19
56 #define TOKEN_SEMICOLON 20
57 #define TOKEN_TEMPLATE 31
58 #define TOKEN_WORD 40
59 #define TOKEN_DWORD 41
60 #define TOKEN_FLOAT 42
61 #define TOKEN_DOUBLE 43
62 #define TOKEN_CHAR 44
63 #define TOKEN_UCHAR 45
64 #define TOKEN_SWORD 46
65 #define TOKEN_SDWORD 47
66 #define TOKEN_VOID 48
67 #define TOKEN_LPSTR 49
68 #define TOKEN_UNICODE 50
69 #define TOKEN_CSTRING 51
70 #define TOKEN_ARRAY 52
72 struct parser
74 FILE *infile;
75 FILE *outfile;
76 int line_no;
79 struct keyword
81 const char *word;
82 WORD token;
85 static const struct keyword reserved_words[] = {
86 {"ARRAY", TOKEN_ARRAY},
87 {"CHAR", TOKEN_CHAR},
88 {"CSTRING", TOKEN_CSTRING},
89 {"DOUBLE", TOKEN_DOUBLE},
90 {"DWORD", TOKEN_DWORD},
91 {"FLOAT", TOKEN_FLOAT},
92 {"SDWORD", TOKEN_SDWORD},
93 {"STRING", TOKEN_LPSTR},
94 {"SWORD", TOKEN_SWORD},
95 {"TEMPLATE", TOKEN_TEMPLATE},
96 {"UCHAR", TOKEN_UCHAR},
97 {"UNICODE", TOKEN_UNICODE},
98 {"VOID", TOKEN_VOID},
99 {"WORD", TOKEN_WORD}
102 extern int getopt(int argc, char *const *argv, const char *optstring);
104 static BOOL option_header;
105 static char *option_inc_var_name = NULL;
106 static char *option_inc_size_name = NULL;
107 static const char *option_outfile_name = "-";
108 static char *program_name;
109 static const char *infile_name;
110 static BYTE *output_data;
111 static UINT output_pos, output_size;
113 #ifndef __GNUC__
114 #define __attribute__(x)
115 #endif
117 static void fatal_error( struct parser *parser, const char *msg, ... ) __attribute__ ((__format__ (__printf__, 2, 3)));
119 static void fatal_error( struct parser *parser, const char *msg, ... )
121 va_list valist;
122 va_start( valist, msg );
123 if (infile_name)
125 fprintf( stderr, "%s:%d:", infile_name, parser->line_no );
126 fprintf( stderr, " error: " );
128 else fprintf( stderr, "%s: error: ", program_name );
129 vfprintf( stderr, msg, valist );
130 va_end( valist );
131 exit( 1 );
135 static inline BOOL read_byte(struct parser *parser, char *byte)
137 int c = fgetc(parser->infile);
138 *byte = c;
139 if (c == '\n') parser->line_no++;
140 return c != EOF;
143 static inline BOOL unread_byte(struct parser *parser, char last_byte)
145 if (last_byte == '\n') parser->line_no--;
146 return ungetc(last_byte, parser->infile) != EOF;
149 static inline BOOL read_bytes(struct parser *parser, void *data, DWORD size)
151 return fread(data, size, 1, parser->infile) > 0;
154 static BOOL write_c_hex_bytes(struct parser *parser)
156 UINT i;
157 for (i = 0; i < output_pos; i++)
159 if (i % 12 == 0)
160 fprintf(parser->outfile, "\n ");
161 fprintf(parser->outfile, " 0x%02x,", output_data[i]);
163 return TRUE;
166 static BOOL write_raw_bytes(struct parser *parser)
168 return fwrite(output_data, output_pos, 1, parser->outfile) > 0;
171 static inline BOOL write_bytes(struct parser *parser, const void *data, DWORD size)
173 if (output_pos + size > output_size)
175 output_size = max( output_size * 2, size );
176 output_data = realloc( output_data, output_size );
177 if (!output_data) return FALSE;
179 memcpy( output_data + output_pos, data, size );
180 output_pos += size;
181 return TRUE;
184 static inline BOOL write_byte(struct parser *parser, BYTE value)
186 return write_bytes(parser, &value, sizeof(value));
189 static inline BOOL write_word(struct parser *parser, WORD value)
191 return write_bytes(parser, &value, sizeof(value));
194 static inline BOOL write_dword(struct parser *parser, DWORD value)
196 return write_bytes(parser, &value, sizeof(value));
199 static int compare_names(const void *a, const void *b)
201 return strcasecmp(*(const char **)a, *(const char **)b);
204 static BOOL parse_keyword(struct parser *parser, const char *name)
206 const struct keyword *keyword;
208 keyword = bsearch(&name, reserved_words, ARRAY_SIZE(reserved_words),
209 sizeof(reserved_words[0]), compare_names);
210 if (!keyword)
211 return FALSE;
213 return write_word(parser, keyword->token);
216 static BOOL parse_guid(struct parser *parser)
218 char buf[39];
219 GUID guid;
220 DWORD tab[10];
221 BOOL ret;
222 static const char *guidfmt = "<%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>";
224 buf[0] = '<';
225 if (!read_bytes(parser, buf + 1, 37)) fatal_error( parser, "truncated GUID\n" );
226 buf[38] = 0;
228 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);
229 if (ret != 11) fatal_error( parser, "invalid GUID '%s'\n", buf );
231 guid.Data2 = tab[0];
232 guid.Data3 = tab[1];
233 guid.Data4[0] = tab[2];
234 guid.Data4[1] = tab[3];
235 guid.Data4[2] = tab[4];
236 guid.Data4[3] = tab[5];
237 guid.Data4[4] = tab[6];
238 guid.Data4[5] = tab[7];
239 guid.Data4[6] = tab[8];
240 guid.Data4[7] = tab[9];
242 return write_word(parser, TOKEN_GUID) &&
243 write_bytes(parser, &guid, sizeof(guid));
246 static BOOL parse_name(struct parser *parser)
248 char c;
249 int len = 0;
250 char name[512];
252 while (read_byte(parser, &c) && len < sizeof(name) &&
253 (isalnum(c) || c == '_' || c == '-'))
255 if (len + 1 < sizeof(name))
256 name[len++] = c;
258 unread_byte(parser, c);
259 name[len] = 0;
261 if (parse_keyword(parser, name)) {
262 return TRUE;
263 } else {
264 return write_word(parser, TOKEN_NAME) &&
265 write_dword(parser, len) &&
266 write_bytes(parser, name, len);
270 static BOOL parse_number(struct parser *parser)
272 int len = 0;
273 char c;
274 char buffer[512];
275 BOOL dot = FALSE;
276 BOOL ret;
278 while (read_byte(parser, &c) &&
279 ((!len && c == '-') || (!dot && c == '.') || isdigit(c)))
281 if (len + 1 < sizeof(buffer))
282 buffer[len++] = c;
283 if (c == '.')
284 dot = TRUE;
286 unread_byte(parser, c);
287 buffer[len] = 0;
289 if (dot) {
290 float value;
291 ret = sscanf(buffer, "%f", &value);
292 if (!ret) fatal_error( parser, "invalid float token\n" );
293 ret = write_word(parser, TOKEN_FLOAT) &&
294 write_bytes(parser, &value, sizeof(value));
295 } else {
296 int value;
297 ret = sscanf(buffer, "%d", &value);
298 if (!ret) fatal_error( parser, "invalid integer token\n" );
299 ret = write_word(parser, TOKEN_INTEGER) &&
300 write_dword(parser, value);
303 return ret;
306 static BOOL parse_token(struct parser *parser)
308 char c;
309 int len;
310 char *tok, buffer[512];
312 if (!read_byte(parser, &c))
313 return FALSE;
315 switch (c)
317 case '\n':
318 case '\r':
319 case ' ':
320 case '\t':
321 return TRUE;
323 case '{': return write_word(parser, TOKEN_OBRACE);
324 case '}': return write_word(parser, TOKEN_CBRACE);
325 case '[': return write_word(parser, TOKEN_OBRACKET);
326 case ']': return write_word(parser, TOKEN_CBRACKET);
327 case '(': return write_word(parser, TOKEN_OPAREN);
328 case ')': return write_word(parser, TOKEN_CPAREN);
329 case ',': return write_word(parser, TOKEN_COMMA);
330 case ';': return write_word(parser, TOKEN_SEMICOLON);
331 case '.': return write_word(parser, TOKEN_DOT);
333 case '/':
334 if (!read_byte(parser, &c) || c != '/')
335 fatal_error( parser, "invalid single '/' comment token\n" );
336 while (read_byte(parser, &c) && c != '\n');
337 return c == '\n';
339 case '#':
340 len = 0;
341 while (read_byte(parser, &c) && c != '\n')
342 if (len + 1 < sizeof(buffer)) buffer[len++] = c;
343 if (c != '\n') fatal_error( parser, "line too long\n" );
344 buffer[len] = 0;
345 tok = strtok( buffer, " \t" );
346 if (!tok || strcmp( tok, "pragma" )) return TRUE;
347 tok = strtok( NULL, " \t" );
348 if (!tok || strcmp( tok, "xftmpl" )) return TRUE;
349 tok = strtok( NULL, " \t" );
350 if (!tok) return TRUE;
351 if (!strcmp( tok, "name" ))
353 tok = strtok( NULL, " \t" );
354 if (tok && !option_inc_var_name) option_inc_var_name = strdup( tok );
356 else if (!strcmp( tok, "size" ))
358 tok = strtok( NULL, " \t" );
359 if (tok && !option_inc_size_name) option_inc_size_name = strdup( tok );
361 return TRUE;
363 case '<':
364 return parse_guid(parser);
366 case '"':
367 len = 0;
369 /* FIXME: Handle '\' (e.g. "valid\"string") */
370 while (read_byte(parser, &c) && c != '"') {
371 if (len + 1 < sizeof(buffer))
372 buffer[len++] = c;
374 if (c != '"') fatal_error( parser, "unterminated string\n" );
375 return write_word(parser, TOKEN_STRING) &&
376 write_dword(parser, len) &&
377 write_bytes(parser, buffer, len);
379 default:
380 unread_byte(parser, c);
381 if (isdigit(c) || c == '-')
382 return parse_number(parser);
383 if (isalpha(c) || c == '_')
384 return parse_name(parser);
385 fatal_error( parser, "invalid character '%c' to start token\n", c );
388 return TRUE;
391 static const char *output_file;
393 static void cleanup_files(void)
395 if (output_file) unlink(output_file);
398 static void exit_on_signal( int sig )
400 exit(1); /* this will call the atexit functions */
403 static void usage(void)
405 fprintf(stderr, "Usage: %s [OPTIONS] INFILE\n"
406 "Options:\n"
407 " -H Output to a c header file instead of a binary file\n"
408 " -i NAME Output to a c header file, data in variable NAME\n"
409 " -s NAME In a c header file, define NAME to be the data size\n"
410 " -o FILE Write output to FILE\n",
411 program_name);
414 static char **parse_options(int argc, char **argv)
416 int optc;
418 while ((optc = getopt(argc, argv, "hHi:o:s:")) != -1)
420 switch (optc)
422 case 'h':
423 usage();
424 exit(0);
425 case 'H':
426 option_header = TRUE;
427 break;
428 case 'i':
429 option_header = TRUE;
430 option_inc_var_name = strdup(optarg);
431 break;
432 case 'o':
433 option_outfile_name = strdup(optarg);
434 break;
435 case 's':
436 option_inc_size_name = strdup(optarg);
437 break;
440 return &argv[optind];
443 int main(int argc, char **argv)
445 char header[16];
446 struct parser parser;
447 char **args;
448 char *header_name = NULL;
450 program_name = argv[0];
452 args = parse_options(argc, argv);
453 infile_name = *args++;
454 if (!infile_name || *args)
456 usage();
457 return 1;
460 parser.infile = stdin;
461 parser.outfile = NULL;
463 if (!strcmp(infile_name, "-")) {
464 infile_name = "stdin";
465 } else if (!(parser.infile = fopen(infile_name, "rb"))) {
466 perror(infile_name);
467 goto error;
470 if (!read_bytes(&parser, header, sizeof(header))) {
471 fprintf(stderr, "%s: Failed to read file header\n", program_name);
472 goto error;
474 if (strncmp(header, "xof ", 4))
476 fprintf(stderr, "%s: Invalid magic value '%.4s'\n", program_name, header);
477 goto error;
479 if (strncmp(header + 4, "0302", 4) && strncmp(header + 4, "0303", 4))
481 fprintf(stderr, "%s: Unsupported version '%.4s'\n", program_name, header + 4);
482 goto error;
484 if (strncmp(header + 8, "txt ", 4))
486 fprintf(stderr, "%s: Only support conversion from text encoded X files.",
487 program_name);
488 goto error;
490 if (strncmp(header + 12, "0032", 4) && strncmp(header + 12, "0064", 4))
492 fprintf(stderr, "%s: Only 32-bit or 64-bit float format supported, not '%.4s'.\n",
493 program_name, header + 12);
494 goto error;
497 if (!strcmp(option_outfile_name, "-")) {
498 option_outfile_name = "stdout";
499 parser.outfile = stdout;
500 } else {
501 output_file = option_outfile_name;
502 atexit(cleanup_files);
503 signal(SIGTERM, exit_on_signal);
504 signal(SIGINT, exit_on_signal);
505 #ifdef SIGHUP
506 signal(SIGHUP, exit_on_signal);
507 #endif
508 if (!(parser.outfile = fopen(output_file, "wb"))) {
509 perror(option_outfile_name);
510 goto error;
514 if (!write_bytes(&parser, "xof 0302bin 0064", 16))
515 goto error;
517 parser.line_no = 1;
518 while (parse_token(&parser));
520 if (ferror(parser.outfile) || ferror(parser.infile))
521 goto error;
523 if (option_header)
525 char *str_ptr;
527 if (!option_inc_var_name)
528 fatal_error( &parser, "variable name must be specified with -i or #pragma name\n" );
530 header_name = strrchr(option_outfile_name, '/');
531 if (header_name)
532 header_name = strdup(header_name + 1);
533 else
534 header_name = strdup(option_outfile_name);
535 if (!header_name) {
536 fprintf(stderr, "Out of memory\n");
537 goto error;
540 str_ptr = header_name;
541 while (*str_ptr) {
542 if (*str_ptr == '.')
543 *str_ptr = '_';
544 else
545 *str_ptr = toupper(*str_ptr);
546 str_ptr++;
549 fprintf(parser.outfile,
550 "/* File generated automatically from %s; do not edit */\n"
551 "\n"
552 "#ifndef __WINE_%s\n"
553 "#define __WINE_%s\n"
554 "\n"
555 "unsigned char %s[] = {",
556 infile_name, header_name, header_name, option_inc_var_name);
557 write_c_hex_bytes( &parser );
558 fprintf(parser.outfile, "\n};\n\n");
559 if (option_inc_size_name)
560 fprintf(parser.outfile, "#define %s %u\n\n", option_inc_size_name, output_pos);
561 fprintf(parser.outfile, "#endif /* __WINE_%s */\n", header_name);
562 if (ferror(parser.outfile))
563 goto error;
565 else write_raw_bytes( &parser );
567 fclose(parser.infile);
568 fclose(parser.outfile);
569 output_file = NULL;
571 return 0;
572 error:
573 if (parser.infile) {
574 if (ferror(parser.infile))
575 perror(infile_name);
576 fclose(parser.infile);
578 if (parser.outfile) {
579 if (ferror(parser.outfile))
580 perror(option_outfile_name);
581 fclose(parser.outfile);
583 return 1;