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