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