quartz: Sign-compare warnings fix.
[wine] / dlls / d3dxof / d3dxof.c
1 /*
2  * Implementation of DirectX File Interfaces
3  *
4  * Copyright 2004, 2008 Christian Costa
5  *
6  * This file contains the (internal) driver registration functions,
7  * driver enumeration APIs and DirectDraw creation functions.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wine/debug.h"
26
27 #define COBJMACROS
28
29 #include "winbase.h"
30 #include "wingdi.h"
31
32 #include "d3dxof_private.h"
33 #include "dxfile.h"
34
35 #include <stdio.h>
36
37 WINE_DEFAULT_DEBUG_CHANNEL(d3dxof);
38
39 #define MAKEFOUR(a,b,c,d) ((DWORD)a + ((DWORD)b << 8) + ((DWORD)c << 16) + ((DWORD)d << 24))
40 #define XOFFILE_FORMAT_MAGIC         MAKEFOUR('x','o','f',' ')
41 #define XOFFILE_FORMAT_VERSION       MAKEFOUR('0','3','0','2')
42 #define XOFFILE_FORMAT_BINARY        MAKEFOUR('b','i','n',' ')
43 #define XOFFILE_FORMAT_TEXT          MAKEFOUR('t','x','t',' ')
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 #define MAX_INPUT_SIZE 1000000
83 #define MAX_DATA_SIZE 100000
84
85 static const struct IDirectXFileVtbl IDirectXFile_Vtbl;
86 static const struct IDirectXFileBinaryVtbl IDirectXFileBinary_Vtbl;
87 static const struct IDirectXFileDataVtbl IDirectXFileData_Vtbl;
88 static const struct IDirectXFileDataReferenceVtbl IDirectXFileDataReference_Vtbl;
89 static const struct IDirectXFileEnumObjectVtbl IDirectXFileEnumObject_Vtbl;
90 static const struct IDirectXFileObjectVtbl IDirectXFileObject_Vtbl;
91 static const struct IDirectXFileSaveObjectVtbl IDirectXFileSaveObject_Vtbl;
92
93 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional);
94 static BOOL parse_object(parse_buffer * buf);
95 static const char* get_primitive_string(WORD token);
96
97 static void dump_template(xtemplate* templates_array, xtemplate* ptemplate)
98 {
99   int j, k;
100   GUID* clsid;
101
102   clsid = &ptemplate->class_id;
103
104   DPRINTF("template %s\n", ptemplate->name);
105   DPRINTF("{\n");
106   DPRINTF(CLSIDFMT "\n", clsid->Data1, clsid->Data2, clsid->Data3, clsid->Data4[0],
107   clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7]);
108   for (j = 0; j < ptemplate->nb_members; j++)
109   {
110     if (ptemplate->members[j].nb_dims)
111       DPRINTF("array ");
112     if (ptemplate->members[j].type == TOKEN_NAME)
113       DPRINTF("%s ", templates_array[ptemplate->members[j].idx_template].name);
114     else
115       DPRINTF("%s ", get_primitive_string(ptemplate->members[j].type));
116     DPRINTF("%s", ptemplate->members[j].name);
117     for (k = 0; k < ptemplate->members[j].nb_dims; k++)
118     {
119       if (ptemplate->members[j].dim_fixed[k])
120         DPRINTF("[%d]", ptemplate->members[j].dim_value[k]);
121       else
122         DPRINTF("[%s]", ptemplate->members[ptemplate->members[j].dim_value[k]].name);
123     }
124     DPRINTF(";\n");
125   }
126   if (ptemplate->open)
127     DPRINTF("[...]\n");
128   else if (ptemplate->nb_childs)
129   {
130     DPRINTF("[%s", ptemplate->childs[0]);
131     for (j = 1; j < ptemplate->nb_childs; j++)
132       DPRINTF(",%s", ptemplate->childs[j]);
133     DPRINTF("]\n");
134   }
135   DPRINTF("}\n");
136 }
137
138 HRESULT IDirectXFileImpl_Create(IUnknown* pUnkOuter, LPVOID* ppObj)
139 {
140     IDirectXFileImpl* object;
141
142     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
143       
144     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileImpl));
145     
146     object->lpVtbl.lpVtbl = &IDirectXFile_Vtbl;
147     object->ref = 1;
148
149     *ppObj = object;
150     
151     return S_OK;
152 }
153
154 /*** IUnknown methods ***/
155 static HRESULT WINAPI IDirectXFileImpl_QueryInterface(IDirectXFile* iface, REFIID riid, void** ppvObject)
156 {
157   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
158
159   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
160
161   if (IsEqualGUID(riid, &IID_IUnknown)
162       || IsEqualGUID(riid, &IID_IDirectXFile))
163   {
164     IClassFactory_AddRef(iface);
165     *ppvObject = This;
166     return S_OK;
167   }
168
169   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
170   return E_NOINTERFACE;
171 }
172
173 static ULONG WINAPI IDirectXFileImpl_AddRef(IDirectXFile* iface)
174 {
175   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
176   ULONG ref = InterlockedIncrement(&This->ref);
177
178   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
179
180   return ref;
181 }
182
183 static ULONG WINAPI IDirectXFileImpl_Release(IDirectXFile* iface)
184 {
185   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
186   ULONG ref = InterlockedDecrement(&This->ref);
187
188   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
189
190   if (!ref)
191     HeapFree(GetProcessHeap(), 0, This);
192
193   return ref;
194 }
195
196 /*** IDirectXFile methods ***/
197 static HRESULT WINAPI IDirectXFileImpl_CreateEnumObject(IDirectXFile* iface, LPVOID pvSource, DXFILELOADOPTIONS dwLoadOptions, LPDIRECTXFILEENUMOBJECT* ppEnumObj)
198 {
199   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
200   IDirectXFileEnumObjectImpl* object;
201   HRESULT hr;
202   DWORD header[4];
203   DWORD size;
204   HANDLE hFile = INVALID_HANDLE_VALUE;
205
206   TRACE("(%p/%p)->(%p,%x,%p)\n", This, iface, pvSource, dwLoadOptions, ppEnumObj);
207
208   if (!ppEnumObj)
209     return DXFILEERR_BADVALUE;
210
211   if (dwLoadOptions == DXFILELOAD_FROMFILE)
212   {
213     TRACE("Open source file '%s'\n", (char*)pvSource);
214
215     hFile = CreateFileA((char*)pvSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
216     if (hFile == INVALID_HANDLE_VALUE)
217     {
218       TRACE("File '%s' not found\n", (char*)pvSource);
219       return DXFILEERR_FILENOTFOUND;
220     }
221
222     if (!ReadFile(hFile, header, 16, &size, NULL))
223     {
224       hr = DXFILEERR_BADVALUE;
225       goto error;
226     }
227
228     if (size < 16)
229     {
230       hr = DXFILEERR_BADFILETYPE;
231       goto error;
232     }
233
234     if (TRACE_ON(d3dxof))
235     {
236       char string[17];
237       memcpy(string, header, 16);
238       string[16] = 0;
239       TRACE("header = '%s'\n", string);
240     }
241   }
242   else
243   {
244     FIXME("Source type %d is not handled yet\n", dwLoadOptions);
245     hr = DXFILEERR_NOTDONEYET;
246     goto error;
247   }
248
249   if (header[0] != XOFFILE_FORMAT_MAGIC)
250   {
251     hr = DXFILEERR_BADFILETYPE;
252     goto error;
253   }
254
255   if (header[1] != XOFFILE_FORMAT_VERSION)
256   {
257     hr = DXFILEERR_BADFILEVERSION;
258     goto error;
259   }
260
261   if ((header[2] != XOFFILE_FORMAT_BINARY) && (header[2] != XOFFILE_FORMAT_TEXT) && (header[2] != XOFFILE_FORMAT_COMPRESSED))
262   {
263     hr = DXFILEERR_BADFILETYPE;
264     goto error;
265   }
266
267   if (header[2] == XOFFILE_FORMAT_BINARY)
268   {
269     FIXME("Binary format not supported yet\n");
270     hr = DXFILEERR_NOTDONEYET;
271     goto error;
272   }
273
274   if (header[2] == XOFFILE_FORMAT_COMPRESSED)
275   {
276     FIXME("Compressed formats not supported yet\n");
277     hr = DXFILEERR_BADVALUE;
278     goto error;
279   }
280
281   if ((header[3] != XOFFILE_FORMAT_FLOAT_BITS_32) && (header[3] != XOFFILE_FORMAT_FLOAT_BITS_64))
282   {
283     hr = DXFILEERR_BADFILEFLOATSIZE;
284     goto error;
285   }
286
287   TRACE("Header is correct\n");
288
289   hr = IDirectXFileEnumObjectImpl_Create(&object);
290   if (FAILED(hr))
291     goto error;
292
293   object->source = dwLoadOptions;
294   object->hFile = hFile;
295   object->pDirectXFile = This;
296   object->buf.pdxf = This;
297   object->buf.txt = TRUE;
298   object->buf.token_present = FALSE;
299   object->buf.cur_subobject = 0;
300
301   object->buf.buffer = HeapAlloc(GetProcessHeap(), 0, MAX_INPUT_SIZE+1);
302   if (!object->buf.buffer)
303   {
304     WARN("Out of memory\n");
305     hr = DXFILEERR_BADALLOC;
306     goto error;
307   }
308
309   ReadFile(hFile, object->buf.buffer, MAX_INPUT_SIZE+1, &object->buf.rem_bytes, NULL);
310   if (object->buf.rem_bytes > MAX_INPUT_SIZE)
311   {
312     FIXME("File size > %d not supported yet\n", MAX_INPUT_SIZE);
313     HeapFree(GetProcessHeap(), 0, object->buf.buffer);
314     hr = DXFILEERR_PARSEERROR;
315     goto error;
316   }
317   TRACE("Read %d bytes\n", object->buf.rem_bytes);
318
319   *ppEnumObj = (LPDIRECTXFILEENUMOBJECT)object;
320
321   return DXFILE_OK;
322
323 error:
324   if (hFile != INVALID_HANDLE_VALUE)
325     CloseHandle(hFile);
326   *ppEnumObj = NULL;
327
328   return hr;
329 }
330
331 static HRESULT WINAPI IDirectXFileImpl_CreateSaveObject(IDirectXFile* iface, LPCSTR szFileName, DXFILEFORMAT dwFileFormat, LPDIRECTXFILESAVEOBJECT* ppSaveObj)
332 {
333   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
334
335   FIXME("(%p/%p)->(%s,%x,%p) stub!\n", This, iface, szFileName, dwFileFormat, ppSaveObj);
336
337   return DXFILEERR_BADVALUE;
338 }
339
340 static BOOL read_bytes(parse_buffer * buf, LPVOID data, DWORD size)
341 {
342   if (buf->rem_bytes < size)
343     return FALSE;
344   memcpy(data, buf->buffer, size);
345   buf->buffer += size;
346   buf->rem_bytes -= size;
347   return TRUE;
348 }
349
350 static void dump_TOKEN(WORD token)
351 {
352 #define DUMP_TOKEN(t) case t: TRACE(#t "\n"); break
353   switch(token)
354   {
355     DUMP_TOKEN(TOKEN_NAME);
356     DUMP_TOKEN(TOKEN_STRING);
357     DUMP_TOKEN(TOKEN_INTEGER);
358     DUMP_TOKEN(TOKEN_GUID);
359     DUMP_TOKEN(TOKEN_INTEGER_LIST);
360     DUMP_TOKEN(TOKEN_FLOAT_LIST);
361     DUMP_TOKEN(TOKEN_OBRACE);
362     DUMP_TOKEN(TOKEN_CBRACE);
363     DUMP_TOKEN(TOKEN_OPAREN);
364     DUMP_TOKEN(TOKEN_CPAREN);
365     DUMP_TOKEN(TOKEN_OBRACKET);
366     DUMP_TOKEN(TOKEN_CBRACKET);
367     DUMP_TOKEN(TOKEN_OANGLE);
368     DUMP_TOKEN(TOKEN_CANGLE);
369     DUMP_TOKEN(TOKEN_DOT);
370     DUMP_TOKEN(TOKEN_COMMA);
371     DUMP_TOKEN(TOKEN_SEMICOLON);
372     DUMP_TOKEN(TOKEN_TEMPLATE);
373     DUMP_TOKEN(TOKEN_WORD);
374     DUMP_TOKEN(TOKEN_DWORD);
375     DUMP_TOKEN(TOKEN_FLOAT);
376     DUMP_TOKEN(TOKEN_DOUBLE);
377     DUMP_TOKEN(TOKEN_CHAR);
378     DUMP_TOKEN(TOKEN_UCHAR);
379     DUMP_TOKEN(TOKEN_SWORD);
380     DUMP_TOKEN(TOKEN_SDWORD);
381     DUMP_TOKEN(TOKEN_VOID);
382     DUMP_TOKEN(TOKEN_LPSTR);
383     DUMP_TOKEN(TOKEN_UNICODE);
384     DUMP_TOKEN(TOKEN_CSTRING);
385     DUMP_TOKEN(TOKEN_ARRAY);
386     default:
387       if (0)
388         TRACE("Unknown token %d\n", token);
389       break;
390   }
391 #undef DUMP_TOKEN
392 }
393
394 static BOOL is_space(char c)
395 {
396   switch (c)
397   {
398     case 0x00:
399     case 0x0D:
400     case 0x0A:
401     case ' ':
402     case '\t':
403       return TRUE;
404   }
405   return FALSE;
406 }
407
408 static BOOL is_operator(char c)
409 {
410   switch(c)
411   {
412     case '{':
413     case '}':
414     case '[':
415     case ']':
416     case '(':
417     case ')':
418     case '<':
419     case '>':
420     case ',':
421     case ';':
422       return TRUE;
423   }
424   return FALSE;
425 }
426
427 static inline BOOL is_separator(char c)
428 {
429   return is_space(c) || is_operator(c);
430 }
431
432 static WORD get_operator_token(char c)
433 {
434   switch(c)
435   {
436     case '{':
437       return TOKEN_OBRACE;
438     case '}':
439       return TOKEN_CBRACE;
440     case '[':
441       return TOKEN_OBRACKET;
442     case ']':
443       return TOKEN_CBRACKET;
444     case '(':
445       return TOKEN_OPAREN;
446     case ')':
447       return TOKEN_CPAREN;
448     case '<':
449       return TOKEN_OANGLE;
450     case '>':
451       return TOKEN_CANGLE;
452     case ',':
453       return TOKEN_COMMA;
454     case ';':
455       return TOKEN_SEMICOLON;
456   }
457   return 0;
458 }
459
460 static BOOL is_keyword(parse_buffer* buf, const char* keyword)
461 {
462   DWORD len = strlen(keyword);
463   if (!strncmp((char*)buf->buffer, keyword,len) && is_separator(*(buf->buffer+len)))
464   {
465     buf->buffer += len;
466     buf->rem_bytes -= len;
467     return TRUE;
468   }
469   return FALSE;
470 }
471
472 static WORD get_keyword_token(parse_buffer* buf)
473 {
474   if (is_keyword(buf, "template"))
475     return TOKEN_TEMPLATE;
476   if (is_keyword(buf, "WORD"))
477     return TOKEN_WORD;
478   if (is_keyword(buf, "DWORD"))
479     return TOKEN_DWORD;
480   if (is_keyword(buf, "FLOAT"))
481     return TOKEN_FLOAT;
482   if (is_keyword(buf, "DOUBLE"))
483     return TOKEN_DOUBLE;
484   if (is_keyword(buf, "CHAR"))
485     return TOKEN_CHAR;
486   if (is_keyword(buf, "UCHAR"))
487     return TOKEN_UCHAR;
488   if (is_keyword(buf, "SWORD"))
489     return TOKEN_SWORD;
490   if (is_keyword(buf, "SDWORD"))
491     return TOKEN_SDWORD;
492   if (is_keyword(buf, "VOID"))
493     return TOKEN_VOID;
494   if (is_keyword(buf, "STRING"))
495     return TOKEN_LPSTR;
496   if (is_keyword(buf, "UNICODE"))
497     return TOKEN_UNICODE;
498   if (is_keyword(buf, "CSTRING"))
499     return TOKEN_CSTRING;
500   if (is_keyword(buf, "array"))
501     return TOKEN_ARRAY;
502
503   return 0;
504 }
505
506 static BOOL is_guid(parse_buffer* buf)
507 {
508   char tmp[50];
509   DWORD pos = 1;
510   GUID class_id;
511   DWORD tab[10];
512   int ret;
513
514   if (*buf->buffer != '<')
515     return FALSE;
516   tmp[0] = '<';
517   while (*(buf->buffer+pos) != '>')
518   {
519     tmp[pos] = *(buf->buffer+pos);
520     pos++;
521   }
522   tmp[pos++] = '>';
523   tmp[pos] = 0;
524   if (pos != 38 /* <+36+> */)
525   {
526     TRACE("Wrong guid %s (%d)\n", tmp, pos);
527     return FALSE;
528   }
529   buf->buffer += pos;
530   buf->rem_bytes -= pos;
531
532   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);
533   if (ret != 11)
534   {
535     TRACE("Wrong guid %s (%d)\n", tmp, pos);
536     return FALSE;
537   }
538   TRACE("Found guid %s (%d)\n", tmp, pos);
539
540   class_id.Data2 = tab[0];
541   class_id.Data3 = tab[1];
542   class_id.Data4[0] = tab[2];
543   class_id.Data4[1] = tab[3];
544   class_id.Data4[2] = tab[4];
545   class_id.Data4[3] = tab[5];
546   class_id.Data4[4] = tab[6];
547   class_id.Data4[5] = tab[7];
548   class_id.Data4[6] = tab[8];
549   class_id.Data4[7] = tab[9];
550
551   *(GUID*)buf->value = class_id;
552
553   return TRUE;
554 }
555
556 static BOOL is_name(parse_buffer* buf)
557 {
558   char tmp[50];
559   DWORD pos = 0;
560   char c;
561   BOOL error = 0;
562   while (!is_separator(c = *(buf->buffer+pos)))
563   {
564     if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '_')))
565       error = 1;
566     tmp[pos++] = c;
567   }
568   tmp[pos] = 0;
569
570   if (error)
571   {
572     TRACE("Wrong name %s\n", tmp);
573     return FALSE;
574   }
575
576   buf->buffer += pos;
577   buf->rem_bytes -= pos;
578
579   TRACE("Found name %s\n", tmp);
580   strcpy((char*)buf->value, tmp);
581
582   return TRUE;
583 }
584
585 static BOOL is_float(parse_buffer* buf)
586 {
587   char tmp[50];
588   DWORD pos = 0;
589   char c;
590   float decimal;
591   BOOL dot = 0;
592
593   while (!is_separator(c = *(buf->buffer+pos)))
594   {
595     if (!((!pos && (c == '-')) || ((c >= '0') && (c <= '9')) || (!dot && (c == '.'))))
596       return FALSE;
597     if (c == '.')
598       dot = TRUE;
599     tmp[pos++] = c;
600   }
601   tmp[pos] = 0;
602
603   buf->buffer += pos;
604   buf->rem_bytes -= pos;
605
606   sscanf(tmp, "%f", &decimal);
607
608   TRACE("Found float %s - %f\n", tmp, decimal);
609
610   *(float*)buf->value = decimal;
611
612   return TRUE;
613 }
614
615 static BOOL is_integer(parse_buffer* buf)
616 {
617   char tmp[50];
618   DWORD pos = 0;
619   char c;
620   DWORD integer;
621
622   while (!is_separator(c = *(buf->buffer+pos)))
623   {
624     if (!((c >= '0') && (c <= '9')))
625       return FALSE;
626     tmp[pos++] = c;
627   }
628   tmp[pos] = 0;
629
630   buf->buffer += pos;
631   buf->rem_bytes -= pos;
632
633   sscanf(tmp, "%d", &integer);
634
635   TRACE("Found integer %s - %d\n", tmp, integer);
636
637   *(DWORD*)buf->value = integer;
638
639   return TRUE;
640 }
641
642 static BOOL is_string(parse_buffer* buf)
643 {
644   char tmp[32];
645   DWORD pos = 1;
646   char c;
647   BOOL ok = 0;
648
649   if (*buf->buffer != '"')
650     return FALSE;
651   tmp[0] = '"';
652
653   while (!is_separator(c = *(buf->buffer+pos)) && (pos < 32))
654   {
655     tmp[pos++] = c;
656     if (c == '"')
657     {
658       ok = 1;
659       break;
660     }
661   }
662   tmp[pos] = 0;
663
664   if (!ok)
665   {
666     TRACE("Wrong string %s\n", tmp);
667     return FALSE;
668   }
669
670   buf->buffer += pos;
671   buf->rem_bytes -= pos;
672
673   TRACE("Found string %s\n", tmp);
674   strcpy((char*)buf->value, tmp);
675
676   return TRUE;
677 }
678
679 static WORD parse_TOKEN(parse_buffer * buf)
680 {
681   WORD token;
682
683   if (buf->txt)
684   {
685     while(1)
686     {
687       char c;
688       if (!read_bytes(buf, &c, 1))
689         return 0;
690       /*TRACE("char = '%c'\n", is_space(c) ? ' ' : c);*/
691       if ((c == '#') || (c == '/'))
692       {
693         /* Handle comment (# or //) */
694         if (c == '/')
695         {
696           if (!read_bytes(buf, &c, 1))
697             return 0;
698           if (c != '/')
699             return 0;
700         }
701         c = 0;
702         while (c != 0x0A)
703         {
704           if (!read_bytes(buf, &c, 1))
705             return 0;
706         }
707         continue;
708       }
709       if (is_space(c))
710         continue;
711       if (is_operator(c) && (c != '<'))
712       {
713         token = get_operator_token(c);
714         break;
715       }
716       else if (c == '.')
717       {
718         token = TOKEN_DOT;
719         break;
720       }
721       else
722       {
723         buf->buffer -= 1;
724         buf->rem_bytes += 1;
725
726         if ((token = get_keyword_token(buf)))
727           break;
728
729         if (is_guid(buf))
730         {
731           token = TOKEN_GUID;
732           break;
733         }
734         if (is_integer(buf))
735         {
736           token = TOKEN_INTEGER;
737           break;
738         }
739         if (is_float(buf))
740         {
741           token = TOKEN_FLOAT;
742           break;
743         }
744         if (is_string(buf))
745         {
746           token = TOKEN_LPSTR;
747           break;
748         }
749         if (is_name(buf))
750         {
751           token = TOKEN_NAME;
752           break;
753         }
754
755         FIXME("Unrecognize element\n");
756         return 0;
757       }
758     }
759   }
760   else
761   {
762     if (!read_bytes(buf, &token, 2))
763       return 0;
764
765     switch(token)
766     {
767       case TOKEN_NAME:
768         {
769           DWORD count;
770           char strname[100];
771
772           if (!read_bytes(buf, &count, 4))
773             return 0;
774           if (!read_bytes(buf, strname, count))
775             return 0;
776           strname[count] = 0;
777           /*TRACE("name = %s\n", strname);*/
778
779           strcpy((char*)buf->value, strname);
780         }
781         break;
782       case TOKEN_INTEGER:
783         {
784           DWORD integer;
785
786           if (!read_bytes(buf, &integer, 4))
787             return 0;
788           /*TRACE("integer = %ld\n", integer);*/
789
790           *(DWORD*)buf->value = integer;
791         }
792         break;
793       case TOKEN_GUID:
794         {
795           char strguid[38];
796           GUID class_id;
797
798           if (!read_bytes(buf, &class_id, 16))
799             return 0;
800           sprintf(strguid, CLSIDFMT, class_id.Data1, class_id.Data2, class_id.Data3, class_id.Data4[0],
801             class_id.Data4[1], class_id.Data4[2], class_id.Data4[3], class_id.Data4[4], class_id.Data4[5],
802             class_id.Data4[6], class_id.Data4[7]);
803           /*TRACE("guid = {%s}\n", strguid);*/
804
805           *(GUID*)buf->value = class_id;
806         }
807         break;
808       case TOKEN_STRING:
809       case TOKEN_INTEGER_LIST:
810       case TOKEN_FLOAT_LIST:
811       case TOKEN_OBRACE:
812       case TOKEN_CBRACE:
813       case TOKEN_OPAREN:
814       case TOKEN_CPAREN:
815       case TOKEN_OBRACKET:
816       case TOKEN_CBRACKET:
817       case TOKEN_OANGLE:
818       case TOKEN_CANGLE:
819       case TOKEN_DOT:
820       case TOKEN_COMMA:
821       case TOKEN_SEMICOLON:
822       case TOKEN_TEMPLATE:
823       case TOKEN_WORD:
824       case TOKEN_DWORD:
825       case TOKEN_FLOAT:
826       case TOKEN_DOUBLE:
827       case TOKEN_CHAR:
828       case TOKEN_UCHAR:
829       case TOKEN_SWORD:
830       case TOKEN_SDWORD:
831       case TOKEN_VOID:
832       case TOKEN_LPSTR:
833       case TOKEN_UNICODE:
834       case TOKEN_CSTRING:
835       case TOKEN_ARRAY:
836         break;
837       default:
838         return 0;
839     }
840   }
841
842   dump_TOKEN(token);
843
844   return token;
845 }
846
847 static const char* get_primitive_string(WORD token)
848 {
849   switch(token)
850   {
851     case TOKEN_WORD:
852       return "WORD";
853     case TOKEN_DWORD:
854       return "DWORD";
855     case TOKEN_FLOAT:
856       return "FLOAT";
857     case TOKEN_DOUBLE:
858       return "DOUBLE";
859     case TOKEN_CHAR:
860       return "CHAR";
861     case TOKEN_UCHAR:
862       return "UCHAR";
863     case TOKEN_SWORD:
864       return "SWORD";
865     case TOKEN_SDWORD:
866       return "SDWORD";
867     case TOKEN_VOID:
868       return "VOID";
869     case TOKEN_LPSTR:
870       return "STRING";
871     case TOKEN_UNICODE:
872       return "UNICODE";
873     case TOKEN_CSTRING:
874       return "CSTRING ";
875     default:
876       break;
877   }
878   return NULL;
879 }
880
881 static WORD get_TOKEN(parse_buffer * buf)
882 {
883   if (buf->token_present)
884   {
885     buf->token_present = FALSE;
886     return buf->current_token;
887   }
888
889   buf->current_token = parse_TOKEN(buf);
890
891   return buf->current_token;
892 }
893
894 static WORD check_TOKEN(parse_buffer * buf)
895 {
896   if (buf->token_present)
897     return buf->current_token;
898
899   buf->current_token = parse_TOKEN(buf);
900   buf->token_present = TRUE;
901
902   return buf->current_token;
903 }
904
905 static inline BOOL is_primitive_type(WORD token)
906 {
907   BOOL ret;
908   switch(token)
909   {
910     case TOKEN_WORD:
911     case TOKEN_DWORD:
912     case TOKEN_FLOAT:
913     case TOKEN_DOUBLE:
914     case TOKEN_CHAR:
915     case TOKEN_UCHAR:
916     case TOKEN_SWORD:
917     case TOKEN_SDWORD:
918     case TOKEN_LPSTR:
919     case TOKEN_UNICODE:
920     case TOKEN_CSTRING:
921       ret = 1;
922       break;
923     default:
924       ret = 0;
925       break;
926   }
927   return ret;
928 }
929
930 static BOOL parse_template_option_info(parse_buffer * buf)
931 {
932   xtemplate* cur_template = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates];
933
934   if (check_TOKEN(buf) == TOKEN_DOT)
935   {
936     get_TOKEN(buf);
937     if (get_TOKEN(buf) != TOKEN_DOT)
938       return FALSE;
939     if (get_TOKEN(buf) != TOKEN_DOT)
940       return FALSE;
941     cur_template->open = TRUE;
942   }
943   else
944   {
945     while (1)
946     {
947       if (get_TOKEN(buf) != TOKEN_NAME)
948         return FALSE;
949       strcpy(cur_template->childs[cur_template->nb_childs], (char*)buf->value);
950       if (check_TOKEN(buf) == TOKEN_GUID)
951         get_TOKEN(buf);
952       cur_template->nb_childs++;
953       if (check_TOKEN(buf) != TOKEN_COMMA)
954         break;
955       get_TOKEN(buf);
956     }
957     cur_template->open = FALSE;
958   }
959
960   return TRUE;
961 }
962
963 static BOOL parse_template_members_list(parse_buffer * buf)
964 {
965   int idx_member = 0;
966   member* cur_member;
967
968   while (1)
969   {
970     BOOL array = 0;
971     int nb_dims = 0;
972     cur_member = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[idx_member];
973
974     if (check_TOKEN(buf) == TOKEN_ARRAY)
975     {
976       get_TOKEN(buf);
977       array = 1;
978     }
979
980     if (check_TOKEN(buf) == TOKEN_NAME)
981     {
982       cur_member->type = get_TOKEN(buf);
983       cur_member->idx_template = 0;
984       while (cur_member->idx_template < buf->pdxf->nb_xtemplates)
985       {
986         if (!strcmp((char*)buf->value, buf->pdxf->xtemplates[cur_member->idx_template].name))
987           break;
988         cur_member->idx_template++;
989       }
990       if (cur_member->idx_template == buf->pdxf->nb_xtemplates)
991       {
992         TRACE("Reference to a nonexistent template '%s'\n", (char*)buf->value);
993         return FALSE;
994       }
995     }
996     else if (is_primitive_type(check_TOKEN(buf)))
997       cur_member->type = get_TOKEN(buf);
998     else
999       break;
1000
1001     if (get_TOKEN(buf) != TOKEN_NAME)
1002       return FALSE;
1003     strcpy(cur_member->name, (char*)buf->value);
1004
1005     if (array)
1006     {
1007       while (check_TOKEN(buf) == TOKEN_OBRACKET)
1008       {
1009         if (nb_dims)
1010         {
1011           FIXME("No support for multi-dimensional array yet\n");
1012           return FALSE;
1013         }
1014         get_TOKEN(buf);
1015         if (check_TOKEN(buf) == TOKEN_INTEGER)
1016         {
1017           get_TOKEN(buf);
1018           cur_member->dim_fixed[nb_dims] = TRUE;
1019           cur_member->dim_value[nb_dims] = *(DWORD*)buf->value;
1020         }
1021         else
1022         {
1023           if (get_TOKEN(buf) != TOKEN_NAME)
1024             return FALSE;
1025           cur_member->dim_fixed[nb_dims] = FALSE;
1026           /* Hack: Assume array size is specified in previous member */
1027           cur_member->dim_value[nb_dims] = idx_member - 1;
1028         }
1029         if (get_TOKEN(buf) != TOKEN_CBRACKET)
1030           return FALSE;
1031         nb_dims++;
1032       }
1033       if (!nb_dims)
1034         return FALSE;
1035       cur_member->nb_dims = nb_dims;
1036     }
1037     if (get_TOKEN(buf) != TOKEN_SEMICOLON)
1038       return FALSE;
1039
1040     idx_member++;
1041   }
1042
1043   buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].nb_members = idx_member;
1044
1045   return TRUE;
1046 }
1047
1048 static BOOL parse_template_parts(parse_buffer * buf)
1049 {
1050   if (!parse_template_members_list(buf))
1051     return FALSE;
1052   if (check_TOKEN(buf) == TOKEN_OBRACKET)
1053   {
1054     get_TOKEN(buf);
1055     if (!parse_template_option_info(buf))
1056       return FALSE;
1057     if (get_TOKEN(buf) != TOKEN_CBRACKET)
1058      return FALSE;
1059   }
1060
1061   return TRUE;
1062 }
1063
1064 static BOOL parse_template(parse_buffer * buf)
1065 {
1066   if (get_TOKEN(buf) != TOKEN_TEMPLATE)
1067     return FALSE;
1068   if (get_TOKEN(buf) != TOKEN_NAME)
1069     return FALSE;
1070   strcpy(buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].name, (char*)buf->value);
1071   if (get_TOKEN(buf) != TOKEN_OBRACE)
1072     return FALSE;
1073   if (get_TOKEN(buf) != TOKEN_GUID)
1074     return FALSE;
1075   buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].class_id = *(GUID*)buf->value;
1076   if (!parse_template_parts(buf))
1077     return FALSE;
1078   if (get_TOKEN(buf) != TOKEN_CBRACE)
1079     return FALSE;
1080   if (buf->txt)
1081   {
1082     /* Go to the next template */
1083     while (buf->rem_bytes && is_space(*buf->buffer))
1084     {
1085       buf->buffer++;
1086       buf->rem_bytes--;
1087     }
1088   }
1089
1090   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));
1091   buf->pdxf->nb_xtemplates++;
1092
1093   return TRUE;
1094 }
1095
1096 static HRESULT WINAPI IDirectXFileImpl_RegisterTemplates(IDirectXFile* iface, LPVOID pvData, DWORD cbSize)
1097 {
1098   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
1099   DWORD token_header;
1100   parse_buffer buf;
1101
1102   buf.buffer = (LPBYTE)pvData;
1103   buf.rem_bytes = cbSize;
1104   buf.txt = FALSE;
1105   buf.token_present = FALSE;
1106   buf.pdxf = This;
1107
1108   TRACE("(%p/%p)->(%p,%d)\n", This, iface, pvData, cbSize);
1109
1110   if (!pvData)
1111     return DXFILEERR_BADVALUE;
1112
1113   if (cbSize < 16)
1114     return DXFILEERR_BADFILETYPE;
1115
1116   if (TRACE_ON(d3dxof))
1117   {
1118     char string[17];
1119     memcpy(string, pvData, 16);
1120     string[16] = 0;
1121     TRACE("header = '%s'\n", string);
1122   }
1123
1124   read_bytes(&buf, &token_header, 4);
1125
1126   if (token_header != XOFFILE_FORMAT_MAGIC)
1127     return DXFILEERR_BADFILETYPE;
1128
1129   read_bytes(&buf, &token_header, 4);
1130
1131   if (token_header != XOFFILE_FORMAT_VERSION)
1132     return DXFILEERR_BADFILEVERSION;
1133
1134   read_bytes(&buf, &token_header, 4);
1135
1136   if ((token_header != XOFFILE_FORMAT_BINARY) && (token_header != XOFFILE_FORMAT_TEXT) && (token_header != XOFFILE_FORMAT_COMPRESSED))
1137     return DXFILEERR_BADFILETYPE;
1138
1139   if (token_header == XOFFILE_FORMAT_TEXT)
1140   {
1141     buf.txt = TRUE;
1142   }
1143
1144   if (token_header == XOFFILE_FORMAT_COMPRESSED)
1145   {
1146     FIXME("Compressed formats not supported yet\n");
1147     return DXFILEERR_BADVALUE;
1148   }
1149
1150   read_bytes(&buf, &token_header, 4);
1151
1152   if ((token_header != XOFFILE_FORMAT_FLOAT_BITS_32) && (token_header != XOFFILE_FORMAT_FLOAT_BITS_64))
1153     return DXFILEERR_BADFILEFLOATSIZE;
1154
1155   TRACE("Header is correct\n");
1156
1157   while (buf.rem_bytes)
1158   {
1159     if (!parse_template(&buf))
1160     {
1161       TRACE("Template is not correct\n");
1162       return DXFILEERR_BADVALUE;
1163     }
1164     else
1165     {
1166       TRACE("Template successfully parsed:\n");
1167       if (TRACE_ON(d3dxof))
1168         dump_template(This->xtemplates, &This->xtemplates[This->nb_xtemplates - 1]);
1169     }
1170   }
1171
1172   if (TRACE_ON(d3dxof))
1173   {
1174     int i;
1175     TRACE("Registered templates (%d):\n", This->nb_xtemplates);
1176     for (i = 0; i < This->nb_xtemplates; i++)
1177       DPRINTF("%s - %s\n", This->xtemplates[i].name, debugstr_guid(&This->xtemplates[i].class_id));
1178   }
1179
1180   return DXFILE_OK;
1181 }
1182
1183 static const IDirectXFileVtbl IDirectXFile_Vtbl =
1184 {
1185   IDirectXFileImpl_QueryInterface,
1186   IDirectXFileImpl_AddRef,
1187   IDirectXFileImpl_Release,
1188   IDirectXFileImpl_CreateEnumObject,
1189   IDirectXFileImpl_CreateSaveObject,
1190   IDirectXFileImpl_RegisterTemplates
1191 };
1192
1193 HRESULT IDirectXFileBinaryImpl_Create(IDirectXFileBinaryImpl** ppObj)
1194 {
1195     IDirectXFileBinaryImpl* object;
1196
1197     TRACE("(%p)\n", ppObj);
1198       
1199     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileBinaryImpl));
1200     
1201     object->lpVtbl.lpVtbl = &IDirectXFileBinary_Vtbl;
1202     object->ref = 1;
1203
1204     *ppObj = object;
1205     
1206     return DXFILE_OK;
1207 }
1208
1209 /*** IUnknown methods ***/
1210 static HRESULT WINAPI IDirectXFileBinaryImpl_QueryInterface(IDirectXFileBinary* iface, REFIID riid, void** ppvObject)
1211 {
1212   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1213
1214   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1215
1216   if (IsEqualGUID(riid, &IID_IUnknown)
1217       || IsEqualGUID(riid, &IID_IDirectXFileObject)
1218       || IsEqualGUID(riid, &IID_IDirectXFileBinary))
1219   {
1220     IClassFactory_AddRef(iface);
1221     *ppvObject = This;
1222     return S_OK;
1223   }
1224
1225   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
1226   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
1227       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
1228     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1229
1230   return E_NOINTERFACE;
1231 }
1232
1233 static ULONG WINAPI IDirectXFileBinaryImpl_AddRef(IDirectXFileBinary* iface)
1234 {
1235   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1236   ULONG ref = InterlockedIncrement(&This->ref);
1237
1238   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1239
1240   return ref;
1241 }
1242
1243 static ULONG WINAPI IDirectXFileBinaryImpl_Release(IDirectXFileBinary* iface)
1244 {
1245   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1246   ULONG ref = InterlockedDecrement(&This->ref);
1247
1248   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1249
1250   if (!ref)
1251     HeapFree(GetProcessHeap(), 0, This);
1252
1253   return ref;
1254 }
1255
1256 /*** IDirectXFileObject methods ***/
1257 static HRESULT WINAPI IDirectXFileBinaryImpl_GetName(IDirectXFileBinary* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
1258
1259 {
1260   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1261
1262   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pstrNameBuf, pdwBufLen); 
1263
1264   return DXFILEERR_BADVALUE;
1265 }
1266
1267 static HRESULT WINAPI IDirectXFileBinaryImpl_GetId(IDirectXFileBinary* iface, LPGUID pGuid)
1268 {
1269   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1270
1271   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pGuid); 
1272
1273   return DXFILEERR_BADVALUE;
1274 }
1275
1276 /*** IDirectXFileBinary methods ***/
1277 static HRESULT WINAPI IDirectXFileBinaryImpl_GetSize(IDirectXFileBinary* iface, DWORD* pcbSize)
1278 {
1279   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1280
1281   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pcbSize); 
1282
1283   return DXFILEERR_BADVALUE;
1284 }
1285
1286 static HRESULT WINAPI IDirectXFileBinaryImpl_GetMimeType(IDirectXFileBinary* iface, LPCSTR* pszMimeType)
1287 {
1288   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1289
1290   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pszMimeType);
1291
1292   return DXFILEERR_BADVALUE;
1293 }
1294
1295 static HRESULT WINAPI IDirectXFileBinaryImpl_Read(IDirectXFileBinary* iface, LPVOID pvData, DWORD cbSize, LPDWORD pcbRead)
1296 {
1297   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1298
1299   FIXME("(%p/%p)->(%p, %d, %p) stub!\n", This, iface, pvData, cbSize, pcbRead);
1300
1301   return DXFILEERR_BADVALUE;
1302 }
1303
1304 static const IDirectXFileBinaryVtbl IDirectXFileBinary_Vtbl =
1305 {
1306     IDirectXFileBinaryImpl_QueryInterface,
1307     IDirectXFileBinaryImpl_AddRef,
1308     IDirectXFileBinaryImpl_Release,
1309     IDirectXFileBinaryImpl_GetName,
1310     IDirectXFileBinaryImpl_GetId,
1311     IDirectXFileBinaryImpl_GetSize,
1312     IDirectXFileBinaryImpl_GetMimeType,
1313     IDirectXFileBinaryImpl_Read
1314 };
1315
1316 HRESULT IDirectXFileDataImpl_Create(IDirectXFileDataImpl** ppObj)
1317 {
1318     IDirectXFileDataImpl* object;
1319
1320     TRACE("(%p)\n", ppObj);
1321       
1322     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataImpl));
1323     
1324     object->lpVtbl.lpVtbl = &IDirectXFileData_Vtbl;
1325     object->ref = 1;
1326
1327     *ppObj = object;
1328     
1329     return S_OK;
1330 }
1331
1332 /*** IUnknown methods ***/
1333 static HRESULT WINAPI IDirectXFileDataImpl_QueryInterface(IDirectXFileData* iface, REFIID riid, void** ppvObject)
1334 {
1335   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1336
1337   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1338
1339   if (IsEqualGUID(riid, &IID_IUnknown)
1340       || IsEqualGUID(riid, &IID_IDirectXFileObject)
1341       || IsEqualGUID(riid, &IID_IDirectXFileData))
1342   {
1343     IClassFactory_AddRef(iface);
1344     *ppvObject = This;
1345     return S_OK;
1346   }
1347
1348   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
1349   if (!IsEqualGUID(riid, &IID_IDirectXFileBinary)
1350       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
1351     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1352
1353   return E_NOINTERFACE;
1354 }
1355
1356 static ULONG WINAPI IDirectXFileDataImpl_AddRef(IDirectXFileData* iface)
1357 {
1358   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1359   ULONG ref = InterlockedIncrement(&This->ref);
1360
1361   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1362
1363   return ref;
1364 }
1365
1366 static ULONG WINAPI IDirectXFileDataImpl_Release(IDirectXFileData* iface)
1367 {
1368   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1369   ULONG ref = InterlockedDecrement(&This->ref);
1370
1371   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1372
1373   if (!ref)
1374     HeapFree(GetProcessHeap(), 0, This);
1375
1376   return ref;
1377 }
1378
1379 /*** IDirectXFileObject methods ***/
1380 static HRESULT WINAPI IDirectXFileDataImpl_GetName(IDirectXFileData* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
1381
1382 {
1383   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1384
1385   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
1386
1387   if (!pstrNameBuf)
1388     return DXFILEERR_BADVALUE;
1389
1390   strcpy(pstrNameBuf, This->pobj->name);
1391
1392   return DXFILE_OK;
1393 }
1394
1395 static HRESULT WINAPI IDirectXFileDataImpl_GetId(IDirectXFileData* iface, LPGUID pGuid)
1396 {
1397   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1398
1399   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
1400
1401   if (!pGuid)
1402     return DXFILEERR_BADVALUE;
1403
1404   memcpy(pGuid, &This->pobj->class_id, 16);
1405
1406   return DXFILE_OK;
1407 }
1408
1409 /*** IDirectXFileData methods ***/
1410 static HRESULT WINAPI IDirectXFileDataImpl_GetData(IDirectXFileData* iface, LPCSTR szMember, DWORD* pcbSize, void** ppvData)
1411 {
1412   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1413
1414   TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, szMember, pcbSize, ppvData);
1415
1416   if (!pcbSize || !ppvData)
1417     return DXFILEERR_BADVALUE;
1418
1419   if (szMember)
1420   {
1421     FIXME("Specifying a member is not supported yet!\n");
1422     return DXFILEERR_BADVALUE;
1423   }
1424
1425   *pcbSize = This->pobj->size;
1426   *ppvData = This->pobj->pdata;
1427
1428   return DXFILE_OK;
1429 }
1430
1431 static HRESULT WINAPI IDirectXFileDataImpl_GetType(IDirectXFileData* iface, const GUID** pguid)
1432 {
1433   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1434   static GUID guid;
1435
1436   TRACE("(%p/%p)->(%p)\n", This, iface, pguid);
1437
1438   if (!pguid)
1439     return DXFILEERR_BADVALUE;
1440
1441   memcpy(&guid, &This->pobj->type, 16);
1442   *pguid = &guid;
1443
1444   return DXFILE_OK;
1445 }
1446
1447 static HRESULT WINAPI IDirectXFileDataImpl_GetNextObject(IDirectXFileData* iface, LPDIRECTXFILEOBJECT* ppChildObj)
1448 {
1449   HRESULT hr;
1450   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1451
1452   TRACE("(%p/%p)->(%p)\n", This, iface, ppChildObj);
1453
1454   if (This->cur_enum_object >= This->pobj->nb_childs)
1455     return DXFILEERR_NOMOREOBJECTS;
1456
1457   if (This->from_ref && (This->level >= 1))
1458   {
1459     /* Only 2 levels can enumerated if the object is obtained from a reference */
1460     return DXFILEERR_NOMOREOBJECTS;
1461   }
1462
1463   if (This->pobj->childs[This->cur_enum_object]->ptarget)
1464   {
1465     IDirectXFileDataReferenceImpl *object;
1466
1467     hr = IDirectXFileDataReferenceImpl_Create(&object);
1468     if (hr != S_OK)
1469       return DXFILEERR_BADVALUE;
1470
1471     object->ptarget = This->pobj->childs[This->cur_enum_object++]->ptarget;
1472
1473     *ppChildObj = (LPDIRECTXFILEOBJECT)object;
1474   }
1475   else
1476   {
1477     IDirectXFileDataImpl *object;
1478
1479     hr = IDirectXFileDataImpl_Create(&object);
1480     if (hr != S_OK)
1481       return DXFILEERR_BADVALUE;
1482
1483     object->pobj = This->pobj->childs[This->cur_enum_object++];
1484     object->cur_enum_object = 0;
1485     object->from_ref = This->from_ref;
1486     object->level = This->level + 1;
1487
1488     *ppChildObj = (LPDIRECTXFILEOBJECT)object;
1489   }
1490
1491   return DXFILE_OK;
1492 }
1493
1494 static HRESULT WINAPI IDirectXFileDataImpl_AddDataObject(IDirectXFileData* iface, LPDIRECTXFILEDATA pDataObj)
1495 {
1496   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1497
1498   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pDataObj); 
1499
1500   return DXFILEERR_BADVALUE;
1501 }
1502
1503 static HRESULT WINAPI IDirectXFileDataImpl_AddDataReference(IDirectXFileData* iface, LPCSTR szRef, const GUID* pguidRef)
1504 {
1505   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1506
1507   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szRef, pguidRef); 
1508
1509   return DXFILEERR_BADVALUE;
1510 }
1511
1512 static HRESULT WINAPI IDirectXFileDataImpl_AddBinaryObject(IDirectXFileData* iface, LPCSTR szName, const GUID* pguid, LPCSTR szMimeType, LPVOID pvData, DWORD cbSize)
1513 {
1514   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1515
1516   FIXME("(%p/%p)->(%s,%p,%s,%p,%d) stub!\n", This, iface, szName, pguid, szMimeType, pvData, cbSize);
1517
1518   return DXFILEERR_BADVALUE;
1519 }
1520
1521 static const IDirectXFileDataVtbl IDirectXFileData_Vtbl =
1522 {
1523     IDirectXFileDataImpl_QueryInterface,
1524     IDirectXFileDataImpl_AddRef,
1525     IDirectXFileDataImpl_Release,
1526     IDirectXFileDataImpl_GetName,
1527     IDirectXFileDataImpl_GetId,
1528     IDirectXFileDataImpl_GetData,
1529     IDirectXFileDataImpl_GetType,
1530     IDirectXFileDataImpl_GetNextObject,
1531     IDirectXFileDataImpl_AddDataObject,
1532     IDirectXFileDataImpl_AddDataReference,
1533     IDirectXFileDataImpl_AddBinaryObject
1534 };
1535
1536 HRESULT IDirectXFileDataReferenceImpl_Create(IDirectXFileDataReferenceImpl** ppObj)
1537 {
1538     IDirectXFileDataReferenceImpl* object;
1539
1540     TRACE("(%p)\n", ppObj);
1541       
1542     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataReferenceImpl));
1543     
1544     object->lpVtbl.lpVtbl = &IDirectXFileDataReference_Vtbl;
1545     object->ref = 1;
1546
1547     *ppObj = object;
1548     
1549     return S_OK;
1550 }
1551
1552 /*** IUnknown methods ***/
1553 static HRESULT WINAPI IDirectXFileDataReferenceImpl_QueryInterface(IDirectXFileDataReference* iface, REFIID riid, void** ppvObject)
1554 {
1555   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1556
1557   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1558
1559   if (IsEqualGUID(riid, &IID_IUnknown)
1560       || IsEqualGUID(riid, &IID_IDirectXFileObject)
1561       || IsEqualGUID(riid, &IID_IDirectXFileDataReference))
1562   {
1563     IClassFactory_AddRef(iface);
1564     *ppvObject = This;
1565     return S_OK;
1566   }
1567
1568   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
1569   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
1570       && !IsEqualGUID(riid, &IID_IDirectXFileBinary))
1571     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1572
1573   return E_NOINTERFACE;
1574 }
1575
1576 static ULONG WINAPI IDirectXFileDataReferenceImpl_AddRef(IDirectXFileDataReference* iface)
1577 {
1578   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1579   ULONG ref = InterlockedIncrement(&This->ref);
1580
1581   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1582
1583   return ref;
1584 }
1585
1586 static ULONG WINAPI IDirectXFileDataReferenceImpl_Release(IDirectXFileDataReference* iface)
1587 {
1588   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1589   ULONG ref = InterlockedDecrement(&This->ref);
1590
1591   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1592
1593   if (!ref)
1594     HeapFree(GetProcessHeap(), 0, This);
1595
1596   return ref;
1597 }
1598
1599 /*** IDirectXFileObject methods ***/
1600 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetName(IDirectXFileDataReference* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
1601 {
1602   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1603
1604   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
1605
1606   if (!pstrNameBuf)
1607     return DXFILEERR_BADVALUE;
1608
1609   strcpy(pstrNameBuf, This->ptarget->name);
1610
1611   return DXFILEERR_BADVALUE;
1612 }
1613
1614 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetId(IDirectXFileDataReference* iface, LPGUID pGuid)
1615 {
1616   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1617
1618   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
1619
1620   if (!pGuid)
1621     return DXFILEERR_BADVALUE;
1622
1623   memcpy(pGuid, &This->ptarget->class_id, 16);
1624
1625   return DXFILE_OK;
1626 }
1627
1628 /*** IDirectXFileDataReference ***/
1629 static HRESULT WINAPI IDirectXFileDataReferenceImpl_Resolve(IDirectXFileDataReference* iface, LPDIRECTXFILEDATA* ppDataObj)
1630 {
1631   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1632   IDirectXFileDataImpl *object;
1633   HRESULT hr;
1634
1635   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
1636
1637   if (!ppDataObj)
1638     return DXFILEERR_BADVALUE;
1639
1640   hr = IDirectXFileDataImpl_Create(&object);
1641   if (hr != S_OK)
1642     return DXFILEERR_BADVALUE;
1643
1644   object->pobj = This->ptarget;
1645   object->cur_enum_object = 0;
1646   object->level = 0;
1647   object->from_ref = TRUE;
1648
1649   *ppDataObj = (LPDIRECTXFILEDATA)object;
1650
1651   return DXFILE_OK;
1652 }
1653
1654 static const IDirectXFileDataReferenceVtbl IDirectXFileDataReference_Vtbl =
1655 {
1656     IDirectXFileDataReferenceImpl_QueryInterface,
1657     IDirectXFileDataReferenceImpl_AddRef,
1658     IDirectXFileDataReferenceImpl_Release,
1659     IDirectXFileDataReferenceImpl_GetName,
1660     IDirectXFileDataReferenceImpl_GetId,
1661     IDirectXFileDataReferenceImpl_Resolve
1662 };
1663
1664 HRESULT IDirectXFileEnumObjectImpl_Create(IDirectXFileEnumObjectImpl** ppObj)
1665 {
1666     IDirectXFileEnumObjectImpl* object;
1667
1668     TRACE("(%p)\n", ppObj);
1669       
1670     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileEnumObjectImpl));
1671     
1672     object->lpVtbl.lpVtbl = &IDirectXFileEnumObject_Vtbl;
1673     object->ref = 1;
1674
1675     *ppObj = object;
1676     
1677     return S_OK;
1678 }
1679
1680 /*** IUnknown methods ***/
1681 static HRESULT WINAPI IDirectXFileEnumObjectImpl_QueryInterface(IDirectXFileEnumObject* iface, REFIID riid, void** ppvObject)
1682 {
1683   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1684
1685   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1686
1687   if (IsEqualGUID(riid, &IID_IUnknown)
1688       || IsEqualGUID(riid, &IID_IDirectXFileEnumObject))
1689   {
1690     IClassFactory_AddRef(iface);
1691     *ppvObject = This;
1692     return S_OK;
1693   }
1694
1695   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1696   return E_NOINTERFACE;
1697 }
1698
1699 static ULONG WINAPI IDirectXFileEnumObjectImpl_AddRef(IDirectXFileEnumObject* iface)
1700 {
1701   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1702   ULONG ref = InterlockedIncrement(&This->ref);
1703
1704   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1705
1706   return ref;
1707 }
1708
1709 static ULONG WINAPI IDirectXFileEnumObjectImpl_Release(IDirectXFileEnumObject* iface)
1710 {
1711   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1712   ULONG ref = InterlockedDecrement(&This->ref);
1713
1714   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1715
1716   if (!ref)
1717     HeapFree(GetProcessHeap(), 0, This);
1718
1719   return ref;
1720 }
1721
1722 static BOOL parse_object_members_list(parse_buffer * buf)
1723 {
1724   DWORD token;
1725   int i;
1726   xtemplate* pt = buf->pxt[buf->level];
1727   DWORD last_dword = 0;
1728
1729   for (i = 0; i < pt->nb_members; i++)
1730   {
1731     int nb_elems, k;
1732
1733     if (pt->members[i].nb_dims > 1)
1734     {
1735       FIXME("Arrays with dimension > 1 not yet supported\n");
1736       return FALSE;
1737     }
1738     else if (pt->members[i].nb_dims)
1739     {
1740       if (!pt->members[i].dim_fixed[0])
1741       {
1742         if (!i)
1743         {
1744           FIXME("Array with variable must be preceded by the size\n");
1745           return FALSE;
1746         }
1747         nb_elems = last_dword;
1748         /*FIXME("Arrays with variable size not yet supported\n");
1749         return FALSE;*/
1750       }
1751       else
1752         nb_elems = pt->members[i].dim_value[0];
1753     }
1754     else
1755       nb_elems = 1;
1756
1757     for (k = 0; k < nb_elems; k++)
1758     {
1759       if (k)
1760       {
1761         token = check_TOKEN(buf);
1762         if (token == TOKEN_COMMA)
1763         {
1764           get_TOKEN(buf);
1765         }
1766         else
1767         {
1768           /* Allow comma omission */
1769           if (!((token == TOKEN_FLOAT)))
1770             return FALSE;
1771         }
1772       }
1773
1774       if (pt->members[i].type == TOKEN_NAME)
1775       {
1776         int j;
1777
1778         TRACE("Found suboject %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1779         buf->level++;
1780         /* To do template lookup */
1781         for (j = 0; j < buf->pdxf->nb_xtemplates; j++)
1782         {
1783           if (!strcmp(buf->pdxf->xtemplates[pt->members[i].idx_template].name, buf->pdxf->xtemplates[j].name))
1784           {
1785             buf->pxt[buf->level] = &buf->pdxf->xtemplates[j];
1786             break;
1787           }
1788         }
1789         if (j == buf->pdxf->nb_xtemplates)
1790         {
1791           FIXME("Unknown template %s\n", (char*)buf->value);
1792           buf->level--;
1793           return FALSE;
1794         }
1795         TRACE("Enter %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1796         if (!parse_object_parts(buf, FALSE))
1797         {
1798           buf->level--;
1799           return FALSE;
1800         }
1801         buf->level--;
1802         /*if (get_TOKEN(buf) != TOKEN_SEMICOLON)
1803           return FALSE;*/
1804       }
1805       else
1806       {
1807         token = check_TOKEN(buf);
1808         if (token == TOKEN_INTEGER)
1809         {
1810           get_TOKEN(buf);
1811           last_dword = *(DWORD*)buf->value;
1812           TRACE("%s = %d\n", pt->members[i].name, *(DWORD*)buf->value);
1813           /* Assume larger size */
1814           if ((buf->cur_pdata - buf->pxo->pdata + 4) > MAX_DATA_SIZE)
1815           {
1816             WARN("Buffer too small\n");
1817             return FALSE;
1818           }
1819           if (pt->members[i].type == TOKEN_WORD)
1820           {
1821             *(((WORD*)(buf->cur_pdata))) = (WORD)(*(DWORD*)buf->value);
1822             buf->cur_pdata += 2;
1823           }
1824           else if (pt->members[i].type == TOKEN_DWORD)
1825           {
1826             *(((DWORD*)(buf->cur_pdata))) = (DWORD)(*(DWORD*)buf->value);
1827             buf->cur_pdata += 4;
1828           }
1829           else
1830           {
1831             FIXME("Token %d not supported\n", pt->members[i].type);
1832             return FALSE;
1833           }
1834         }
1835         else if (token == TOKEN_FLOAT)
1836         {
1837           get_TOKEN(buf);
1838           TRACE("%s = %f\n", pt->members[i].name, *(float*)buf->value);
1839           /* Assume larger size */
1840           if ((buf->cur_pdata - buf->pxo->pdata + 4) > MAX_DATA_SIZE)
1841           {
1842             WARN("Buffer too small\n");
1843             return FALSE;
1844           }
1845           if (pt->members[i].type == TOKEN_FLOAT)
1846           {
1847             *(((float*)(buf->cur_pdata))) = (float)(*(float*)buf->value);
1848             buf->cur_pdata += 4;
1849           }
1850           else
1851           {
1852             FIXME("Token %d not supported\n", pt->members[i].type);
1853             return FALSE;
1854           }
1855         }
1856         else if (token == TOKEN_LPSTR)
1857         {
1858           static char fake_string[] = "Fake string";
1859           get_TOKEN(buf);
1860           TRACE("%s = %s\n", pt->members[i].name, (char*)buf->value);
1861           /* Assume larger size */
1862           if ((buf->cur_pdata - buf->pxo->pdata + 4) > MAX_DATA_SIZE)
1863           {
1864             WARN("Buffer too small\n");
1865             return FALSE;
1866           }
1867           if (pt->members[i].type == TOKEN_LPSTR)
1868           {
1869             /* Use a fake string for now */
1870             *(((LPCSTR*)(buf->cur_pdata))) = fake_string;
1871             buf->cur_pdata += 4;
1872           }
1873           else
1874           {
1875             FIXME("Token %d not supported\n", pt->members[i].type);
1876             return FALSE;
1877           }
1878         }
1879         else
1880         {
1881           FIXME("Unexpected token %d\n", token);
1882           return FALSE;
1883         }
1884       }
1885     }
1886
1887     token = get_TOKEN(buf);
1888     if (token != TOKEN_SEMICOLON)
1889     {
1890       /* Allow comma instead of semicolon in some specific cases */
1891       if (!((token == TOKEN_COMMA) && ((i+1) < pt->nb_members) && (pt->members[i].type == pt->members[i+1].type)
1892         && (!pt->members[i].nb_dims) && (!pt->members[i+1].nb_dims)))
1893         return FALSE;
1894     }
1895   }
1896
1897   return TRUE;
1898 }
1899
1900 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional)
1901 {
1902   if (!parse_object_members_list(buf))
1903     return FALSE;
1904
1905   if (allow_optional)
1906   {
1907     buf->pxo->size = buf->cur_pdata - buf->pxo->pdata;
1908
1909     /* Skip trailing semicolon */
1910     while (check_TOKEN(buf) == TOKEN_SEMICOLON)
1911       get_TOKEN(buf);
1912
1913     while (1)
1914     {
1915       if (check_TOKEN(buf) == TOKEN_OBRACE)
1916       {
1917         int i, j;
1918         get_TOKEN(buf);
1919         if (get_TOKEN(buf) != TOKEN_NAME)
1920           return FALSE;
1921         if (get_TOKEN(buf) != TOKEN_CBRACE)
1922           return FALSE;
1923         TRACE("Found optional reference %s\n", (char*)buf->value);
1924         for (i = 0; i < buf->nb_pxo_globals; i++)
1925         {
1926           for (j = 0; j < buf->pxo_globals[i*MAX_SUBOBJECTS].nb_subobjects; j++)
1927           {
1928             if (!strcmp(buf->pxo_globals[i*MAX_SUBOBJECTS+j].name, (char*)buf->value))
1929               goto _exit;
1930           }
1931         }
1932 _exit:
1933         if (i == buf->nb_pxo_globals)
1934         {
1935           ERR("Reference to unknown object %s\n", (char*)buf->value);
1936           return FALSE;
1937         }
1938         buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->cur_subobject++];
1939         buf->pxo->childs[buf->pxo->nb_childs]->ptarget = &buf->pxo_globals[i*MAX_SUBOBJECTS+j];
1940         buf->pxo->nb_childs++;
1941       }
1942       else if (check_TOKEN(buf) == TOKEN_NAME)
1943       {
1944         xobject* pxo = buf->pxo;
1945         buf->pxo = buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->cur_subobject++];
1946
1947         TRACE("Enter optional %s\n", (char*)buf->value);
1948         buf->level++;
1949         if (!parse_object(buf))
1950         {
1951           buf->level--;
1952           return FALSE;
1953         }
1954         buf->level--;
1955         buf->pxo = pxo;
1956         buf->pxo->nb_childs++;
1957       }
1958       else
1959         break;
1960     }
1961   }
1962
1963   return TRUE;
1964 }
1965
1966 static BOOL parse_object(parse_buffer * buf)
1967 {
1968   int i;
1969
1970   buf->pxo->pdata = buf->cur_pdata;
1971   buf->pxo->ptarget = NULL;
1972
1973   if (get_TOKEN(buf) != TOKEN_NAME)
1974     return FALSE;
1975
1976   /* To do template lookup */
1977   for (i = 0; i < buf->pdxf->nb_xtemplates; i++)
1978   {
1979     if (!strcmp((char*)buf->value, buf->pdxf->xtemplates[i].name))
1980     {
1981       buf->pxt[buf->level] = &buf->pdxf->xtemplates[i];
1982       memcpy(&buf->pxo->type, &buf->pdxf->xtemplates[i].class_id, 16);
1983       break;
1984     }
1985   }
1986   if (i == buf->pdxf->nb_xtemplates)
1987   {
1988     FIXME("Unknown template %s\n", (char*)buf->value);
1989     return FALSE;
1990   }
1991
1992   if (check_TOKEN(buf) == TOKEN_NAME)
1993   {
1994     get_TOKEN(buf);
1995     strcpy(buf->pxo->name, (char*)buf->value);
1996   }
1997   else
1998     buf->pxo->name[0] = 0;
1999
2000   if (get_TOKEN(buf) != TOKEN_OBRACE)
2001     return FALSE;
2002   if (check_TOKEN(buf) == TOKEN_GUID)
2003   {
2004     get_TOKEN(buf);
2005     memcpy(&buf->pxo->class_id, buf->value, 16);
2006   }
2007   else
2008     memset(&buf->pxo->class_id, 0, 16);
2009
2010   if (!parse_object_parts(buf, TRUE))
2011     return FALSE;
2012   if (get_TOKEN(buf) != TOKEN_CBRACE)
2013     return FALSE;
2014
2015   if (buf->txt)
2016   {
2017     /* Go to the next object */
2018     while (buf->rem_bytes && is_space(*buf->buffer))
2019     {
2020       buf->buffer++;
2021       buf->rem_bytes--;
2022     }
2023   }
2024
2025   return TRUE;
2026 }
2027
2028 /*** IDirectXFileEnumObject methods ***/
2029 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetNextDataObject(IDirectXFileEnumObject* iface, LPDIRECTXFILEDATA* ppDataObj)
2030 {
2031   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
2032   IDirectXFileDataImpl* object;
2033   HRESULT hr;
2034   LPBYTE pdata;
2035
2036   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
2037
2038   if (!This->buf.rem_bytes)
2039     return DXFILEERR_NOMOREOBJECTS;
2040
2041   hr = IDirectXFileDataImpl_Create(&object);
2042   if (FAILED(hr))
2043     return hr;
2044
2045   This->buf.pxo_globals = &This->xobjects[0][0];
2046   This->buf.nb_pxo_globals = This->nb_xobjects;
2047   This->buf.pxo_tab = &This->xobjects[This->nb_xobjects][0];
2048   This->buf.cur_subobject = 0;
2049   This->buf.pxo = &This->buf.pxo_tab[This->buf.cur_subobject++];
2050
2051   pdata = HeapAlloc(GetProcessHeap(), 0, MAX_DATA_SIZE);
2052   if (!pdata)
2053   {
2054     WARN("Out of memory\n");
2055     return DXFILEERR_BADALLOC;
2056   }
2057   This->buf.cur_pdata = pdata;
2058   This->buf.level = 0;
2059
2060   if (!parse_object(&This->buf))
2061   {
2062     TRACE("Object is not correct\n");
2063     HeapFree(GetProcessHeap(), 0, This->buf.pxo->pdata);
2064     return DXFILEERR_PARSEERROR;
2065   }
2066
2067   This->buf.pxo->nb_subobjects = This->buf.cur_subobject;
2068
2069   object->pobj = This->buf.pxo;
2070   object->cur_enum_object = 0;
2071   object->level = 0;
2072   object->from_ref = FALSE;
2073
2074   *ppDataObj = (LPDIRECTXFILEDATA)object;
2075
2076   This->nb_xobjects++;
2077
2078   return DXFILE_OK;
2079 }
2080
2081 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectById(IDirectXFileEnumObject* iface, REFGUID rguid, LPDIRECTXFILEDATA* ppDataObj)
2082 {
2083   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
2084
2085   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, rguid, ppDataObj); 
2086
2087   return DXFILEERR_BADVALUE;
2088 }
2089
2090 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectByName(IDirectXFileEnumObject* iface, LPCSTR szName, LPDIRECTXFILEDATA* ppDataObj)
2091 {
2092   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
2093
2094   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szName, ppDataObj); 
2095
2096   return DXFILEERR_BADVALUE;
2097 }
2098
2099 static const IDirectXFileEnumObjectVtbl IDirectXFileEnumObject_Vtbl =
2100 {
2101     IDirectXFileEnumObjectImpl_QueryInterface,
2102     IDirectXFileEnumObjectImpl_AddRef,
2103     IDirectXFileEnumObjectImpl_Release,
2104     IDirectXFileEnumObjectImpl_GetNextDataObject,
2105     IDirectXFileEnumObjectImpl_GetDataObjectById,
2106     IDirectXFileEnumObjectImpl_GetDataObjectByName
2107 };
2108
2109 HRESULT IDirectXFileObjectImpl_Create(IDirectXFileObjectImpl** ppObj)
2110 {
2111     IDirectXFileObjectImpl* object;
2112
2113     TRACE("(%p)\n", ppObj);
2114       
2115     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileObjectImpl));
2116     
2117     object->lpVtbl.lpVtbl = &IDirectXFileObject_Vtbl;
2118     object->ref = 1;
2119
2120     *ppObj = object;
2121     
2122     return S_OK;
2123 }
2124
2125 /*** IUnknown methods ***/
2126 static HRESULT WINAPI IDirectXFileObjectImpl_QueryInterface(IDirectXFileObject* iface, REFIID riid, void** ppvObject)
2127 {
2128   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2129
2130   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
2131
2132   if (IsEqualGUID(riid, &IID_IUnknown)
2133       || IsEqualGUID(riid, &IID_IDirectXFileObject))
2134   {
2135     IClassFactory_AddRef(iface);
2136     *ppvObject = This;
2137     return S_OK;
2138   }
2139
2140   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
2141   return E_NOINTERFACE;
2142 }
2143
2144 static ULONG WINAPI IDirectXFileObjectImpl_AddRef(IDirectXFileObject* iface)
2145 {
2146   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2147   ULONG ref = InterlockedIncrement(&This->ref);
2148
2149   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
2150
2151   return ref;
2152 }
2153
2154 static ULONG WINAPI IDirectXFileObjectImpl_Release(IDirectXFileObject* iface)
2155 {
2156   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2157   ULONG ref = InterlockedDecrement(&This->ref);
2158
2159   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
2160
2161   if (!ref)
2162     HeapFree(GetProcessHeap(), 0, This);
2163
2164   return ref;
2165 }
2166
2167 /*** IDirectXFileObject methods ***/
2168 static HRESULT WINAPI IDirectXFileObjectImpl_GetName(IDirectXFileObject* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
2169 {
2170   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
2171
2172   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pstrNameBuf, pdwBufLen); 
2173
2174   return DXFILEERR_BADVALUE;
2175 }
2176
2177 static HRESULT WINAPI IDirectXFileObjectImpl_GetId(IDirectXFileObject* iface, LPGUID pGuid)
2178 {
2179   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2180
2181   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pGuid); 
2182
2183   return DXFILEERR_BADVALUE;
2184 }
2185
2186 static const IDirectXFileObjectVtbl IDirectXFileObject_Vtbl =
2187 {
2188     IDirectXFileObjectImpl_QueryInterface,
2189     IDirectXFileObjectImpl_AddRef,
2190     IDirectXFileObjectImpl_Release,
2191     IDirectXFileObjectImpl_GetName,
2192     IDirectXFileObjectImpl_GetId
2193 };
2194
2195 HRESULT IDirectXFileSaveObjectImpl_Create(IDirectXFileSaveObjectImpl** ppObj)
2196 {
2197     IDirectXFileSaveObjectImpl* object;
2198
2199     TRACE("(%p)\n", ppObj);
2200
2201     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileSaveObjectImpl));
2202     
2203     object->lpVtbl.lpVtbl = &IDirectXFileSaveObject_Vtbl;
2204     object->ref = 1;
2205
2206     *ppObj = object;
2207     
2208     return S_OK;
2209 }
2210
2211 /*** IUnknown methods ***/
2212 static HRESULT WINAPI IDirectXFileSaveObjectImpl_QueryInterface(IDirectXFileSaveObject* iface, REFIID riid, void** ppvObject)
2213 {
2214   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2215
2216   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
2217
2218   if (IsEqualGUID(riid, &IID_IUnknown)
2219       || IsEqualGUID(riid, &IID_IDirectXFileSaveObject))
2220   {
2221     IClassFactory_AddRef(iface);
2222     *ppvObject = This;
2223     return S_OK;
2224   }
2225
2226   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
2227   return E_NOINTERFACE;
2228 }
2229
2230 static ULONG WINAPI IDirectXFileSaveObjectImpl_AddRef(IDirectXFileSaveObject* iface)
2231 {
2232   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2233   ULONG ref = InterlockedIncrement(&This->ref);
2234
2235   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
2236
2237   return ref;
2238 }
2239
2240 static ULONG WINAPI IDirectXFileSaveObjectImpl_Release(IDirectXFileSaveObject* iface)
2241 {
2242   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2243   ULONG ref = InterlockedDecrement(&This->ref);
2244
2245   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
2246
2247   if (!ref)
2248     HeapFree(GetProcessHeap(), 0, This);
2249
2250   return ref;
2251 }
2252
2253 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveTemplates(IDirectXFileSaveObject* iface, DWORD cTemplates, const GUID** ppguidTemplates)
2254 {
2255   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2256
2257   FIXME("(%p/%p)->(%d,%p) stub!\n", This, iface, cTemplates, ppguidTemplates);
2258
2259   return DXFILEERR_BADVALUE;
2260 }
2261
2262 static HRESULT WINAPI IDirectXFileSaveObjectImpl_CreateDataObject(IDirectXFileSaveObject* iface, REFGUID rguidTemplate, LPCSTR szName, const GUID* pguid, DWORD cbSize, LPVOID pvData, LPDIRECTXFILEDATA* ppDataObj)
2263 {
2264   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2265
2266   FIXME("(%p/%p)->(%p,%s,%p,%d,%p,%p) stub!\n", This, iface, rguidTemplate, szName, pguid, cbSize, pvData, ppDataObj);
2267
2268   return DXFILEERR_BADVALUE;
2269 }
2270
2271 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveData(IDirectXFileSaveObject* iface, LPDIRECTXFILEDATA ppDataObj)
2272 {
2273   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2274
2275   FIXME("(%p/%p)->(%p) stub!\n", This, iface, ppDataObj); 
2276
2277   return DXFILEERR_BADVALUE;
2278 }
2279
2280 static const IDirectXFileSaveObjectVtbl IDirectXFileSaveObject_Vtbl =
2281 {
2282     IDirectXFileSaveObjectImpl_QueryInterface,
2283     IDirectXFileSaveObjectImpl_AddRef,
2284     IDirectXFileSaveObjectImpl_Release,
2285     IDirectXFileSaveObjectImpl_SaveTemplates,
2286     IDirectXFileSaveObjectImpl_CreateDataObject,
2287     IDirectXFileSaveObjectImpl_SaveData
2288 };