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