comdlg32: Rewrite the 10ths mm conversion function to use the is_metric helper.
[wine] / dlls / d3dxof / parsing.c
1 /*
2  * X Files parsing
3  *
4  * Copyright 2008 Christian Costa
5  *
6  * This file contains the (internal) driver registration functions,
7  * driver enumeration APIs and DirectDraw creation functions.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wine/debug.h"
26
27 #define COBJMACROS
28
29 #include "winbase.h"
30 #include "wingdi.h"
31
32 #include "d3dxof_private.h"
33 #include "dxfile.h"
34
35 #include <stdio.h>
36
37 WINE_DEFAULT_DEBUG_CHANNEL(d3dxof);
38
39 #define TOKEN_NAME         1
40 #define TOKEN_STRING       2
41 #define TOKEN_INTEGER      3
42 #define TOKEN_GUID         5
43 #define TOKEN_INTEGER_LIST 6
44 #define TOKEN_FLOAT_LIST   7
45 #define TOKEN_OBRACE      10
46 #define TOKEN_CBRACE      11
47 #define TOKEN_OPAREN      12
48 #define TOKEN_CPAREN      13
49 #define TOKEN_OBRACKET    14
50 #define TOKEN_CBRACKET    15
51 #define TOKEN_OANGLE      16
52 #define TOKEN_CANGLE      17
53 #define TOKEN_DOT         18
54 #define TOKEN_COMMA       19
55 #define TOKEN_SEMICOLON   20
56 #define TOKEN_TEMPLATE    31
57 #define TOKEN_WORD        40
58 #define TOKEN_DWORD       41
59 #define TOKEN_FLOAT       42
60 #define TOKEN_DOUBLE      43
61 #define TOKEN_CHAR        44
62 #define TOKEN_UCHAR       45
63 #define TOKEN_SWORD       46
64 #define TOKEN_SDWORD      47
65 #define TOKEN_VOID        48
66 #define TOKEN_LPSTR       49
67 #define TOKEN_UNICODE     50
68 #define TOKEN_CSTRING     51
69 #define TOKEN_ARRAY       52
70
71 #define CLSIDFMT "<%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>"
72
73 static const char* get_primitive_string(WORD token)
74 {
75   switch(token)
76   {
77     case TOKEN_WORD:
78       return "WORD";
79     case TOKEN_DWORD:
80       return "DWORD";
81     case TOKEN_FLOAT:
82       return "FLOAT";
83     case TOKEN_DOUBLE:
84       return "DOUBLE";
85     case TOKEN_CHAR:
86       return "CHAR";
87     case TOKEN_UCHAR:
88       return "UCHAR";
89     case TOKEN_SWORD:
90       return "SWORD";
91     case TOKEN_SDWORD:
92       return "SDWORD";
93     case TOKEN_VOID:
94       return "VOID";
95     case TOKEN_LPSTR:
96       return "STRING";
97     case TOKEN_UNICODE:
98       return "UNICODE";
99     case TOKEN_CSTRING:
100       return "CSTRING ";
101     default:
102       break;
103   }
104   return NULL;
105 }
106
107 void dump_template(xtemplate* templates_array, xtemplate* ptemplate)
108 {
109   int j, k;
110   GUID* clsid;
111
112   clsid = &ptemplate->class_id;
113
114   DPRINTF("template %s\n", ptemplate->name);
115   DPRINTF("{\n");
116   DPRINTF(CLSIDFMT "\n", clsid->Data1, clsid->Data2, clsid->Data3, clsid->Data4[0],
117   clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7]);
118   for (j = 0; j < ptemplate->nb_members; j++)
119   {
120     if (ptemplate->members[j].nb_dims)
121       DPRINTF("array ");
122     if (ptemplate->members[j].type == TOKEN_NAME)
123       DPRINTF("%s ", templates_array[ptemplate->members[j].idx_template].name);
124     else
125       DPRINTF("%s ", get_primitive_string(ptemplate->members[j].type));
126     DPRINTF("%s", ptemplate->members[j].name);
127     for (k = 0; k < ptemplate->members[j].nb_dims; k++)
128     {
129       if (ptemplate->members[j].dim_fixed[k])
130         DPRINTF("[%d]", ptemplate->members[j].dim_value[k]);
131       else
132         DPRINTF("[%s]", ptemplate->members[ptemplate->members[j].dim_value[k]].name);
133     }
134     DPRINTF(";\n");
135   }
136   if (ptemplate->open)
137     DPRINTF("[...]\n");
138   else if (ptemplate->nb_childs)
139   {
140     DPRINTF("[%s", ptemplate->childs[0]);
141     for (j = 1; j < ptemplate->nb_childs; j++)
142       DPRINTF(",%s", ptemplate->childs[j]);
143     DPRINTF("]\n");
144   }
145   DPRINTF("}\n");
146 }
147
148 BOOL read_bytes(parse_buffer * buf, LPVOID data, DWORD size)
149 {
150   if (buf->rem_bytes < size)
151     return FALSE;
152   memcpy(data, buf->buffer, size);
153   buf->buffer += size;
154   buf->rem_bytes -= size;
155   return TRUE;
156 }
157
158 static void rewind_bytes(parse_buffer * buf, DWORD size)
159 {
160   buf->buffer -= size;
161   buf->rem_bytes += size;
162 }
163
164 static void dump_TOKEN(WORD token)
165 {
166 #define DUMP_TOKEN(t) case t: TRACE(#t "\n"); break
167   switch(token)
168   {
169     DUMP_TOKEN(TOKEN_NAME);
170     DUMP_TOKEN(TOKEN_STRING);
171     DUMP_TOKEN(TOKEN_INTEGER);
172     DUMP_TOKEN(TOKEN_GUID);
173     DUMP_TOKEN(TOKEN_INTEGER_LIST);
174     DUMP_TOKEN(TOKEN_FLOAT_LIST);
175     DUMP_TOKEN(TOKEN_OBRACE);
176     DUMP_TOKEN(TOKEN_CBRACE);
177     DUMP_TOKEN(TOKEN_OPAREN);
178     DUMP_TOKEN(TOKEN_CPAREN);
179     DUMP_TOKEN(TOKEN_OBRACKET);
180     DUMP_TOKEN(TOKEN_CBRACKET);
181     DUMP_TOKEN(TOKEN_OANGLE);
182     DUMP_TOKEN(TOKEN_CANGLE);
183     DUMP_TOKEN(TOKEN_DOT);
184     DUMP_TOKEN(TOKEN_COMMA);
185     DUMP_TOKEN(TOKEN_SEMICOLON);
186     DUMP_TOKEN(TOKEN_TEMPLATE);
187     DUMP_TOKEN(TOKEN_WORD);
188     DUMP_TOKEN(TOKEN_DWORD);
189     DUMP_TOKEN(TOKEN_FLOAT);
190     DUMP_TOKEN(TOKEN_DOUBLE);
191     DUMP_TOKEN(TOKEN_CHAR);
192     DUMP_TOKEN(TOKEN_UCHAR);
193     DUMP_TOKEN(TOKEN_SWORD);
194     DUMP_TOKEN(TOKEN_SDWORD);
195     DUMP_TOKEN(TOKEN_VOID);
196     DUMP_TOKEN(TOKEN_LPSTR);
197     DUMP_TOKEN(TOKEN_UNICODE);
198     DUMP_TOKEN(TOKEN_CSTRING);
199     DUMP_TOKEN(TOKEN_ARRAY);
200     default:
201       if (0)
202         TRACE("Unknown token %d\n", token);
203       break;
204   }
205 #undef DUMP_TOKEN
206 }
207
208 static BOOL is_space(char c)
209 {
210   switch (c)
211   {
212     case 0x00:
213     case 0x0D:
214     case 0x0A:
215     case ' ':
216     case '\t':
217       return TRUE;
218   }
219   return FALSE;
220 }
221
222 static BOOL is_operator(char c)
223 {
224   switch(c)
225   {
226     case '{':
227     case '}':
228     case '[':
229     case ']':
230     case '(':
231     case ')':
232     case '<':
233     case '>':
234     case ',':
235     case ';':
236       return TRUE;
237   }
238   return FALSE;
239 }
240
241 static inline BOOL is_separator(char c)
242 {
243   return is_space(c) || is_operator(c);
244 }
245
246 static WORD get_operator_token(char c)
247 {
248   switch(c)
249   {
250     case '{':
251       return TOKEN_OBRACE;
252     case '}':
253       return TOKEN_CBRACE;
254     case '[':
255       return TOKEN_OBRACKET;
256     case ']':
257       return TOKEN_CBRACKET;
258     case '(':
259       return TOKEN_OPAREN;
260     case ')':
261       return TOKEN_CPAREN;
262     case '<':
263       return TOKEN_OANGLE;
264     case '>':
265       return TOKEN_CANGLE;
266     case ',':
267       return TOKEN_COMMA;
268     case ';':
269       return TOKEN_SEMICOLON;
270   }
271   return 0;
272 }
273
274 static BOOL is_keyword(parse_buffer* buf, const char* keyword)
275 {
276   char tmp[9]; /* template keyword size + 1 */
277   DWORD len = strlen(keyword);
278   read_bytes(buf, tmp, len+1);
279   if (!strncasecmp(tmp, keyword,len) && is_separator(tmp[len]))
280   {
281     rewind_bytes(buf, 1);
282     return TRUE;
283   }
284   rewind_bytes(buf, len+1);
285   return FALSE;
286 }
287
288 static WORD get_keyword_token(parse_buffer* buf)
289 {
290   if (is_keyword(buf, "template"))
291     return TOKEN_TEMPLATE;
292   if (is_keyword(buf, "WORD"))
293     return TOKEN_WORD;
294   if (is_keyword(buf, "DWORD"))
295     return TOKEN_DWORD;
296   if (is_keyword(buf, "FLOAT"))
297     return TOKEN_FLOAT;
298   if (is_keyword(buf, "DOUBLE"))
299     return TOKEN_DOUBLE;
300   if (is_keyword(buf, "CHAR"))
301     return TOKEN_CHAR;
302   if (is_keyword(buf, "UCHAR"))
303     return TOKEN_UCHAR;
304   if (is_keyword(buf, "SWORD"))
305     return TOKEN_SWORD;
306   if (is_keyword(buf, "SDWORD"))
307     return TOKEN_SDWORD;
308   if (is_keyword(buf, "VOID"))
309     return TOKEN_VOID;
310   if (is_keyword(buf, "STRING"))
311     return TOKEN_LPSTR;
312   if (is_keyword(buf, "UNICODE"))
313     return TOKEN_UNICODE;
314   if (is_keyword(buf, "CSTRING"))
315     return TOKEN_CSTRING;
316   if (is_keyword(buf, "array"))
317     return TOKEN_ARRAY;
318
319   return 0;
320 }
321
322 static BOOL is_guid(parse_buffer* buf)
323 {
324   char tmp[50];
325   DWORD pos = 1;
326   GUID class_id;
327   DWORD tab[10];
328   int ret;
329
330   if (*buf->buffer != '<')
331     return FALSE;
332   tmp[0] = '<';
333   while (*(buf->buffer+pos) != '>')
334   {
335     tmp[pos] = *(buf->buffer+pos);
336     pos++;
337   }
338   tmp[pos++] = '>';
339   tmp[pos] = 0;
340   if (pos != 38 /* <+36+> */)
341   {
342     TRACE("Wrong guid %s (%d)\n", tmp, pos);
343     return FALSE;
344   }
345   buf->buffer += pos;
346   buf->rem_bytes -= pos;
347
348   ret = sscanf(tmp, CLSIDFMT, &class_id.Data1, tab, tab+1, tab+2, tab+3, tab+4, tab+5, tab+6, tab+7, tab+8, tab+9);
349   if (ret != 11)
350   {
351     TRACE("Wrong guid %s (%d)\n", tmp, pos);
352     return FALSE;
353   }
354   TRACE("Found guid %s (%d)\n", tmp, pos);
355
356   class_id.Data2 = tab[0];
357   class_id.Data3 = tab[1];
358   class_id.Data4[0] = tab[2];
359   class_id.Data4[1] = tab[3];
360   class_id.Data4[2] = tab[4];
361   class_id.Data4[3] = tab[5];
362   class_id.Data4[4] = tab[6];
363   class_id.Data4[5] = tab[7];
364   class_id.Data4[6] = tab[8];
365   class_id.Data4[7] = tab[9];
366
367   *(GUID*)buf->value = class_id;
368
369   return TRUE;
370 }
371
372 static BOOL is_name(parse_buffer* buf)
373 {
374   char tmp[50];
375   DWORD pos = 0;
376   char c;
377   BOOL error = 0;
378   while (!is_separator(c = *(buf->buffer+pos)))
379   {
380     if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '_') || (c == '-')))
381       error = 1;
382     tmp[pos++] = c;
383   }
384   tmp[pos] = 0;
385
386   if (error)
387   {
388     TRACE("Wrong name %s\n", tmp);
389     return FALSE;
390   }
391
392   buf->buffer += pos;
393   buf->rem_bytes -= pos;
394
395   TRACE("Found name %s\n", tmp);
396   strcpy((char*)buf->value, tmp);
397
398   return TRUE;
399 }
400
401 static BOOL is_float(parse_buffer* buf)
402 {
403   char tmp[50];
404   DWORD pos = 0;
405   char c;
406   float decimal;
407   BOOL dot = 0;
408
409   while (!is_separator(c = *(buf->buffer+pos)))
410   {
411     if (!((!pos && (c == '-')) || ((c >= '0') && (c <= '9')) || (!dot && (c == '.'))))
412       return FALSE;
413     if (c == '.')
414       dot = TRUE;
415     tmp[pos++] = c;
416   }
417   tmp[pos] = 0;
418
419   buf->buffer += pos;
420   buf->rem_bytes -= pos;
421
422   sscanf(tmp, "%f", &decimal);
423
424   TRACE("Found float %s - %f\n", tmp, decimal);
425
426   *(float*)buf->value = decimal;
427
428   return TRUE;
429 }
430
431 static BOOL is_integer(parse_buffer* buf)
432 {
433   char tmp[50];
434   DWORD pos = 0;
435   char c;
436   DWORD integer;
437
438   while (!is_separator(c = *(buf->buffer+pos)))
439   {
440     if (!((c >= '0') && (c <= '9')))
441       return FALSE;
442     tmp[pos++] = c;
443   }
444   tmp[pos] = 0;
445
446   buf->buffer += pos;
447   buf->rem_bytes -= pos;
448
449   sscanf(tmp, "%d", &integer);
450
451   TRACE("Found integer %s - %d\n", tmp, integer);
452
453   *(DWORD*)buf->value = integer;
454
455   return TRUE;
456 }
457
458 static BOOL is_string(parse_buffer* buf)
459 {
460   char tmp[32];
461   DWORD pos = 0;
462   char c;
463   BOOL ok = 0;
464
465   if (*buf->buffer != '"')
466     return FALSE;
467
468   while (!is_separator(c = *(buf->buffer+pos+1)) && (pos < 31))
469   {
470     if (c == '"')
471     {
472       ok = 1;
473       break;
474     }
475     tmp[pos++] = c;
476   }
477   tmp[pos] = 0;
478
479   if (!ok)
480   {
481     TRACE("Wrong string %s\n", tmp);
482     return FALSE;
483   }
484
485   buf->buffer += pos + 2;
486   buf->rem_bytes -= pos + 2;
487
488   TRACE("Found string %s\n", tmp);
489   strcpy((char*)buf->value, tmp);
490
491   return TRUE;
492 }
493
494 static WORD parse_TOKEN(parse_buffer * buf)
495 {
496   WORD token;
497
498   if (buf->txt)
499   {
500     while(1)
501     {
502       char c;
503       if (!read_bytes(buf, &c, 1))
504         return 0;
505       /*TRACE("char = '%c'\n", is_space(c) ? ' ' : c);*/
506       if ((c == '#') || (c == '/'))
507       {
508         /* Handle comment (# or //) */
509         if (c == '/')
510         {
511           if (!read_bytes(buf, &c, 1))
512             return 0;
513           if (c != '/')
514             return 0;
515         }
516         c = 0;
517         while (c != 0x0A)
518         {
519           if (!read_bytes(buf, &c, 1))
520             return 0;
521         }
522         continue;
523       }
524       if (is_space(c))
525         continue;
526       if (is_operator(c) && (c != '<'))
527       {
528         token = get_operator_token(c);
529         break;
530       }
531       else if (c == '.')
532       {
533         token = TOKEN_DOT;
534         break;
535       }
536       else
537       {
538         rewind_bytes(buf, 1);
539
540         if ((token = get_keyword_token(buf)))
541           break;
542
543         if (is_guid(buf))
544         {
545           token = TOKEN_GUID;
546           break;
547         }
548         if (is_integer(buf))
549         {
550           token = TOKEN_INTEGER;
551           break;
552         }
553         if (is_float(buf))
554         {
555           token = TOKEN_FLOAT;
556           break;
557         }
558         if (is_string(buf))
559         {
560           token = TOKEN_LPSTR;
561           break;
562         }
563         if (is_name(buf))
564         {
565           token = TOKEN_NAME;
566           break;
567         }
568
569         FIXME("Unrecognize element\n");
570         return 0;
571       }
572     }
573   }
574   else
575   {
576     static int nb_elem;
577     static int is_float;
578
579     if (!nb_elem)
580     {
581       if (!read_bytes(buf, &token, 2))
582         return 0;
583
584       /* Convert integer and float list into separate elements */
585       if (token == TOKEN_INTEGER_LIST)
586       {
587         if (!read_bytes(buf, &nb_elem, 4))
588           return 0;
589         token = TOKEN_INTEGER;
590         is_float = FALSE;
591         TRACE("Integer list (TOKEN_INTEGER_LIST) of size %d\n", nb_elem);
592       }
593       else if (token == TOKEN_FLOAT_LIST)
594       {
595         if (!read_bytes(buf, &nb_elem, 4))
596           return 0;
597         token = TOKEN_FLOAT;
598         is_float = TRUE;
599         TRACE("Float list (TOKEN_FLOAT_LIST) of size %d\n", nb_elem);
600       }
601     }
602
603     if (nb_elem)
604     {
605       token = is_float ? TOKEN_FLOAT : TOKEN_INTEGER;
606       nb_elem--;
607         {
608           DWORD integer;
609
610           if (!read_bytes(buf, &integer, 4))
611             return 0;
612
613           *(DWORD*)buf->value = integer;
614         }
615       dump_TOKEN(token);
616       return token;
617     }
618
619     switch (token)
620     {
621       case TOKEN_NAME:
622         {
623           DWORD count;
624           char strname[100];
625
626           if (!read_bytes(buf, &count, 4))
627             return 0;
628           if (!read_bytes(buf, strname, count))
629             return 0;
630           strname[count] = 0;
631           /*TRACE("name = %s\n", strname);*/
632
633           strcpy((char*)buf->value, strname);
634         }
635         break;
636       case TOKEN_INTEGER:
637         {
638           DWORD integer;
639
640           if (!read_bytes(buf, &integer, 4))
641             return 0;
642           /*TRACE("integer = %ld\n", integer);*/
643
644           *(DWORD*)buf->value = integer;
645         }
646         break;
647       case TOKEN_GUID:
648         {
649           char strguid[39];
650           GUID class_id;
651
652           if (!read_bytes(buf, &class_id, 16))
653             return 0;
654           sprintf(strguid, CLSIDFMT, class_id.Data1, class_id.Data2, class_id.Data3, class_id.Data4[0],
655             class_id.Data4[1], class_id.Data4[2], class_id.Data4[3], class_id.Data4[4], class_id.Data4[5],
656             class_id.Data4[6], class_id.Data4[7]);
657           /*TRACE("guid = {%s}\n", strguid);*/
658
659           *(GUID*)buf->value = class_id;
660         }
661         break;
662       case TOKEN_STRING:
663         {
664           DWORD count;
665           WORD tmp_token;
666           char strname[100];
667           if (!read_bytes(buf, &count, 4))
668             return 0;
669           if (!read_bytes(buf, strname, count))
670             return 0;
671           strname[count] = 0;
672           if (!read_bytes(buf, &tmp_token, 2))
673             return 0;
674           if ((tmp_token != TOKEN_COMMA) && (tmp_token != TOKEN_SEMICOLON))
675             ERR("No comma or semicolon (got %d)\n", tmp_token);
676           /*TRACE("name = %s\n", strname);*/
677
678           strcpy((char*)buf->value, strname);
679           token = TOKEN_LPSTR;
680         }
681         break;
682       case TOKEN_OBRACE:
683       case TOKEN_CBRACE:
684       case TOKEN_OPAREN:
685       case TOKEN_CPAREN:
686       case TOKEN_OBRACKET:
687       case TOKEN_CBRACKET:
688       case TOKEN_OANGLE:
689       case TOKEN_CANGLE:
690       case TOKEN_DOT:
691       case TOKEN_COMMA:
692       case TOKEN_SEMICOLON:
693       case TOKEN_TEMPLATE:
694       case TOKEN_WORD:
695       case TOKEN_DWORD:
696       case TOKEN_FLOAT:
697       case TOKEN_DOUBLE:
698       case TOKEN_CHAR:
699       case TOKEN_UCHAR:
700       case TOKEN_SWORD:
701       case TOKEN_SDWORD:
702       case TOKEN_VOID:
703       case TOKEN_LPSTR:
704       case TOKEN_UNICODE:
705       case TOKEN_CSTRING:
706       case TOKEN_ARRAY:
707         break;
708       default:
709         return 0;
710     }
711   }
712
713   dump_TOKEN(token);
714
715   return token;
716 }
717
718 static WORD get_TOKEN(parse_buffer * buf)
719 {
720   if (buf->token_present)
721   {
722     buf->token_present = FALSE;
723     return buf->current_token;
724   }
725
726   buf->current_token = parse_TOKEN(buf);
727
728   return buf->current_token;
729 }
730
731 static WORD check_TOKEN(parse_buffer * buf)
732 {
733   if (buf->token_present)
734     return buf->current_token;
735
736   buf->current_token = parse_TOKEN(buf);
737   buf->token_present = TRUE;
738
739   return buf->current_token;
740 }
741
742 BOOL is_template_available(parse_buffer * buf)
743 {
744   return check_TOKEN(buf) == TOKEN_TEMPLATE;
745 }
746
747 static inline BOOL is_primitive_type(WORD token)
748 {
749   BOOL ret;
750   switch(token)
751   {
752     case TOKEN_WORD:
753     case TOKEN_DWORD:
754     case TOKEN_FLOAT:
755     case TOKEN_DOUBLE:
756     case TOKEN_CHAR:
757     case TOKEN_UCHAR:
758     case TOKEN_SWORD:
759     case TOKEN_SDWORD:
760     case TOKEN_LPSTR:
761     case TOKEN_UNICODE:
762     case TOKEN_CSTRING:
763       ret = 1;
764       break;
765     default:
766       ret = 0;
767       break;
768   }
769   return ret;
770 }
771
772 static BOOL parse_template_option_info(parse_buffer * buf)
773 {
774   xtemplate* cur_template = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates];
775
776   if (check_TOKEN(buf) == TOKEN_DOT)
777   {
778     get_TOKEN(buf);
779     if (get_TOKEN(buf) != TOKEN_DOT)
780       return FALSE;
781     if (get_TOKEN(buf) != TOKEN_DOT)
782       return FALSE;
783     cur_template->open = TRUE;
784   }
785   else
786   {
787     while (1)
788     {
789       if (get_TOKEN(buf) != TOKEN_NAME)
790         return FALSE;
791       strcpy(cur_template->childs[cur_template->nb_childs], (char*)buf->value);
792       if (check_TOKEN(buf) == TOKEN_GUID)
793         get_TOKEN(buf);
794       cur_template->nb_childs++;
795       if (check_TOKEN(buf) != TOKEN_COMMA)
796         break;
797       get_TOKEN(buf);
798     }
799     cur_template->open = FALSE;
800   }
801
802   return TRUE;
803 }
804
805 static BOOL parse_template_members_list(parse_buffer * buf)
806 {
807   int idx_member = 0;
808   member* cur_member;
809
810   while (1)
811   {
812     BOOL array = 0;
813     int nb_dims = 0;
814     cur_member = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[idx_member];
815
816     if (check_TOKEN(buf) == TOKEN_ARRAY)
817     {
818       get_TOKEN(buf);
819       array = 1;
820     }
821
822     if (check_TOKEN(buf) == TOKEN_NAME)
823     {
824       cur_member->type = get_TOKEN(buf);
825       cur_member->idx_template = 0;
826       while (cur_member->idx_template < buf->pdxf->nb_xtemplates)
827       {
828         if (!strcasecmp((char*)buf->value, buf->pdxf->xtemplates[cur_member->idx_template].name))
829           break;
830         cur_member->idx_template++;
831       }
832       if (cur_member->idx_template == buf->pdxf->nb_xtemplates)
833       {
834         ERR("Reference to a nonexistent template '%s'\n", (char*)buf->value);
835         return FALSE;
836       }
837     }
838     else if (is_primitive_type(check_TOKEN(buf)))
839       cur_member->type = get_TOKEN(buf);
840     else
841       break;
842
843     if (get_TOKEN(buf) != TOKEN_NAME)
844       return FALSE;
845     strcpy(cur_member->name, (char*)buf->value);
846
847     if (array)
848     {
849       while (check_TOKEN(buf) == TOKEN_OBRACKET)
850       {
851         if (nb_dims >= MAX_ARRAY_DIM)
852         {
853           FIXME("Too many dimensions (%d) for multi-dimensional array\n", nb_dims + 1);
854           return FALSE;
855         }
856         get_TOKEN(buf);
857         if (check_TOKEN(buf) == TOKEN_INTEGER)
858         {
859           get_TOKEN(buf);
860           cur_member->dim_fixed[nb_dims] = TRUE;
861           cur_member->dim_value[nb_dims] = *(DWORD*)buf->value;
862         }
863         else
864         {
865           int i;
866           if (get_TOKEN(buf) != TOKEN_NAME)
867             return FALSE;
868           for (i = 0; i < idx_member; i++)
869           {
870             if (!strcmp((char*)buf->value, buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].name))
871             {
872               if (buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].nb_dims)
873               {
874                 ERR("Array cannot be used to specify variable array size\n");
875                 return FALSE;
876               }
877               if (buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].type != TOKEN_DWORD)
878               {
879                 FIXME("Only DWORD supported to specify variable array size\n");
880                 return FALSE;
881               }
882               break;
883             }
884           }
885           if (i == idx_member)
886           {
887             ERR("Reference to unknown member %s\n", (char*)buf->value);
888             return FALSE;
889           }
890           cur_member->dim_fixed[nb_dims] = FALSE;
891           cur_member->dim_value[nb_dims] = i;
892         }
893         if (get_TOKEN(buf) != TOKEN_CBRACKET)
894           return FALSE;
895         nb_dims++;
896       }
897       if (!nb_dims)
898         return FALSE;
899       cur_member->nb_dims = nb_dims;
900     }
901     if (get_TOKEN(buf) != TOKEN_SEMICOLON)
902       return FALSE;
903
904     idx_member++;
905   }
906
907   buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].nb_members = idx_member;
908
909   return TRUE;
910 }
911
912 static BOOL parse_template_parts(parse_buffer * buf)
913 {
914   if (!parse_template_members_list(buf))
915     return FALSE;
916   if (check_TOKEN(buf) == TOKEN_OBRACKET)
917   {
918     get_TOKEN(buf);
919     if (!parse_template_option_info(buf))
920       return FALSE;
921     if (get_TOKEN(buf) != TOKEN_CBRACKET)
922      return FALSE;
923   }
924
925   return TRUE;
926 }
927
928 static void go_to_next_definition(parse_buffer * buf)
929 {
930   char c;
931   while (buf->rem_bytes)
932   {
933     read_bytes(buf, &c, 1);
934     if ((c == '#') || (c == '/'))
935     {
936       /* Handle comment (# or //) */
937       if (c == '/')
938       {
939         if (!read_bytes(buf, &c, 1))
940           return;
941         if (c != '/')
942           return;
943       }
944       c = 0;
945       while (c != 0x0A)
946       {
947         if (!read_bytes(buf, &c, 1))
948           return;
949       }
950       continue;
951     }
952     else if (!is_space(c))
953     {
954       rewind_bytes(buf, 1);
955       break;
956     }
957   }
958 }
959
960 BOOL parse_template(parse_buffer * buf)
961 {
962   if (get_TOKEN(buf) != TOKEN_TEMPLATE)
963     return FALSE;
964   if (get_TOKEN(buf) != TOKEN_NAME)
965     return FALSE;
966   strcpy(buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].name, (char*)buf->value);
967   if (get_TOKEN(buf) != TOKEN_OBRACE)
968     return FALSE;
969   if (get_TOKEN(buf) != TOKEN_GUID)
970     return FALSE;
971   buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].class_id = *(GUID*)buf->value;
972   if (!parse_template_parts(buf))
973     return FALSE;
974   if (get_TOKEN(buf) != TOKEN_CBRACE)
975     return FALSE;
976   if (buf->txt)
977   {
978     /* Go to the next template */
979     go_to_next_definition(buf);
980   }
981
982   TRACE("%d - %s - %s\n", buf->pdxf->nb_xtemplates, buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].name, debugstr_guid(&buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].class_id));
983   buf->pdxf->nb_xtemplates++;
984
985   return TRUE;
986 }
987
988 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional);
989 static BOOL parse_object_members_list(parse_buffer * buf)
990 {
991   DWORD token;
992   int i;
993   xtemplate* pt = buf->pxt[buf->level];
994   DWORD last_dword = 0;
995
996   for (i = 0; i < pt->nb_members; i++)
997   {
998     int k;
999     int nb_elems = 1;
1000
1001     buf->pxo->members[i].name = pt->members[i].name;
1002     buf->pxo->members[i].start = buf->cur_pdata;
1003
1004     for (k = 0; k < pt->members[i].nb_dims; k++)
1005     {
1006       if (pt->members[i].dim_fixed[k])
1007         nb_elems *= pt->members[i].dim_value[k];
1008       else
1009         nb_elems *= *(DWORD*)buf->pxo->members[pt->members[i].dim_value[k]].start;
1010     }
1011
1012     TRACE("Elements to consider: %d\n", nb_elems);
1013
1014     for (k = 0; k < nb_elems; k++)
1015     {
1016       if (buf->txt && k)
1017       {
1018         token = check_TOKEN(buf);
1019         if (token == TOKEN_COMMA)
1020         {
1021           get_TOKEN(buf);
1022         }
1023         else
1024         {
1025           /* Allow comma omission */
1026           if (!((token == TOKEN_FLOAT) || (token == TOKEN_INTEGER)))
1027             return FALSE;
1028         }
1029       }
1030
1031       if (pt->members[i].type == TOKEN_NAME)
1032       {
1033         int j;
1034
1035         TRACE("Found sub-object %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1036         buf->level++;
1037         /* To do template lookup */
1038         for (j = 0; j < buf->pdxf->nb_xtemplates; j++)
1039         {
1040           if (!strcasecmp(buf->pdxf->xtemplates[pt->members[i].idx_template].name, buf->pdxf->xtemplates[j].name))
1041           {
1042             buf->pxt[buf->level] = &buf->pdxf->xtemplates[j];
1043             break;
1044           }
1045         }
1046         if (j == buf->pdxf->nb_xtemplates)
1047         {
1048           ERR("Unknown template %s\n", (char*)buf->value);
1049           buf->level--;
1050           return FALSE;
1051         }
1052         TRACE("Enter %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1053         if (!parse_object_parts(buf, FALSE))
1054         {
1055           buf->level--;
1056           return FALSE;
1057         }
1058         buf->level--;
1059       }
1060       else
1061       {
1062         token = check_TOKEN(buf);
1063         if (token == TOKEN_INTEGER)
1064         {
1065           get_TOKEN(buf);
1066           last_dword = *(DWORD*)buf->value;
1067           TRACE("%s = %d\n", pt->members[i].name, *(DWORD*)buf->value);
1068           /* Assume larger size */
1069           if ((buf->cur_pdata - buf->pdata + 4) > MAX_DATA_SIZE)
1070           {
1071             FIXME("Buffer too small\n");
1072             return FALSE;
1073           }
1074           if (pt->members[i].type == TOKEN_WORD)
1075           {
1076             *(((WORD*)(buf->cur_pdata))) = (WORD)(*(DWORD*)buf->value);
1077             buf->cur_pdata += 2;
1078           }
1079           else if (pt->members[i].type == TOKEN_DWORD)
1080           {
1081             *(((DWORD*)(buf->cur_pdata))) = (DWORD)(*(DWORD*)buf->value);
1082             buf->cur_pdata += 4;
1083           }
1084           else
1085           {
1086             FIXME("Token %d not supported\n", pt->members[i].type);
1087             return FALSE;
1088           }
1089         }
1090         else if (token == TOKEN_FLOAT)
1091         {
1092           get_TOKEN(buf);
1093           TRACE("%s = %f\n", pt->members[i].name, *(float*)buf->value);
1094           /* Assume larger size */
1095           if ((buf->cur_pdata - buf->pdata + 4) > MAX_DATA_SIZE)
1096           {
1097             FIXME("Buffer too small\n");
1098             return FALSE;
1099           }
1100           if (pt->members[i].type == TOKEN_FLOAT)
1101           {
1102             *(((float*)(buf->cur_pdata))) = (float)(*(float*)buf->value);
1103             buf->cur_pdata += 4;
1104           }
1105           else
1106           {
1107             FIXME("Token %d not supported\n", pt->members[i].type);
1108             return FALSE;
1109           }
1110         }
1111         else if (token == TOKEN_LPSTR)
1112         {
1113           get_TOKEN(buf);
1114           TRACE("%s = %s\n", pt->members[i].name, (char*)buf->value);
1115           /* Assume larger size */
1116           if ((buf->cur_pdata - buf->pdata + 4) > MAX_DATA_SIZE)
1117           {
1118             FIXME("Buffer too small\n");
1119             return FALSE;
1120           }
1121           if (pt->members[i].type == TOKEN_LPSTR)
1122           {
1123             int len = strlen((char*)buf->value) + 1;
1124             if ((buf->cur_pstrings - buf->pstrings + len) > MAX_STRINGS_BUFFER)
1125             {
1126               FIXME("Buffer too small %p %p %d\n", buf->cur_pstrings, buf->pstrings, len);
1127               return FALSE;
1128             }
1129             strcpy((char*)buf->cur_pstrings, (char*)buf->value);
1130             *(((LPCSTR*)(buf->cur_pdata))) = (char*)buf->cur_pstrings;
1131             buf->cur_pstrings += len;
1132             buf->cur_pdata += 4;
1133           }
1134           else
1135           {
1136             FIXME("Token %d not supported\n", pt->members[i].type);
1137             return FALSE;
1138           }
1139         }
1140         else
1141         {
1142           FIXME("Unexpected token %d\n", token);
1143           return FALSE;
1144         }
1145       }
1146     }
1147
1148     if (buf->txt && (check_TOKEN(buf) != TOKEN_CBRACE))
1149     {
1150       token = get_TOKEN(buf);
1151       if ((token != TOKEN_SEMICOLON) && (token != TOKEN_COMMA))
1152       {
1153         /* Allow comma instead of semicolon in some specific cases */
1154         if (!((token == TOKEN_COMMA) && ((i+1) < pt->nb_members) && (pt->members[i].type == pt->members[i+1].type)
1155           && (!pt->members[i].nb_dims) && (!pt->members[i+1].nb_dims)))
1156           return FALSE;
1157       }
1158     }
1159   }
1160
1161   return TRUE;
1162 }
1163
1164 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional)
1165 {
1166   if (!parse_object_members_list(buf))
1167     return FALSE;
1168
1169   if (allow_optional)
1170   {
1171     buf->pxo->size = buf->cur_pdata - buf->pxo->pdata;
1172
1173     /* Skip trailing semicolon */
1174     while (check_TOKEN(buf) == TOKEN_SEMICOLON)
1175       get_TOKEN(buf);
1176
1177     while (1)
1178     {
1179       if (check_TOKEN(buf) == TOKEN_OBRACE)
1180       {
1181         int i, j;
1182         get_TOKEN(buf);
1183         if (get_TOKEN(buf) != TOKEN_NAME)
1184           return FALSE;
1185         if (get_TOKEN(buf) != TOKEN_CBRACE)
1186           return FALSE;
1187         TRACE("Found optional reference %s\n", (char*)buf->value);
1188         for (i = 0; i < buf->nb_pxo_globals; i++)
1189         {
1190           for (j = 0; j < (buf->pxo_globals[i])[0].nb_subobjects; j++)
1191           {
1192             if (!strcmp((buf->pxo_globals[i])[j].name, (char*)buf->value))
1193               goto _exit;
1194           }
1195         }
1196 _exit:
1197         if (i == buf->nb_pxo_globals)
1198         {
1199           ERR("Reference to unknown object %s\n", (char*)buf->value);
1200           return FALSE;
1201         }
1202         buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->cur_subobject++];
1203         buf->pxo->childs[buf->pxo->nb_childs]->ptarget = &(buf->pxo_globals[i])[j];
1204         buf->pxo->nb_childs++;
1205       }
1206       else if (check_TOKEN(buf) == TOKEN_NAME)
1207       {
1208         xobject* pxo = buf->pxo;
1209         buf->pxo = buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->cur_subobject++];
1210
1211         TRACE("Enter optional %s\n", (char*)buf->value);
1212         buf->level++;
1213         if (!parse_object(buf))
1214         {
1215           buf->level--;
1216           return FALSE;
1217         }
1218         buf->level--;
1219         buf->pxo = pxo;
1220         buf->pxo->nb_childs++;
1221       }
1222       else
1223         break;
1224     }
1225   }
1226
1227   if (buf->pxo->nb_childs > MAX_CHILDS)
1228   {
1229     FIXME("Too many childs %d\n", buf->pxo->nb_childs);
1230     return FALSE;
1231   }
1232
1233   return TRUE;
1234 }
1235
1236 BOOL parse_object(parse_buffer * buf)
1237 {
1238   int i;
1239
1240   buf->pxo->pdata = buf->cur_pdata;
1241   buf->pxo->ptarget = NULL;
1242
1243   if (get_TOKEN(buf) != TOKEN_NAME)
1244     return FALSE;
1245
1246   /* To do template lookup */
1247   for (i = 0; i < buf->pdxf->nb_xtemplates; i++)
1248   {
1249     if (!strcasecmp((char*)buf->value, buf->pdxf->xtemplates[i].name))
1250     {
1251       buf->pxt[buf->level] = &buf->pdxf->xtemplates[i];
1252       memcpy(&buf->pxo->type, &buf->pdxf->xtemplates[i].class_id, 16);
1253       break;
1254     }
1255   }
1256   if (i == buf->pdxf->nb_xtemplates)
1257   {
1258     ERR("Unknown template %s\n", (char*)buf->value);
1259     return FALSE;
1260   }
1261
1262   if (check_TOKEN(buf) == TOKEN_NAME)
1263   {
1264     get_TOKEN(buf);
1265     strcpy(buf->pxo->name, (char*)buf->value);
1266   }
1267   else
1268     buf->pxo->name[0] = 0;
1269
1270   if (get_TOKEN(buf) != TOKEN_OBRACE)
1271     return FALSE;
1272   if (check_TOKEN(buf) == TOKEN_GUID)
1273   {
1274     get_TOKEN(buf);
1275     memcpy(&buf->pxo->class_id, buf->value, 16);
1276   }
1277   else
1278     memset(&buf->pxo->class_id, 0, 16);
1279
1280   if (!parse_object_parts(buf, TRUE))
1281     return FALSE;
1282   if (get_TOKEN(buf) != TOKEN_CBRACE)
1283     return FALSE;
1284
1285   if (buf->txt)
1286   {
1287     /* Go to the next object */
1288     go_to_next_definition(buf);
1289   }
1290
1291   return TRUE;
1292 }