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