quartz: Make some functions and variables static.
[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
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 void go_to_next_definition(parse_buffer * buf)
1181 {
1182   while (buf->rem_bytes)
1183   {
1184     char c = *buf->buffer;
1185     if ((c == '#') || (c == '/'))
1186     {
1187       read_bytes(buf, &c, 1);
1188       /* Handle comment (# or //) */
1189       if (c == '/')
1190       {
1191         if (!read_bytes(buf, &c, 1))
1192           return;
1193         if (c != '/')
1194           return;
1195       }
1196       c = 0;
1197       while (c != 0x0A)
1198       {
1199         if (!read_bytes(buf, &c, 1))
1200           return;
1201       }
1202       continue;
1203     }
1204     else if (is_space(*buf->buffer))
1205     {
1206       buf->buffer++;
1207       buf->rem_bytes--;
1208     }
1209     else
1210       break;
1211   }
1212 }
1213
1214 static BOOL parse_template(parse_buffer * buf)
1215 {
1216   if (get_TOKEN(buf) != TOKEN_TEMPLATE)
1217     return FALSE;
1218   if (get_TOKEN(buf) != TOKEN_NAME)
1219     return FALSE;
1220   strcpy(buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].name, (char*)buf->value);
1221   if (get_TOKEN(buf) != TOKEN_OBRACE)
1222     return FALSE;
1223   if (get_TOKEN(buf) != TOKEN_GUID)
1224     return FALSE;
1225   buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].class_id = *(GUID*)buf->value;
1226   if (!parse_template_parts(buf))
1227     return FALSE;
1228   if (get_TOKEN(buf) != TOKEN_CBRACE)
1229     return FALSE;
1230   if (buf->txt)
1231   {
1232     /* Go to the next template */
1233     go_to_next_definition(buf);
1234   }
1235
1236   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));
1237   buf->pdxf->nb_xtemplates++;
1238
1239   return TRUE;
1240 }
1241
1242 static HRESULT WINAPI IDirectXFileImpl_RegisterTemplates(IDirectXFile* iface, LPVOID pvData, DWORD cbSize)
1243 {
1244   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
1245   DWORD token_header;
1246   parse_buffer buf;
1247
1248   buf.buffer = (LPBYTE)pvData;
1249   buf.rem_bytes = cbSize;
1250   buf.txt = FALSE;
1251   buf.token_present = FALSE;
1252   buf.pdxf = This;
1253
1254   TRACE("(%p/%p)->(%p,%d)\n", This, iface, pvData, cbSize);
1255
1256   if (!pvData)
1257     return DXFILEERR_BADVALUE;
1258
1259   if (cbSize < 16)
1260     return DXFILEERR_BADFILETYPE;
1261
1262   if (TRACE_ON(d3dxof))
1263   {
1264     char string[17];
1265     memcpy(string, pvData, 16);
1266     string[16] = 0;
1267     TRACE("header = '%s'\n", string);
1268   }
1269
1270   read_bytes(&buf, &token_header, 4);
1271
1272   if (token_header != XOFFILE_FORMAT_MAGIC)
1273     return DXFILEERR_BADFILETYPE;
1274
1275   read_bytes(&buf, &token_header, 4);
1276
1277   if ((token_header != XOFFILE_FORMAT_VERSION_302) && (token_header != XOFFILE_FORMAT_VERSION_303))
1278     return DXFILEERR_BADFILEVERSION;
1279
1280   read_bytes(&buf, &token_header, 4);
1281
1282   if ((token_header != XOFFILE_FORMAT_BINARY) && (token_header != XOFFILE_FORMAT_TEXT) && (token_header != XOFFILE_FORMAT_COMPRESSED))
1283     return DXFILEERR_BADFILETYPE;
1284
1285   if (token_header == XOFFILE_FORMAT_TEXT)
1286   {
1287     buf.txt = TRUE;
1288   }
1289
1290   if (token_header == XOFFILE_FORMAT_COMPRESSED)
1291   {
1292     FIXME("Compressed formats not supported yet\n");
1293     return DXFILEERR_BADVALUE;
1294   }
1295
1296   read_bytes(&buf, &token_header, 4);
1297
1298   if ((token_header != XOFFILE_FORMAT_FLOAT_BITS_32) && (token_header != XOFFILE_FORMAT_FLOAT_BITS_64))
1299     return DXFILEERR_BADFILEFLOATSIZE;
1300
1301   TRACE("Header is correct\n");
1302
1303   while (buf.rem_bytes)
1304   {
1305     if (!parse_template(&buf))
1306     {
1307       TRACE("Template is not correct\n");
1308       return DXFILEERR_BADVALUE;
1309     }
1310     else
1311     {
1312       TRACE("Template successfully parsed:\n");
1313       if (TRACE_ON(d3dxof))
1314         dump_template(This->xtemplates, &This->xtemplates[This->nb_xtemplates - 1]);
1315     }
1316   }
1317
1318   if (TRACE_ON(d3dxof))
1319   {
1320     int i;
1321     TRACE("Registered templates (%d):\n", This->nb_xtemplates);
1322     for (i = 0; i < This->nb_xtemplates; i++)
1323       DPRINTF("%s - %s\n", This->xtemplates[i].name, debugstr_guid(&This->xtemplates[i].class_id));
1324   }
1325
1326   return DXFILE_OK;
1327 }
1328
1329 static const IDirectXFileVtbl IDirectXFile_Vtbl =
1330 {
1331   IDirectXFileImpl_QueryInterface,
1332   IDirectXFileImpl_AddRef,
1333   IDirectXFileImpl_Release,
1334   IDirectXFileImpl_CreateEnumObject,
1335   IDirectXFileImpl_CreateSaveObject,
1336   IDirectXFileImpl_RegisterTemplates
1337 };
1338
1339 HRESULT IDirectXFileBinaryImpl_Create(IDirectXFileBinaryImpl** ppObj)
1340 {
1341     IDirectXFileBinaryImpl* object;
1342
1343     TRACE("(%p)\n", ppObj);
1344       
1345     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileBinaryImpl));
1346     
1347     object->lpVtbl.lpVtbl = &IDirectXFileBinary_Vtbl;
1348     object->ref = 1;
1349
1350     *ppObj = object;
1351     
1352     return DXFILE_OK;
1353 }
1354
1355 /*** IUnknown methods ***/
1356 static HRESULT WINAPI IDirectXFileBinaryImpl_QueryInterface(IDirectXFileBinary* iface, REFIID riid, void** ppvObject)
1357 {
1358   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1359
1360   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1361
1362   if (IsEqualGUID(riid, &IID_IUnknown)
1363       || IsEqualGUID(riid, &IID_IDirectXFileObject)
1364       || IsEqualGUID(riid, &IID_IDirectXFileBinary))
1365   {
1366     IClassFactory_AddRef(iface);
1367     *ppvObject = This;
1368     return S_OK;
1369   }
1370
1371   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
1372   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
1373       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
1374     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1375
1376   return E_NOINTERFACE;
1377 }
1378
1379 static ULONG WINAPI IDirectXFileBinaryImpl_AddRef(IDirectXFileBinary* iface)
1380 {
1381   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1382   ULONG ref = InterlockedIncrement(&This->ref);
1383
1384   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1385
1386   return ref;
1387 }
1388
1389 static ULONG WINAPI IDirectXFileBinaryImpl_Release(IDirectXFileBinary* iface)
1390 {
1391   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1392   ULONG ref = InterlockedDecrement(&This->ref);
1393
1394   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1395
1396   if (!ref)
1397     HeapFree(GetProcessHeap(), 0, This);
1398
1399   return ref;
1400 }
1401
1402 /*** IDirectXFileObject methods ***/
1403 static HRESULT WINAPI IDirectXFileBinaryImpl_GetName(IDirectXFileBinary* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
1404
1405 {
1406   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1407
1408   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pstrNameBuf, pdwBufLen); 
1409
1410   return DXFILEERR_BADVALUE;
1411 }
1412
1413 static HRESULT WINAPI IDirectXFileBinaryImpl_GetId(IDirectXFileBinary* iface, LPGUID pGuid)
1414 {
1415   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1416
1417   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pGuid); 
1418
1419   return DXFILEERR_BADVALUE;
1420 }
1421
1422 /*** IDirectXFileBinary methods ***/
1423 static HRESULT WINAPI IDirectXFileBinaryImpl_GetSize(IDirectXFileBinary* iface, DWORD* pcbSize)
1424 {
1425   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1426
1427   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pcbSize); 
1428
1429   return DXFILEERR_BADVALUE;
1430 }
1431
1432 static HRESULT WINAPI IDirectXFileBinaryImpl_GetMimeType(IDirectXFileBinary* iface, LPCSTR* pszMimeType)
1433 {
1434   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1435
1436   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pszMimeType);
1437
1438   return DXFILEERR_BADVALUE;
1439 }
1440
1441 static HRESULT WINAPI IDirectXFileBinaryImpl_Read(IDirectXFileBinary* iface, LPVOID pvData, DWORD cbSize, LPDWORD pcbRead)
1442 {
1443   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
1444
1445   FIXME("(%p/%p)->(%p, %d, %p) stub!\n", This, iface, pvData, cbSize, pcbRead);
1446
1447   return DXFILEERR_BADVALUE;
1448 }
1449
1450 static const IDirectXFileBinaryVtbl IDirectXFileBinary_Vtbl =
1451 {
1452     IDirectXFileBinaryImpl_QueryInterface,
1453     IDirectXFileBinaryImpl_AddRef,
1454     IDirectXFileBinaryImpl_Release,
1455     IDirectXFileBinaryImpl_GetName,
1456     IDirectXFileBinaryImpl_GetId,
1457     IDirectXFileBinaryImpl_GetSize,
1458     IDirectXFileBinaryImpl_GetMimeType,
1459     IDirectXFileBinaryImpl_Read
1460 };
1461
1462 HRESULT IDirectXFileDataImpl_Create(IDirectXFileDataImpl** ppObj)
1463 {
1464     IDirectXFileDataImpl* object;
1465
1466     TRACE("(%p)\n", ppObj);
1467       
1468     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataImpl));
1469     
1470     object->lpVtbl.lpVtbl = &IDirectXFileData_Vtbl;
1471     object->ref = 1;
1472
1473     *ppObj = object;
1474     
1475     return S_OK;
1476 }
1477
1478 /*** IUnknown methods ***/
1479 static HRESULT WINAPI IDirectXFileDataImpl_QueryInterface(IDirectXFileData* iface, REFIID riid, void** ppvObject)
1480 {
1481   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1482
1483   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1484
1485   if (IsEqualGUID(riid, &IID_IUnknown)
1486       || IsEqualGUID(riid, &IID_IDirectXFileObject)
1487       || IsEqualGUID(riid, &IID_IDirectXFileData))
1488   {
1489     IClassFactory_AddRef(iface);
1490     *ppvObject = This;
1491     return S_OK;
1492   }
1493
1494   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
1495   if (!IsEqualGUID(riid, &IID_IDirectXFileBinary)
1496       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
1497     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1498
1499   return E_NOINTERFACE;
1500 }
1501
1502 static ULONG WINAPI IDirectXFileDataImpl_AddRef(IDirectXFileData* iface)
1503 {
1504   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1505   ULONG ref = InterlockedIncrement(&This->ref);
1506
1507   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1508
1509   return ref;
1510 }
1511
1512 static ULONG WINAPI IDirectXFileDataImpl_Release(IDirectXFileData* iface)
1513 {
1514   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1515   ULONG ref = InterlockedDecrement(&This->ref);
1516
1517   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1518
1519   if (!ref)
1520     HeapFree(GetProcessHeap(), 0, This);
1521
1522   return ref;
1523 }
1524
1525 /*** IDirectXFileObject methods ***/
1526 static HRESULT WINAPI IDirectXFileDataImpl_GetName(IDirectXFileData* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
1527
1528 {
1529   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1530
1531   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
1532
1533   if (!pstrNameBuf)
1534     return DXFILEERR_BADVALUE;
1535
1536   strcpy(pstrNameBuf, This->pobj->name);
1537
1538   return DXFILE_OK;
1539 }
1540
1541 static HRESULT WINAPI IDirectXFileDataImpl_GetId(IDirectXFileData* iface, LPGUID pGuid)
1542 {
1543   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1544
1545   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
1546
1547   if (!pGuid)
1548     return DXFILEERR_BADVALUE;
1549
1550   memcpy(pGuid, &This->pobj->class_id, 16);
1551
1552   return DXFILE_OK;
1553 }
1554
1555 /*** IDirectXFileData methods ***/
1556 static HRESULT WINAPI IDirectXFileDataImpl_GetData(IDirectXFileData* iface, LPCSTR szMember, DWORD* pcbSize, void** ppvData)
1557 {
1558   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1559
1560   TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, szMember, pcbSize, ppvData);
1561
1562   if (!pcbSize || !ppvData)
1563     return DXFILEERR_BADVALUE;
1564
1565   if (szMember)
1566   {
1567     FIXME("Specifying a member is not supported yet!\n");
1568     return DXFILEERR_BADVALUE;
1569   }
1570
1571   *pcbSize = This->pobj->size;
1572   *ppvData = This->pobj->pdata;
1573
1574   return DXFILE_OK;
1575 }
1576
1577 static HRESULT WINAPI IDirectXFileDataImpl_GetType(IDirectXFileData* iface, const GUID** pguid)
1578 {
1579   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1580   static GUID guid;
1581
1582   TRACE("(%p/%p)->(%p)\n", This, iface, pguid);
1583
1584   if (!pguid)
1585     return DXFILEERR_BADVALUE;
1586
1587   memcpy(&guid, &This->pobj->type, 16);
1588   *pguid = &guid;
1589
1590   return DXFILE_OK;
1591 }
1592
1593 static HRESULT WINAPI IDirectXFileDataImpl_GetNextObject(IDirectXFileData* iface, LPDIRECTXFILEOBJECT* ppChildObj)
1594 {
1595   HRESULT hr;
1596   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1597
1598   TRACE("(%p/%p)->(%p)\n", This, iface, ppChildObj);
1599
1600   if (This->cur_enum_object >= This->pobj->nb_childs)
1601     return DXFILEERR_NOMOREOBJECTS;
1602
1603   if (This->from_ref && (This->level >= 1))
1604   {
1605     /* Only 2 levels can enumerated if the object is obtained from a reference */
1606     return DXFILEERR_NOMOREOBJECTS;
1607   }
1608
1609   if (This->pobj->childs[This->cur_enum_object]->ptarget)
1610   {
1611     IDirectXFileDataReferenceImpl *object;
1612
1613     hr = IDirectXFileDataReferenceImpl_Create(&object);
1614     if (hr != S_OK)
1615       return DXFILEERR_BADVALUE;
1616
1617     object->ptarget = This->pobj->childs[This->cur_enum_object++]->ptarget;
1618
1619     *ppChildObj = (LPDIRECTXFILEOBJECT)object;
1620   }
1621   else
1622   {
1623     IDirectXFileDataImpl *object;
1624
1625     hr = IDirectXFileDataImpl_Create(&object);
1626     if (hr != S_OK)
1627       return DXFILEERR_BADVALUE;
1628
1629     object->pobj = This->pobj->childs[This->cur_enum_object++];
1630     object->cur_enum_object = 0;
1631     object->from_ref = This->from_ref;
1632     object->level = This->level + 1;
1633
1634     *ppChildObj = (LPDIRECTXFILEOBJECT)object;
1635   }
1636
1637   return DXFILE_OK;
1638 }
1639
1640 static HRESULT WINAPI IDirectXFileDataImpl_AddDataObject(IDirectXFileData* iface, LPDIRECTXFILEDATA pDataObj)
1641 {
1642   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1643
1644   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pDataObj); 
1645
1646   return DXFILEERR_BADVALUE;
1647 }
1648
1649 static HRESULT WINAPI IDirectXFileDataImpl_AddDataReference(IDirectXFileData* iface, LPCSTR szRef, const GUID* pguidRef)
1650 {
1651   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1652
1653   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szRef, pguidRef); 
1654
1655   return DXFILEERR_BADVALUE;
1656 }
1657
1658 static HRESULT WINAPI IDirectXFileDataImpl_AddBinaryObject(IDirectXFileData* iface, LPCSTR szName, const GUID* pguid, LPCSTR szMimeType, LPVOID pvData, DWORD cbSize)
1659 {
1660   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
1661
1662   FIXME("(%p/%p)->(%s,%p,%s,%p,%d) stub!\n", This, iface, szName, pguid, szMimeType, pvData, cbSize);
1663
1664   return DXFILEERR_BADVALUE;
1665 }
1666
1667 static const IDirectXFileDataVtbl IDirectXFileData_Vtbl =
1668 {
1669     IDirectXFileDataImpl_QueryInterface,
1670     IDirectXFileDataImpl_AddRef,
1671     IDirectXFileDataImpl_Release,
1672     IDirectXFileDataImpl_GetName,
1673     IDirectXFileDataImpl_GetId,
1674     IDirectXFileDataImpl_GetData,
1675     IDirectXFileDataImpl_GetType,
1676     IDirectXFileDataImpl_GetNextObject,
1677     IDirectXFileDataImpl_AddDataObject,
1678     IDirectXFileDataImpl_AddDataReference,
1679     IDirectXFileDataImpl_AddBinaryObject
1680 };
1681
1682 HRESULT IDirectXFileDataReferenceImpl_Create(IDirectXFileDataReferenceImpl** ppObj)
1683 {
1684     IDirectXFileDataReferenceImpl* object;
1685
1686     TRACE("(%p)\n", ppObj);
1687       
1688     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataReferenceImpl));
1689     
1690     object->lpVtbl.lpVtbl = &IDirectXFileDataReference_Vtbl;
1691     object->ref = 1;
1692
1693     *ppObj = object;
1694     
1695     return S_OK;
1696 }
1697
1698 /*** IUnknown methods ***/
1699 static HRESULT WINAPI IDirectXFileDataReferenceImpl_QueryInterface(IDirectXFileDataReference* iface, REFIID riid, void** ppvObject)
1700 {
1701   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1702
1703   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1704
1705   if (IsEqualGUID(riid, &IID_IUnknown)
1706       || IsEqualGUID(riid, &IID_IDirectXFileObject)
1707       || IsEqualGUID(riid, &IID_IDirectXFileDataReference))
1708   {
1709     IClassFactory_AddRef(iface);
1710     *ppvObject = This;
1711     return S_OK;
1712   }
1713
1714   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
1715   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
1716       && !IsEqualGUID(riid, &IID_IDirectXFileBinary))
1717     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1718
1719   return E_NOINTERFACE;
1720 }
1721
1722 static ULONG WINAPI IDirectXFileDataReferenceImpl_AddRef(IDirectXFileDataReference* iface)
1723 {
1724   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1725   ULONG ref = InterlockedIncrement(&This->ref);
1726
1727   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1728
1729   return ref;
1730 }
1731
1732 static ULONG WINAPI IDirectXFileDataReferenceImpl_Release(IDirectXFileDataReference* iface)
1733 {
1734   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1735   ULONG ref = InterlockedDecrement(&This->ref);
1736
1737   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1738
1739   if (!ref)
1740     HeapFree(GetProcessHeap(), 0, This);
1741
1742   return ref;
1743 }
1744
1745 /*** IDirectXFileObject methods ***/
1746 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetName(IDirectXFileDataReference* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
1747 {
1748   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1749
1750   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
1751
1752   if (!pstrNameBuf)
1753     return DXFILEERR_BADVALUE;
1754
1755   strcpy(pstrNameBuf, This->ptarget->name);
1756
1757   return DXFILEERR_BADVALUE;
1758 }
1759
1760 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetId(IDirectXFileDataReference* iface, LPGUID pGuid)
1761 {
1762   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1763
1764   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
1765
1766   if (!pGuid)
1767     return DXFILEERR_BADVALUE;
1768
1769   memcpy(pGuid, &This->ptarget->class_id, 16);
1770
1771   return DXFILE_OK;
1772 }
1773
1774 /*** IDirectXFileDataReference ***/
1775 static HRESULT WINAPI IDirectXFileDataReferenceImpl_Resolve(IDirectXFileDataReference* iface, LPDIRECTXFILEDATA* ppDataObj)
1776 {
1777   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
1778   IDirectXFileDataImpl *object;
1779   HRESULT hr;
1780
1781   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
1782
1783   if (!ppDataObj)
1784     return DXFILEERR_BADVALUE;
1785
1786   hr = IDirectXFileDataImpl_Create(&object);
1787   if (hr != S_OK)
1788     return DXFILEERR_BADVALUE;
1789
1790   object->pobj = This->ptarget;
1791   object->cur_enum_object = 0;
1792   object->level = 0;
1793   object->from_ref = TRUE;
1794
1795   *ppDataObj = (LPDIRECTXFILEDATA)object;
1796
1797   return DXFILE_OK;
1798 }
1799
1800 static const IDirectXFileDataReferenceVtbl IDirectXFileDataReference_Vtbl =
1801 {
1802     IDirectXFileDataReferenceImpl_QueryInterface,
1803     IDirectXFileDataReferenceImpl_AddRef,
1804     IDirectXFileDataReferenceImpl_Release,
1805     IDirectXFileDataReferenceImpl_GetName,
1806     IDirectXFileDataReferenceImpl_GetId,
1807     IDirectXFileDataReferenceImpl_Resolve
1808 };
1809
1810 HRESULT IDirectXFileEnumObjectImpl_Create(IDirectXFileEnumObjectImpl** ppObj)
1811 {
1812     IDirectXFileEnumObjectImpl* object;
1813
1814     TRACE("(%p)\n", ppObj);
1815       
1816     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileEnumObjectImpl));
1817     
1818     object->lpVtbl.lpVtbl = &IDirectXFileEnumObject_Vtbl;
1819     object->ref = 1;
1820
1821     *ppObj = object;
1822     
1823     return S_OK;
1824 }
1825
1826 /*** IUnknown methods ***/
1827 static HRESULT WINAPI IDirectXFileEnumObjectImpl_QueryInterface(IDirectXFileEnumObject* iface, REFIID riid, void** ppvObject)
1828 {
1829   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1830
1831   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1832
1833   if (IsEqualGUID(riid, &IID_IUnknown)
1834       || IsEqualGUID(riid, &IID_IDirectXFileEnumObject))
1835   {
1836     IClassFactory_AddRef(iface);
1837     *ppvObject = This;
1838     return S_OK;
1839   }
1840
1841   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1842   return E_NOINTERFACE;
1843 }
1844
1845 static ULONG WINAPI IDirectXFileEnumObjectImpl_AddRef(IDirectXFileEnumObject* iface)
1846 {
1847   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1848   ULONG ref = InterlockedIncrement(&This->ref);
1849
1850   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1851
1852   return ref;
1853 }
1854
1855 static ULONG WINAPI IDirectXFileEnumObjectImpl_Release(IDirectXFileEnumObject* iface)
1856 {
1857   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1858   ULONG ref = InterlockedDecrement(&This->ref);
1859
1860   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1861
1862   if (!ref)
1863   {
1864     CloseHandle(This->hFile);
1865     HeapFree(GetProcessHeap(), 0, This);
1866   }
1867
1868   return ref;
1869 }
1870
1871 static BOOL parse_object_members_list(parse_buffer * buf)
1872 {
1873   DWORD token;
1874   int i;
1875   xtemplate* pt = buf->pxt[buf->level];
1876   DWORD last_dword = 0;
1877
1878   for (i = 0; i < pt->nb_members; i++)
1879   {
1880     int k;
1881     int nb_elems = 1;
1882
1883     buf->pxo->members[i].start = buf->cur_pdata;
1884
1885     for (k = 0; k < pt->members[i].nb_dims; k++)
1886     {
1887       if (pt->members[i].dim_fixed[k])
1888         nb_elems *= pt->members[i].dim_value[k];
1889       else
1890         nb_elems *= *(DWORD*)buf->pxo->members[pt->members[i].dim_value[k]].start;
1891     }
1892
1893     TRACE("Elements to consider: %d\n", nb_elems);
1894
1895     for (k = 0; k < nb_elems; k++)
1896     {
1897       if (buf->txt && k)
1898       {
1899         token = check_TOKEN(buf);
1900         if (token == TOKEN_COMMA)
1901         {
1902           get_TOKEN(buf);
1903         }
1904         else
1905         {
1906           /* Allow comma omission */
1907           if (!((token == TOKEN_FLOAT) || (token == TOKEN_INTEGER)))
1908             return FALSE;
1909         }
1910       }
1911
1912       if (pt->members[i].type == TOKEN_NAME)
1913       {
1914         int j;
1915
1916         TRACE("Found sub-object %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1917         buf->level++;
1918         /* To do template lookup */
1919         for (j = 0; j < buf->pdxf->nb_xtemplates; j++)
1920         {
1921           if (!strcmp(buf->pdxf->xtemplates[pt->members[i].idx_template].name, buf->pdxf->xtemplates[j].name))
1922           {
1923             buf->pxt[buf->level] = &buf->pdxf->xtemplates[j];
1924             break;
1925           }
1926         }
1927         if (j == buf->pdxf->nb_xtemplates)
1928         {
1929           FIXME("Unknown template %s\n", (char*)buf->value);
1930           buf->level--;
1931           return FALSE;
1932         }
1933         TRACE("Enter %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name);
1934         if (!parse_object_parts(buf, FALSE))
1935         {
1936           buf->level--;
1937           return FALSE;
1938         }
1939         buf->level--;
1940       }
1941       else
1942       {
1943         token = check_TOKEN(buf);
1944         if (token == TOKEN_INTEGER)
1945         {
1946           get_TOKEN(buf);
1947           last_dword = *(DWORD*)buf->value;
1948           TRACE("%s = %d\n", pt->members[i].name, *(DWORD*)buf->value);
1949           /* Assume larger size */
1950           if ((buf->cur_pdata - buf->pdata + 4) > MAX_DATA_SIZE)
1951           {
1952             FIXME("Buffer too small\n");
1953             return FALSE;
1954           }
1955           if (pt->members[i].type == TOKEN_WORD)
1956           {
1957             *(((WORD*)(buf->cur_pdata))) = (WORD)(*(DWORD*)buf->value);
1958             buf->cur_pdata += 2;
1959           }
1960           else if (pt->members[i].type == TOKEN_DWORD)
1961           {
1962             *(((DWORD*)(buf->cur_pdata))) = (DWORD)(*(DWORD*)buf->value);
1963             buf->cur_pdata += 4;
1964           }
1965           else
1966           {
1967             FIXME("Token %d not supported\n", pt->members[i].type);
1968             return FALSE;
1969           }
1970         }
1971         else if (token == TOKEN_FLOAT)
1972         {
1973           get_TOKEN(buf);
1974           TRACE("%s = %f\n", pt->members[i].name, *(float*)buf->value);
1975           /* Assume larger size */
1976           if ((buf->cur_pdata - buf->pdata + 4) > MAX_DATA_SIZE)
1977           {
1978             FIXME("Buffer too small\n");
1979             return FALSE;
1980           }
1981           if (pt->members[i].type == TOKEN_FLOAT)
1982           {
1983             *(((float*)(buf->cur_pdata))) = (float)(*(float*)buf->value);
1984             buf->cur_pdata += 4;
1985           }
1986           else
1987           {
1988             FIXME("Token %d not supported\n", pt->members[i].type);
1989             return FALSE;
1990           }
1991         }
1992         else if (token == TOKEN_LPSTR)
1993         {
1994           get_TOKEN(buf);
1995           TRACE("%s = %s\n", pt->members[i].name, (char*)buf->value);
1996           /* Assume larger size */
1997           if ((buf->cur_pdata - buf->pdata + 4) > MAX_DATA_SIZE)
1998           {
1999             FIXME("Buffer too small\n");
2000             return FALSE;
2001           }
2002           if (pt->members[i].type == TOKEN_LPSTR)
2003           {
2004             int len = strlen((char*)buf->value) + 1;
2005             if ((buf->cur_pstrings - buf->pstrings + len) > MAX_STRINGS_BUFFER)
2006             {
2007               FIXME("Buffer too small %p %p %d\n", buf->cur_pstrings, buf->pstrings, len);
2008               return FALSE;
2009             }
2010             strcpy((char*)buf->cur_pstrings, (char*)buf->value);
2011             *(((LPCSTR*)(buf->cur_pdata))) = (char*)buf->cur_pstrings;
2012             buf->cur_pstrings += len;
2013             buf->cur_pdata += 4;
2014           }
2015           else
2016           {
2017             FIXME("Token %d not supported\n", pt->members[i].type);
2018             return FALSE;
2019           }
2020         }
2021         else
2022         {
2023           FIXME("Unexpected token %d\n", token);
2024           return FALSE;
2025         }
2026       }
2027     }
2028
2029     if (buf->txt && (check_TOKEN(buf) != TOKEN_CBRACE))
2030     {
2031       token = get_TOKEN(buf);
2032       if ((token != TOKEN_SEMICOLON) && (token != TOKEN_COMMA))
2033       {
2034         /* Allow comma instead of semicolon in some specific cases */
2035         if (!((token == TOKEN_COMMA) && ((i+1) < pt->nb_members) && (pt->members[i].type == pt->members[i+1].type)
2036           && (!pt->members[i].nb_dims) && (!pt->members[i+1].nb_dims)))
2037           return FALSE;
2038       }
2039     }
2040   }
2041
2042   return TRUE;
2043 }
2044
2045 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional)
2046 {
2047   if (!parse_object_members_list(buf))
2048     return FALSE;
2049
2050   if (allow_optional)
2051   {
2052     buf->pxo->size = buf->cur_pdata - buf->pxo->pdata;
2053
2054     /* Skip trailing semicolon */
2055     while (check_TOKEN(buf) == TOKEN_SEMICOLON)
2056       get_TOKEN(buf);
2057
2058     while (1)
2059     {
2060       if (check_TOKEN(buf) == TOKEN_OBRACE)
2061       {
2062         int i, j;
2063         get_TOKEN(buf);
2064         if (get_TOKEN(buf) != TOKEN_NAME)
2065           return FALSE;
2066         if (get_TOKEN(buf) != TOKEN_CBRACE)
2067           return FALSE;
2068         TRACE("Found optional reference %s\n", (char*)buf->value);
2069         for (i = 0; i < buf->nb_pxo_globals; i++)
2070         {
2071           for (j = 0; j < buf->pxo_globals[i*MAX_SUBOBJECTS].nb_subobjects; j++)
2072           {
2073             if (!strcmp(buf->pxo_globals[i*MAX_SUBOBJECTS+j].name, (char*)buf->value))
2074               goto _exit;
2075           }
2076         }
2077 _exit:
2078         if (i == buf->nb_pxo_globals)
2079         {
2080           ERR("Reference to unknown object %s\n", (char*)buf->value);
2081           return FALSE;
2082         }
2083         buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->cur_subobject++];
2084         buf->pxo->childs[buf->pxo->nb_childs]->ptarget = &buf->pxo_globals[i*MAX_SUBOBJECTS+j];
2085         buf->pxo->nb_childs++;
2086       }
2087       else if (check_TOKEN(buf) == TOKEN_NAME)
2088       {
2089         xobject* pxo = buf->pxo;
2090         buf->pxo = buf->pxo->childs[buf->pxo->nb_childs] = &buf->pxo_tab[buf->cur_subobject++];
2091
2092         TRACE("Enter optional %s\n", (char*)buf->value);
2093         buf->level++;
2094         if (!parse_object(buf))
2095         {
2096           buf->level--;
2097           return FALSE;
2098         }
2099         buf->level--;
2100         buf->pxo = pxo;
2101         buf->pxo->nb_childs++;
2102       }
2103       else
2104         break;
2105     }
2106   }
2107
2108   if (buf->pxo->nb_childs > MAX_CHILDS)
2109   {
2110     FIXME("Too many childs %d\n", buf->pxo->nb_childs);
2111     return FALSE;
2112   }
2113
2114   return TRUE;
2115 }
2116
2117 static BOOL parse_object(parse_buffer * buf)
2118 {
2119   int i;
2120
2121   buf->pxo->pdata = buf->cur_pdata;
2122   buf->pxo->ptarget = NULL;
2123
2124   if (get_TOKEN(buf) != TOKEN_NAME)
2125     return FALSE;
2126
2127   /* To do template lookup */
2128   for (i = 0; i < buf->pdxf->nb_xtemplates; i++)
2129   {
2130     if (!strcmp((char*)buf->value, buf->pdxf->xtemplates[i].name))
2131     {
2132       buf->pxt[buf->level] = &buf->pdxf->xtemplates[i];
2133       memcpy(&buf->pxo->type, &buf->pdxf->xtemplates[i].class_id, 16);
2134       break;
2135     }
2136   }
2137   if (i == buf->pdxf->nb_xtemplates)
2138   {
2139     FIXME("Unknown template %s\n", (char*)buf->value);
2140     return FALSE;
2141   }
2142
2143   if (check_TOKEN(buf) == TOKEN_NAME)
2144   {
2145     get_TOKEN(buf);
2146     strcpy(buf->pxo->name, (char*)buf->value);
2147   }
2148   else
2149     buf->pxo->name[0] = 0;
2150
2151   if (get_TOKEN(buf) != TOKEN_OBRACE)
2152     return FALSE;
2153   if (check_TOKEN(buf) == TOKEN_GUID)
2154   {
2155     get_TOKEN(buf);
2156     memcpy(&buf->pxo->class_id, buf->value, 16);
2157   }
2158   else
2159     memset(&buf->pxo->class_id, 0, 16);
2160
2161   if (!parse_object_parts(buf, TRUE))
2162     return FALSE;
2163   if (get_TOKEN(buf) != TOKEN_CBRACE)
2164     return FALSE;
2165
2166   if (buf->txt)
2167   {
2168     /* Go to the next object */
2169     go_to_next_definition(buf);
2170   }
2171
2172   return TRUE;
2173 }
2174
2175 /*** IDirectXFileEnumObject methods ***/
2176 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetNextDataObject(IDirectXFileEnumObject* iface, LPDIRECTXFILEDATA* ppDataObj)
2177 {
2178   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
2179   IDirectXFileDataImpl* object;
2180   HRESULT hr;
2181   LPBYTE pdata;
2182   LPBYTE pstrings;
2183
2184   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
2185
2186   if (This->nb_xobjects >= MAX_OBJECTS)
2187   {
2188     ERR("Too many objects\n");
2189     return DXFILEERR_NOMOREOBJECTS;
2190   }
2191
2192   if (!This->buf.rem_bytes)
2193     return DXFILEERR_NOMOREOBJECTS;
2194
2195   hr = IDirectXFileDataImpl_Create(&object);
2196   if (FAILED(hr))
2197     return hr;
2198
2199   This->buf.pxo_globals = &This->xobjects[0][0];
2200   This->buf.nb_pxo_globals = This->nb_xobjects;
2201   This->buf.pxo_tab = &This->xobjects[This->nb_xobjects][0];
2202   This->buf.cur_subobject = 0;
2203   This->buf.pxo = &This->buf.pxo_tab[This->buf.cur_subobject++];
2204   This->buf.level = 0;
2205
2206   pdata = HeapAlloc(GetProcessHeap(), 0, MAX_DATA_SIZE);
2207   if (!pdata)
2208   {
2209     WARN("Out of memory\n");
2210     return DXFILEERR_BADALLOC;
2211   }
2212   This->buf.cur_pdata = This->buf.pdata = pdata;
2213
2214   pstrings = HeapAlloc(GetProcessHeap(), 0, MAX_STRINGS_BUFFER);
2215   if (!pstrings)
2216   {
2217     WARN("Out of memory\n");
2218     HeapFree(GetProcessHeap(), 0, This->buf.pxo->pdata);
2219     return DXFILEERR_BADALLOC;
2220   }
2221   This->buf.cur_pstrings = This->buf.pstrings = pstrings;
2222
2223   if (!parse_object(&This->buf))
2224   {
2225     TRACE("Object is not correct\n");
2226     HeapFree(GetProcessHeap(), 0, This->buf.pxo->pdata);
2227     HeapFree(GetProcessHeap(), 0, This->buf.pstrings);
2228     return DXFILEERR_PARSEERROR;
2229   }
2230
2231   This->buf.pxo->nb_subobjects = This->buf.cur_subobject;
2232   if (This->buf.cur_subobject > MAX_SUBOBJECTS)
2233   {
2234     FIXME("Too many suobjects %d\n", This->buf.cur_subobject);
2235     return DXFILEERR_BADALLOC;
2236   }
2237
2238   object->pstrings = pstrings;
2239   object->pobj = This->buf.pxo;
2240   object->cur_enum_object = 0;
2241   object->level = 0;
2242   object->from_ref = FALSE;
2243
2244   *ppDataObj = (LPDIRECTXFILEDATA)object;
2245
2246   This->nb_xobjects++;
2247
2248   return DXFILE_OK;
2249 }
2250
2251 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectById(IDirectXFileEnumObject* iface, REFGUID rguid, LPDIRECTXFILEDATA* ppDataObj)
2252 {
2253   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
2254
2255   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, rguid, ppDataObj); 
2256
2257   return DXFILEERR_BADVALUE;
2258 }
2259
2260 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectByName(IDirectXFileEnumObject* iface, LPCSTR szName, LPDIRECTXFILEDATA* ppDataObj)
2261 {
2262   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
2263
2264   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szName, ppDataObj); 
2265
2266   return DXFILEERR_BADVALUE;
2267 }
2268
2269 static const IDirectXFileEnumObjectVtbl IDirectXFileEnumObject_Vtbl =
2270 {
2271     IDirectXFileEnumObjectImpl_QueryInterface,
2272     IDirectXFileEnumObjectImpl_AddRef,
2273     IDirectXFileEnumObjectImpl_Release,
2274     IDirectXFileEnumObjectImpl_GetNextDataObject,
2275     IDirectXFileEnumObjectImpl_GetDataObjectById,
2276     IDirectXFileEnumObjectImpl_GetDataObjectByName
2277 };
2278
2279 HRESULT IDirectXFileObjectImpl_Create(IDirectXFileObjectImpl** ppObj)
2280 {
2281     IDirectXFileObjectImpl* object;
2282
2283     TRACE("(%p)\n", ppObj);
2284       
2285     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileObjectImpl));
2286     
2287     object->lpVtbl.lpVtbl = &IDirectXFileObject_Vtbl;
2288     object->ref = 1;
2289
2290     *ppObj = object;
2291     
2292     return S_OK;
2293 }
2294
2295 /*** IUnknown methods ***/
2296 static HRESULT WINAPI IDirectXFileObjectImpl_QueryInterface(IDirectXFileObject* iface, REFIID riid, void** ppvObject)
2297 {
2298   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2299
2300   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
2301
2302   if (IsEqualGUID(riid, &IID_IUnknown)
2303       || IsEqualGUID(riid, &IID_IDirectXFileObject))
2304   {
2305     IClassFactory_AddRef(iface);
2306     *ppvObject = This;
2307     return S_OK;
2308   }
2309
2310   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
2311   return E_NOINTERFACE;
2312 }
2313
2314 static ULONG WINAPI IDirectXFileObjectImpl_AddRef(IDirectXFileObject* iface)
2315 {
2316   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2317   ULONG ref = InterlockedIncrement(&This->ref);
2318
2319   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
2320
2321   return ref;
2322 }
2323
2324 static ULONG WINAPI IDirectXFileObjectImpl_Release(IDirectXFileObject* iface)
2325 {
2326   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2327   ULONG ref = InterlockedDecrement(&This->ref);
2328
2329   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
2330
2331   if (!ref)
2332     HeapFree(GetProcessHeap(), 0, This);
2333
2334   return ref;
2335 }
2336
2337 /*** IDirectXFileObject methods ***/
2338 static HRESULT WINAPI IDirectXFileObjectImpl_GetName(IDirectXFileObject* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
2339 {
2340   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
2341
2342   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pstrNameBuf, pdwBufLen); 
2343
2344   return DXFILEERR_BADVALUE;
2345 }
2346
2347 static HRESULT WINAPI IDirectXFileObjectImpl_GetId(IDirectXFileObject* iface, LPGUID pGuid)
2348 {
2349   IDirectXFileObjectImpl *This = (IDirectXFileObjectImpl *)iface;
2350
2351   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pGuid); 
2352
2353   return DXFILEERR_BADVALUE;
2354 }
2355
2356 static const IDirectXFileObjectVtbl IDirectXFileObject_Vtbl =
2357 {
2358     IDirectXFileObjectImpl_QueryInterface,
2359     IDirectXFileObjectImpl_AddRef,
2360     IDirectXFileObjectImpl_Release,
2361     IDirectXFileObjectImpl_GetName,
2362     IDirectXFileObjectImpl_GetId
2363 };
2364
2365 HRESULT IDirectXFileSaveObjectImpl_Create(IDirectXFileSaveObjectImpl** ppObj)
2366 {
2367     IDirectXFileSaveObjectImpl* object;
2368
2369     TRACE("(%p)\n", ppObj);
2370
2371     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileSaveObjectImpl));
2372     
2373     object->lpVtbl.lpVtbl = &IDirectXFileSaveObject_Vtbl;
2374     object->ref = 1;
2375
2376     *ppObj = object;
2377     
2378     return S_OK;
2379 }
2380
2381 /*** IUnknown methods ***/
2382 static HRESULT WINAPI IDirectXFileSaveObjectImpl_QueryInterface(IDirectXFileSaveObject* iface, REFIID riid, void** ppvObject)
2383 {
2384   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2385
2386   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
2387
2388   if (IsEqualGUID(riid, &IID_IUnknown)
2389       || IsEqualGUID(riid, &IID_IDirectXFileSaveObject))
2390   {
2391     IClassFactory_AddRef(iface);
2392     *ppvObject = This;
2393     return S_OK;
2394   }
2395
2396   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
2397   return E_NOINTERFACE;
2398 }
2399
2400 static ULONG WINAPI IDirectXFileSaveObjectImpl_AddRef(IDirectXFileSaveObject* iface)
2401 {
2402   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2403   ULONG ref = InterlockedIncrement(&This->ref);
2404
2405   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
2406
2407   return ref;
2408 }
2409
2410 static ULONG WINAPI IDirectXFileSaveObjectImpl_Release(IDirectXFileSaveObject* iface)
2411 {
2412   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2413   ULONG ref = InterlockedDecrement(&This->ref);
2414
2415   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
2416
2417   if (!ref)
2418     HeapFree(GetProcessHeap(), 0, This);
2419
2420   return ref;
2421 }
2422
2423 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveTemplates(IDirectXFileSaveObject* iface, DWORD cTemplates, const GUID** ppguidTemplates)
2424 {
2425   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2426
2427   FIXME("(%p/%p)->(%d,%p) stub!\n", This, iface, cTemplates, ppguidTemplates);
2428
2429   return DXFILEERR_BADVALUE;
2430 }
2431
2432 static HRESULT WINAPI IDirectXFileSaveObjectImpl_CreateDataObject(IDirectXFileSaveObject* iface, REFGUID rguidTemplate, LPCSTR szName, const GUID* pguid, DWORD cbSize, LPVOID pvData, LPDIRECTXFILEDATA* ppDataObj)
2433 {
2434   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2435
2436   FIXME("(%p/%p)->(%p,%s,%p,%d,%p,%p) stub!\n", This, iface, rguidTemplate, szName, pguid, cbSize, pvData, ppDataObj);
2437
2438   return DXFILEERR_BADVALUE;
2439 }
2440
2441 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveData(IDirectXFileSaveObject* iface, LPDIRECTXFILEDATA ppDataObj)
2442 {
2443   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
2444
2445   FIXME("(%p/%p)->(%p) stub!\n", This, iface, ppDataObj); 
2446
2447   return DXFILEERR_BADVALUE;
2448 }
2449
2450 static const IDirectXFileSaveObjectVtbl IDirectXFileSaveObject_Vtbl =
2451 {
2452     IDirectXFileSaveObjectImpl_QueryInterface,
2453     IDirectXFileSaveObjectImpl_AddRef,
2454     IDirectXFileSaveObjectImpl_Release,
2455     IDirectXFileSaveObjectImpl_SaveTemplates,
2456     IDirectXFileSaveObjectImpl_CreateDataObject,
2457     IDirectXFileSaveObjectImpl_SaveData
2458 };