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