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