d3dxof: Fix data buffer deallocation on error.
[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_parsing);
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[8]; /* longest keyword size (template) */
277   DWORD len = strlen(keyword);
278
279   if (!read_bytes(buf, tmp, len))
280     return FALSE;
281   if (strncasecmp(tmp, keyword, len))
282   {
283     rewind_bytes(buf, len);
284     return FALSE;
285   }
286
287   if (!read_bytes(buf, tmp, 1))
288     return TRUE;
289   if (is_separator(tmp[0]))
290   {
291     rewind_bytes(buf, 1);
292     return TRUE;
293   }
294   rewind_bytes(buf, len+1);
295   return FALSE;
296 }
297
298 static WORD get_keyword_token(parse_buffer* buf)
299 {
300   if (is_keyword(buf, "template"))
301     return TOKEN_TEMPLATE;
302   if (is_keyword(buf, "WORD"))
303     return TOKEN_WORD;
304   if (is_keyword(buf, "DWORD"))
305     return TOKEN_DWORD;
306   if (is_keyword(buf, "FLOAT"))
307     return TOKEN_FLOAT;
308   if (is_keyword(buf, "DOUBLE"))
309     return TOKEN_DOUBLE;
310   if (is_keyword(buf, "CHAR"))
311     return TOKEN_CHAR;
312   if (is_keyword(buf, "UCHAR"))
313     return TOKEN_UCHAR;
314   if (is_keyword(buf, "SWORD"))
315     return TOKEN_SWORD;
316   if (is_keyword(buf, "SDWORD"))
317     return TOKEN_SDWORD;
318   if (is_keyword(buf, "VOID"))
319     return TOKEN_VOID;
320   if (is_keyword(buf, "STRING"))
321     return TOKEN_LPSTR;
322   if (is_keyword(buf, "UNICODE"))
323     return TOKEN_UNICODE;
324   if (is_keyword(buf, "CSTRING"))
325     return TOKEN_CSTRING;
326   if (is_keyword(buf, "array"))
327     return TOKEN_ARRAY;
328
329   return 0;
330 }
331
332 static BOOL is_guid(parse_buffer* buf)
333 {
334   char tmp[50];
335   DWORD pos = 1;
336   GUID class_id;
337   DWORD tab[10];
338   int ret;
339
340   if (*buf->buffer != '<')
341     return FALSE;
342   tmp[0] = '<';
343   while (*(buf->buffer+pos) != '>')
344   {
345     tmp[pos] = *(buf->buffer+pos);
346     pos++;
347   }
348   tmp[pos++] = '>';
349   tmp[pos] = 0;
350   if (pos != 38 /* <+36+> */)
351   {
352     TRACE("Wrong guid %s (%d)\n", tmp, pos);
353     return FALSE;
354   }
355   buf->buffer += pos;
356   buf->rem_bytes -= pos;
357
358   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);
359   if (ret != 11)
360   {
361     TRACE("Wrong guid %s (%d)\n", tmp, pos);
362     return FALSE;
363   }
364   TRACE("Found guid %s (%d)\n", tmp, pos);
365
366   class_id.Data2 = tab[0];
367   class_id.Data3 = tab[1];
368   class_id.Data4[0] = tab[2];
369   class_id.Data4[1] = tab[3];
370   class_id.Data4[2] = tab[4];
371   class_id.Data4[3] = tab[5];
372   class_id.Data4[4] = tab[6];
373   class_id.Data4[5] = tab[7];
374   class_id.Data4[6] = tab[8];
375   class_id.Data4[7] = tab[9];
376
377   *(GUID*)buf->value = class_id;
378
379   return TRUE;
380 }
381
382 static BOOL is_name(parse_buffer* buf)
383 {
384   char tmp[50];
385   DWORD pos = 0;
386   char c;
387   BOOL error = 0;
388   while (!is_separator(c = *(buf->buffer+pos)))
389   {
390     if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '_') || (c == '-')))
391       error = 1;
392     tmp[pos++] = c;
393   }
394   tmp[pos] = 0;
395
396   if (error)
397   {
398     TRACE("Wrong name %s\n", tmp);
399     return FALSE;
400   }
401
402   buf->buffer += pos;
403   buf->rem_bytes -= pos;
404
405   TRACE("Found name %s\n", tmp);
406   strcpy((char*)buf->value, tmp);
407
408   return TRUE;
409 }
410
411 static BOOL is_float(parse_buffer* buf)
412 {
413   char tmp[50];
414   DWORD pos = 0;
415   char c;
416   float decimal;
417   BOOL dot = 0;
418
419   while (!is_separator(c = *(buf->buffer+pos)))
420   {
421     if (!((!pos && (c == '-')) || ((c >= '0') && (c <= '9')) || (!dot && (c == '.'))))
422       return FALSE;
423     if (c == '.')
424       dot = TRUE;
425     tmp[pos++] = c;
426   }
427   tmp[pos] = 0;
428
429   buf->buffer += pos;
430   buf->rem_bytes -= pos;
431
432   sscanf(tmp, "%f", &decimal);
433
434   TRACE("Found float %s - %f\n", tmp, decimal);
435
436   *(float*)buf->value = decimal;
437
438   return TRUE;
439 }
440
441 static BOOL is_integer(parse_buffer* buf)
442 {
443   char tmp[50];
444   DWORD pos = 0;
445   char c;
446   DWORD integer;
447
448   while (!is_separator(c = *(buf->buffer+pos)))
449   {
450     if (!((c >= '0') && (c <= '9')))
451       return FALSE;
452     tmp[pos++] = c;
453   }
454   tmp[pos] = 0;
455
456   buf->buffer += pos;
457   buf->rem_bytes -= pos;
458
459   sscanf(tmp, "%d", &integer);
460
461   TRACE("Found integer %s - %d\n", tmp, integer);
462
463   *(DWORD*)buf->value = integer;
464
465   return TRUE;
466 }
467
468 static BOOL is_string(parse_buffer* buf)
469 {
470   char tmp[100];
471   DWORD pos = 0;
472   char c;
473   BOOL ok = 0;
474
475   if (*buf->buffer != '"')
476     return FALSE;
477
478   while (!is_separator(c = *(buf->buffer+pos+1)) && (pos < 99))
479   {
480     if (c == '"')
481     {
482       ok = 1;
483       break;
484     }
485     tmp[pos++] = c;
486   }
487   tmp[pos] = 0;
488
489   if (!ok)
490   {
491     TRACE("Wrong string %s\n", tmp);
492     return FALSE;
493   }
494
495   buf->buffer += pos + 2;
496   buf->rem_bytes -= pos + 2;
497
498   TRACE("Found string %s\n", tmp);
499   strcpy((char*)buf->value, tmp);
500
501   return TRUE;
502 }
503
504 static WORD parse_TOKEN(parse_buffer * buf)
505 {
506   WORD token;
507
508   if (buf->txt)
509   {
510     while(1)
511     {
512       char c;
513       if (!read_bytes(buf, &c, 1))
514         return 0;
515       /*TRACE("char = '%c'\n", is_space(c) ? ' ' : c);*/
516       if ((c == '#') || (c == '/'))
517       {
518         /* Handle comment (# or //) */
519         if (c == '/')
520         {
521           if (!read_bytes(buf, &c, 1))
522             return 0;
523           if (c != '/')
524             return 0;
525         }
526         c = 0;
527         while (c != 0x0A)
528         {
529           if (!read_bytes(buf, &c, 1))
530             return 0;
531         }
532         continue;
533       }
534       if (is_space(c))
535         continue;
536       if (is_operator(c) && (c != '<'))
537       {
538         token = get_operator_token(c);
539         break;
540       }
541       else if (c == '.')
542       {
543         token = TOKEN_DOT;
544         break;
545       }
546       else
547       {
548         rewind_bytes(buf, 1);
549
550         if ((token = get_keyword_token(buf)))
551           break;
552
553         if (is_guid(buf))
554         {
555           token = TOKEN_GUID;
556           break;
557         }
558         if (is_integer(buf))
559         {
560           token = TOKEN_INTEGER;
561           break;
562         }
563         if (is_float(buf))
564         {
565           token = TOKEN_FLOAT;
566           break;
567         }
568         if (is_string(buf))
569         {
570           token = TOKEN_LPSTR;
571           break;
572         }
573         if (is_name(buf))
574         {
575           token = TOKEN_NAME;
576           break;
577         }
578
579         FIXME("Unrecognize element\n");
580         return 0;
581       }
582     }
583   }
584   else
585   {
586     static int nb_elem;
587     static int is_float;
588
589     if (!nb_elem)
590     {
591       if (!read_bytes(buf, &token, 2))
592         return 0;
593
594       /* Convert integer and float list into separate elements */
595       if (token == TOKEN_INTEGER_LIST)
596       {
597         if (!read_bytes(buf, &nb_elem, 4))
598           return 0;
599         token = TOKEN_INTEGER;
600         is_float = FALSE;
601         TRACE("Integer list (TOKEN_INTEGER_LIST) of size %d\n", nb_elem);
602       }
603       else if (token == TOKEN_FLOAT_LIST)
604       {
605         if (!read_bytes(buf, &nb_elem, 4))
606           return 0;
607         token = TOKEN_FLOAT;
608         is_float = TRUE;
609         TRACE("Float list (TOKEN_FLOAT_LIST) of size %d\n", nb_elem);
610       }
611     }
612
613     if (nb_elem)
614     {
615       token = is_float ? TOKEN_FLOAT : TOKEN_INTEGER;
616       nb_elem--;
617         {
618           DWORD integer;
619
620           if (!read_bytes(buf, &integer, 4))
621             return 0;
622
623           *(DWORD*)buf->value = integer;
624         }
625       dump_TOKEN(token);
626       return token;
627     }
628
629     switch (token)
630     {
631       case TOKEN_NAME:
632         {
633           DWORD count;
634           char strname[100];
635
636           if (!read_bytes(buf, &count, 4))
637             return 0;
638           if (!read_bytes(buf, strname, count))
639             return 0;
640           strname[count] = 0;
641           /*TRACE("name = %s\n", strname);*/
642
643           strcpy((char*)buf->value, strname);
644         }
645         break;
646       case TOKEN_INTEGER:
647         {
648           DWORD integer;
649
650           if (!read_bytes(buf, &integer, 4))
651             return 0;
652           /*TRACE("integer = %ld\n", integer);*/
653
654           *(DWORD*)buf->value = integer;
655         }
656         break;
657       case TOKEN_GUID:
658         {
659           char strguid[39];
660           GUID class_id;
661
662           if (!read_bytes(buf, &class_id, 16))
663             return 0;
664           sprintf(strguid, CLSIDFMT, class_id.Data1, class_id.Data2, class_id.Data3, class_id.Data4[0],
665             class_id.Data4[1], class_id.Data4[2], class_id.Data4[3], class_id.Data4[4], class_id.Data4[5],
666             class_id.Data4[6], class_id.Data4[7]);
667           /*TRACE("guid = {%s}\n", strguid);*/
668
669           *(GUID*)buf->value = class_id;
670         }
671         break;
672       case TOKEN_STRING:
673         {
674           DWORD count;
675           WORD tmp_token;
676           char strname[100];
677           if (!read_bytes(buf, &count, 4))
678             return 0;
679           if (!read_bytes(buf, strname, count))
680             return 0;
681           strname[count] = 0;
682           if (!read_bytes(buf, &tmp_token, 2))
683             return 0;
684           if ((tmp_token != TOKEN_COMMA) && (tmp_token != TOKEN_SEMICOLON))
685             ERR("No comma or semicolon (got %d)\n", tmp_token);
686           /*TRACE("name = %s\n", strname);*/
687
688           strcpy((char*)buf->value, strname);
689           token = TOKEN_LPSTR;
690         }
691         break;
692       case TOKEN_OBRACE:
693       case TOKEN_CBRACE:
694       case TOKEN_OPAREN:
695       case TOKEN_CPAREN:
696       case TOKEN_OBRACKET:
697       case TOKEN_CBRACKET:
698       case TOKEN_OANGLE:
699       case TOKEN_CANGLE:
700       case TOKEN_DOT:
701       case TOKEN_COMMA:
702       case TOKEN_SEMICOLON:
703       case TOKEN_TEMPLATE:
704       case TOKEN_WORD:
705       case TOKEN_DWORD:
706       case TOKEN_FLOAT:
707       case TOKEN_DOUBLE:
708       case TOKEN_CHAR:
709       case TOKEN_UCHAR:
710       case TOKEN_SWORD:
711       case TOKEN_SDWORD:
712       case TOKEN_VOID:
713       case TOKEN_LPSTR:
714       case TOKEN_UNICODE:
715       case TOKEN_CSTRING:
716       case TOKEN_ARRAY:
717         break;
718       default:
719         return 0;
720     }
721   }
722
723   dump_TOKEN(token);
724
725   return token;
726 }
727
728 static WORD get_TOKEN(parse_buffer * buf)
729 {
730   if (buf->token_present)
731   {
732     buf->token_present = FALSE;
733     return buf->current_token;
734   }
735
736   buf->current_token = parse_TOKEN(buf);
737
738   return buf->current_token;
739 }
740
741 static WORD check_TOKEN(parse_buffer * buf)
742 {
743   if (buf->token_present)
744     return buf->current_token;
745
746   buf->current_token = parse_TOKEN(buf);
747   buf->token_present = TRUE;
748
749   return buf->current_token;
750 }
751
752 BOOL is_template_available(parse_buffer * buf)
753 {
754   return check_TOKEN(buf) == TOKEN_TEMPLATE;
755 }
756
757 static inline BOOL is_primitive_type(WORD token)
758 {
759   BOOL ret;
760   switch(token)
761   {
762     case TOKEN_WORD:
763     case TOKEN_DWORD:
764     case TOKEN_FLOAT:
765     case TOKEN_DOUBLE:
766     case TOKEN_CHAR:
767     case TOKEN_UCHAR:
768     case TOKEN_SWORD:
769     case TOKEN_SDWORD:
770     case TOKEN_LPSTR:
771     case TOKEN_UNICODE:
772     case TOKEN_CSTRING:
773       ret = 1;
774       break;
775     default:
776       ret = 0;
777       break;
778   }
779   return ret;
780 }
781
782 static BOOL parse_template_option_info(parse_buffer * buf)
783 {
784   xtemplate* cur_template = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates];
785
786   if (check_TOKEN(buf) == TOKEN_DOT)
787   {
788     get_TOKEN(buf);
789     if (get_TOKEN(buf) != TOKEN_DOT)
790       return FALSE;
791     if (get_TOKEN(buf) != TOKEN_DOT)
792       return FALSE;
793     cur_template->open = TRUE;
794   }
795   else
796   {
797     while (1)
798     {
799       if (get_TOKEN(buf) != TOKEN_NAME)
800         return FALSE;
801       strcpy(cur_template->childs[cur_template->nb_childs], (char*)buf->value);
802       if (check_TOKEN(buf) == TOKEN_GUID)
803         get_TOKEN(buf);
804       cur_template->nb_childs++;
805       if (check_TOKEN(buf) != TOKEN_COMMA)
806         break;
807       get_TOKEN(buf);
808     }
809     cur_template->open = FALSE;
810   }
811
812   return TRUE;
813 }
814
815 static BOOL parse_template_members_list(parse_buffer * buf)
816 {
817   int idx_member = 0;
818   member* cur_member;
819
820   while (1)
821   {
822     BOOL array = 0;
823     int nb_dims = 0;
824     cur_member = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[idx_member];
825
826     if (check_TOKEN(buf) == TOKEN_ARRAY)
827     {
828       get_TOKEN(buf);
829       array = 1;
830     }
831
832     if (check_TOKEN(buf) == TOKEN_NAME)
833     {
834       cur_member->type = get_TOKEN(buf);
835       cur_member->idx_template = 0;
836       while (cur_member->idx_template < buf->pdxf->nb_xtemplates)
837       {
838         if (!strcasecmp((char*)buf->value, buf->pdxf->xtemplates[cur_member->idx_template].name))
839           break;
840         cur_member->idx_template++;
841       }
842       if (cur_member->idx_template == buf->pdxf->nb_xtemplates)
843       {
844         ERR("Reference to a nonexistent template '%s'\n", (char*)buf->value);
845         return FALSE;
846       }
847     }
848     else if (is_primitive_type(check_TOKEN(buf)))
849       cur_member->type = get_TOKEN(buf);
850     else
851       break;
852
853     if (get_TOKEN(buf) != TOKEN_NAME)
854       return FALSE;
855     strcpy(cur_member->name, (char*)buf->value);
856
857     if (array)
858     {
859       while (check_TOKEN(buf) == TOKEN_OBRACKET)
860       {
861         if (nb_dims >= MAX_ARRAY_DIM)
862         {
863           FIXME("Too many dimensions (%d) for multi-dimensional array\n", nb_dims + 1);
864           return FALSE;
865         }
866         get_TOKEN(buf);
867         if (check_TOKEN(buf) == TOKEN_INTEGER)
868         {
869           get_TOKEN(buf);
870           cur_member->dim_fixed[nb_dims] = TRUE;
871           cur_member->dim_value[nb_dims] = *(DWORD*)buf->value;
872         }
873         else
874         {
875           int i;
876           if (get_TOKEN(buf) != TOKEN_NAME)
877             return FALSE;
878           for (i = 0; i < idx_member; i++)
879           {
880             if (!strcmp((char*)buf->value, buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].name))
881             {
882               if (buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].nb_dims)
883               {
884                 ERR("Array cannot be used to specify variable array size\n");
885                 return FALSE;
886               }
887               if (buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].type != TOKEN_DWORD)
888               {
889                 FIXME("Only DWORD supported to specify variable array size\n");
890                 return FALSE;
891               }
892               break;
893             }
894           }
895           if (i == idx_member)
896           {
897             ERR("Reference to unknown member %s\n", (char*)buf->value);
898             return FALSE;
899           }
900           cur_member->dim_fixed[nb_dims] = FALSE;
901           cur_member->dim_value[nb_dims] = i;
902         }
903         if (get_TOKEN(buf) != TOKEN_CBRACKET)
904           return FALSE;
905         nb_dims++;
906       }
907       if (!nb_dims)
908         return FALSE;
909       cur_member->nb_dims = nb_dims;
910     }
911     if (get_TOKEN(buf) != TOKEN_SEMICOLON)
912       return FALSE;
913
914     idx_member++;
915   }
916
917   buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].nb_members = idx_member;
918
919   return TRUE;
920 }
921
922 static BOOL parse_template_parts(parse_buffer * buf)
923 {
924   if (!parse_template_members_list(buf))
925     return FALSE;
926   if (check_TOKEN(buf) == TOKEN_OBRACKET)
927   {
928     get_TOKEN(buf);
929     if (!parse_template_option_info(buf))
930       return FALSE;
931     if (get_TOKEN(buf) != TOKEN_CBRACKET)
932      return FALSE;
933   }
934
935   return TRUE;
936 }
937
938 static void go_to_next_definition(parse_buffer * buf)
939 {
940   char c;
941   while (buf->rem_bytes)
942   {
943     read_bytes(buf, &c, 1);
944     if ((c == '#') || (c == '/'))
945     {
946       /* Handle comment (# or //) */
947       if (c == '/')
948       {
949         if (!read_bytes(buf, &c, 1))
950           return;
951         if (c != '/')
952           return;
953       }
954       c = 0;
955       while (c != 0x0A)
956       {
957         if (!read_bytes(buf, &c, 1))
958           return;
959       }
960       continue;
961     }
962     else if (!is_space(c))
963     {
964       rewind_bytes(buf, 1);
965       break;
966     }
967   }
968 }
969
970 BOOL parse_template(parse_buffer * buf)
971 {
972   if (get_TOKEN(buf) != TOKEN_TEMPLATE)
973     return FALSE;
974   if (get_TOKEN(buf) != TOKEN_NAME)
975     return FALSE;
976   strcpy(buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].name, (char*)buf->value);
977   if (get_TOKEN(buf) != TOKEN_OBRACE)
978     return FALSE;
979   if (get_TOKEN(buf) != TOKEN_GUID)
980     return FALSE;
981   buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].class_id = *(GUID*)buf->value;
982   if (!parse_template_parts(buf))
983     return FALSE;
984   if (get_TOKEN(buf) != TOKEN_CBRACE)
985     return FALSE;
986   if (buf->txt)
987   {
988     /* Go to the next template */
989     go_to_next_definition(buf);
990   }
991
992   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));
993   buf->pdxf->nb_xtemplates++;
994
995   return TRUE;
996 }
997
998 static BOOL check_buffer(parse_buffer * buf, ULONG size)
999 {
1000   if ((buf->cur_pos_data + size) > buf->capacity)
1001   {
1002     LPBYTE pdata;
1003     ULONG new_capacity = buf->capacity ? 2 * buf->capacity : 100000;
1004
1005     pdata = HeapAlloc(GetProcessHeap(), 0, new_capacity);
1006     if (!pdata)
1007       return FALSE;
1008     memcpy(pdata, buf->pdata, buf->cur_pos_data);
1009     HeapFree(GetProcessHeap(), 0, buf->pdata);
1010     buf->capacity = new_capacity;
1011     buf->pdata = pdata;
1012     buf->pxo->root->pdata = pdata;
1013   }
1014   return TRUE;
1015 }
1016
1017 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional);
1018 static BOOL parse_object_members_list(parse_buffer * buf)
1019 {
1020   DWORD token;
1021   int i;
1022   xtemplate* pt = buf->pxt[buf->level];
1023
1024   for (i = 0; i < pt->nb_members; i++)
1025   {
1026     int k;
1027     int nb_elems = 1;
1028
1029     buf->pxo->members[i].name = pt->members[i].name;
1030     buf->pxo->members[i].start = buf->cur_pos_data;
1031
1032     for (k = 0; k < pt->members[i].nb_dims; k++)
1033     {
1034       if (pt->members[i].dim_fixed[k])
1035         nb_elems *= pt->members[i].dim_value[k];
1036       else
1037         nb_elems *= *(DWORD*)(buf->pxo->root->pdata + buf->pxo->members[pt->members[i].dim_value[k]].start);
1038     }
1039
1040     TRACE("Elements to consider: %d\n", nb_elems);
1041
1042     for (k = 0; k < nb_elems; k++)
1043     {
1044       if (buf->txt && k)
1045       {
1046         token = check_TOKEN(buf);
1047         if (token == TOKEN_COMMA)
1048         {
1049           get_TOKEN(buf);
1050         }
1051         else
1052         {
1053           /* Allow comma omission */
1054           if (!((token == TOKEN_FLOAT) || (token == TOKEN_INTEGER)))
1055             return FALSE;
1056         }
1057       }
1058
1059       if (pt->members[i].type == TOKEN_NAME)
1060       {
1061         int j;
1062
1063         TRACE("Found sub-object %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1064         buf->level++;
1065         /* To do template lookup */
1066         for (j = 0; j < buf->pdxf->nb_xtemplates; j++)
1067         {
1068           if (!strcasecmp(buf->pdxf->xtemplates[pt->members[i].idx_template].name, buf->pdxf->xtemplates[j].name))
1069           {
1070             buf->pxt[buf->level] = &buf->pdxf->xtemplates[j];
1071             break;
1072           }
1073         }
1074         if (j == buf->pdxf->nb_xtemplates)
1075         {
1076           ERR("Unknown template %s\n", (char*)buf->value);
1077           buf->level--;
1078           return FALSE;
1079         }
1080         TRACE("Enter %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1081         if (!parse_object_parts(buf, FALSE))
1082         {
1083           buf->level--;
1084           return FALSE;
1085         }
1086         buf->level--;
1087       }
1088       else
1089       {
1090         token = check_TOKEN(buf);
1091         if (token == TOKEN_INTEGER)
1092         {
1093           get_TOKEN(buf);
1094           TRACE("%s = %d\n", pt->members[i].name, *(DWORD*)buf->value);
1095           /* Assume larger size */
1096           if (!check_buffer(buf, 4))
1097             return FALSE;
1098           if (pt->members[i].type == TOKEN_WORD)
1099           {
1100             *(((WORD*)(buf->cur_pos_data + buf->pdata))) = (WORD)(*(DWORD*)buf->value);
1101             buf->cur_pos_data += 2;
1102           }
1103           else if (pt->members[i].type == TOKEN_DWORD)
1104           {
1105             *(((DWORD*)(buf->cur_pos_data + buf->pdata))) = (DWORD)(*(DWORD*)buf->value);
1106             buf->cur_pos_data += 4;
1107           }
1108           else
1109           {
1110             FIXME("Token %d not supported\n", pt->members[i].type);
1111             return FALSE;
1112           }
1113         }
1114         else if (token == TOKEN_FLOAT)
1115         {
1116           get_TOKEN(buf);
1117           TRACE("%s = %f\n", pt->members[i].name, *(float*)buf->value);
1118           if (!check_buffer(buf, 4))
1119             return FALSE;
1120           if (pt->members[i].type == TOKEN_FLOAT)
1121           {
1122             *(((float*)(buf->cur_pos_data + buf->pdata))) = (float)(*(float*)buf->value);
1123             buf->cur_pos_data += 4;
1124           }
1125           else
1126           {
1127             FIXME("Token %d not supported\n", pt->members[i].type);
1128             return FALSE;
1129           }
1130         }
1131         else if (token == TOKEN_LPSTR)
1132         {
1133           get_TOKEN(buf);
1134           TRACE("%s = %s\n", pt->members[i].name, (char*)buf->value);
1135           if (!check_buffer(buf, 4))
1136             return FALSE;
1137           if (pt->members[i].type == TOKEN_LPSTR)
1138           {
1139             int len = strlen((char*)buf->value) + 1;
1140             if ((buf->cur_pstrings - buf->pstrings + len) > MAX_STRINGS_BUFFER)
1141             {
1142               FIXME("Buffer too small %p %p %d\n", buf->cur_pstrings, buf->pstrings, len);
1143               return FALSE;
1144             }
1145             strcpy((char*)buf->cur_pstrings, (char*)buf->value);
1146             *(((LPCSTR*)(buf->cur_pos_data + buf->pdata))) = (char*)buf->cur_pstrings;
1147             buf->cur_pstrings += len;
1148             buf->cur_pos_data += 4;
1149           }
1150           else
1151           {
1152             FIXME("Token %d not supported\n", pt->members[i].type);
1153             return FALSE;
1154           }
1155         }
1156         else
1157         {
1158           FIXME("Unexpected token %d\n", token);
1159           return FALSE;
1160         }
1161       }
1162     }
1163
1164     if (nb_elems && buf->txt && (check_TOKEN(buf) != TOKEN_CBRACE))
1165     {
1166       token = get_TOKEN(buf);
1167       if ((token != TOKEN_SEMICOLON) && (token != TOKEN_COMMA))
1168         return FALSE;
1169     }
1170   }
1171
1172   return TRUE;
1173 }
1174
1175 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional)
1176 {
1177   buf->pxo->nb_childs = 0;
1178
1179   if (!parse_object_members_list(buf))
1180     return FALSE;
1181
1182   if (allow_optional)
1183   {
1184     buf->pxo->size = buf->cur_pos_data - buf->pxo->pos_data;
1185
1186     /* Skip trailing semicolon */
1187     while (check_TOKEN(buf) == TOKEN_SEMICOLON)
1188       get_TOKEN(buf);
1189
1190     while (1)
1191     {
1192       if (check_TOKEN(buf) == TOKEN_OBRACE)
1193       {
1194         int i, j;
1195         get_TOKEN(buf);
1196         if (get_TOKEN(buf) != TOKEN_NAME)
1197           return FALSE;
1198         if (get_TOKEN(buf) != TOKEN_CBRACE)
1199           return FALSE;
1200         TRACE("Found optional reference %s\n", (char*)buf->value);
1201         for (i = 0; i < (buf->nb_pxo_globals+1); i++)
1202         {
1203           for (j = 0; j < (buf->pxo_globals[i])[0].nb_subobjects; j++)
1204           {
1205             if (!strcmp((buf->pxo_globals[i])[j].name, (char*)buf->value))
1206               goto _exit;
1207           }
1208         }
1209 _exit:
1210         if (i == (buf->nb_pxo_globals+1))
1211         {
1212           ERR("Reference to unknown object %s\n", (char*)buf->value);
1213           return FALSE;
1214         }
1215         buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->pxo->root->nb_subobjects++];
1216         buf->pxo->childs[buf->pxo->nb_childs]->ptarget = &(buf->pxo_globals[i])[j];
1217         buf->pxo->nb_childs++;
1218       }
1219       else if (check_TOKEN(buf) == TOKEN_NAME)
1220       {
1221         xobject* pxo = buf->pxo;
1222         buf->pxo = buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->pxo->root->nb_subobjects++];
1223
1224         TRACE("Enter optional %s\n", (char*)buf->value);
1225         buf->level++;
1226         if (!parse_object(buf))
1227         {
1228           buf->level--;
1229           return FALSE;
1230         }
1231         buf->level--;
1232         buf->pxo = pxo;
1233         buf->pxo->nb_childs++;
1234       }
1235       else
1236         break;
1237     }
1238   }
1239
1240   if (buf->pxo->nb_childs > MAX_CHILDS)
1241   {
1242     FIXME("Too many childs %d\n", buf->pxo->nb_childs);
1243     return FALSE;
1244   }
1245
1246   return TRUE;
1247 }
1248
1249 BOOL parse_object(parse_buffer * buf)
1250 {
1251   int i;
1252
1253   buf->pxo->pos_data = buf->cur_pos_data;
1254   buf->pxo->ptarget = NULL;
1255   buf->pxo->root = buf->pxo_tab;
1256
1257   if (get_TOKEN(buf) != TOKEN_NAME)
1258     return FALSE;
1259
1260   /* To do template lookup */
1261   for (i = 0; i < buf->pdxf->nb_xtemplates; i++)
1262   {
1263     if (!strcasecmp((char*)buf->value, buf->pdxf->xtemplates[i].name))
1264     {
1265       buf->pxt[buf->level] = &buf->pdxf->xtemplates[i];
1266       memcpy(&buf->pxo->type, &buf->pdxf->xtemplates[i].class_id, 16);
1267       break;
1268     }
1269   }
1270   if (i == buf->pdxf->nb_xtemplates)
1271   {
1272     ERR("Unknown template %s\n", (char*)buf->value);
1273     return FALSE;
1274   }
1275
1276   if (check_TOKEN(buf) == TOKEN_NAME)
1277   {
1278     get_TOKEN(buf);
1279     strcpy(buf->pxo->name, (char*)buf->value);
1280   }
1281   else
1282     buf->pxo->name[0] = 0;
1283
1284   if (get_TOKEN(buf) != TOKEN_OBRACE)
1285     return FALSE;
1286   if (check_TOKEN(buf) == TOKEN_GUID)
1287   {
1288     get_TOKEN(buf);
1289     memcpy(&buf->pxo->class_id, buf->value, 16);
1290   }
1291   else
1292     memset(&buf->pxo->class_id, 0, 16);
1293
1294   if (!parse_object_parts(buf, TRUE))
1295     return FALSE;
1296   if (get_TOKEN(buf) != TOKEN_CBRACE)
1297     return FALSE;
1298
1299   if (buf->txt)
1300   {
1301     /* Go to the next object */
1302     go_to_next_definition(buf);
1303   }
1304
1305   return TRUE;
1306 }