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