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