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