Back to home page

Wine source

 
 

    


File indexing completed on 2023-02-02 23:38:35

e6a824d5f Dyla*0001 /*
                0002  * Binary encode X templates from text format.
                0003  *
                0004  * Copyright 2011 Dylan Smith
                0005  *
                0006  * This library is free software; you can redistribute it and/or
                0007  * modify it under the terms of the GNU Lesser General Public
                0008  * License as published by the Free Software Foundation; either
                0009  * version 2.1 of the License, or (at your option) any later version.
                0010  *
                0011  * This library is distributed in the hope that it will be useful,
                0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                0014  * Lesser General Public License for more details.
                0015  *
                0016  * You should have received a copy of the GNU Lesser General Public
                0017  * License along with this library; if not, write to the Free Software
                0018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
                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             /* FIXME: Handle '\' (e.g. "valid\"string") */
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);  /* this will call the atexit functions */
                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 }