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