d3dxof: Turn some TRACEs into WARNs in case of parsing error.
[wine] / dlls / d3dxof / d3dxof.c
1 /*
2  * Implementation of DirectX File Interfaces
3  *
4  * Copyright 2004, 2008 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/debug.h"
23
24 #define COBJMACROS
25
26 #include "winbase.h"
27 #include "wingdi.h"
28
29 #include "d3dxof_private.h"
30 #include "dxfile.h"
31
32 #include <stdio.h>
33
34 WINE_DEFAULT_DEBUG_CHANNEL(d3dxof);
35
36 #define MAKEFOUR(a,b,c,d) ((DWORD)a + ((DWORD)b << 8) + ((DWORD)c << 16) + ((DWORD)d << 24))
37 #define XOFFILE_FORMAT_MAGIC         MAKEFOUR('x','o','f',' ')
38 #define XOFFILE_FORMAT_VERSION_302   MAKEFOUR('0','3','0','2')
39 #define XOFFILE_FORMAT_VERSION_303   MAKEFOUR('0','3','0','3')
40 #define XOFFILE_FORMAT_BINARY        MAKEFOUR('b','i','n',' ')
41 #define XOFFILE_FORMAT_TEXT          MAKEFOUR('t','x','t',' ')
42 #define XOFFILE_FORMAT_BINARY_MSZIP  MAKEFOUR('b','z','i','p')
43 #define XOFFILE_FORMAT_TEXT_MSZIP    MAKEFOUR('t','z','i','p')
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 static const struct IDirectXFileVtbl IDirectXFile_Vtbl;
49 static const struct IDirectXFileBinaryVtbl IDirectXFileBinary_Vtbl;
50 static const struct IDirectXFileDataVtbl IDirectXFileData_Vtbl;
51 static const struct IDirectXFileDataReferenceVtbl IDirectXFileDataReference_Vtbl;
52 static const struct IDirectXFileEnumObjectVtbl IDirectXFileEnumObject_Vtbl;
53 static const struct IDirectXFileObjectVtbl IDirectXFileObject_Vtbl;
54 static const struct IDirectXFileSaveObjectVtbl IDirectXFileSaveObject_Vtbl;
55
56 static HRESULT IDirectXFileDataReferenceImpl_Create(IDirectXFileDataReferenceImpl** ppObj);
57 static HRESULT IDirectXFileEnumObjectImpl_Create(IDirectXFileEnumObjectImpl** ppObj);
58 static HRESULT IDirectXFileSaveObjectImpl_Create(IDirectXFileSaveObjectImpl** ppObj);
59
60 /* FOURCC to string conversion for debug messages */
61 const char *debugstr_fourcc(DWORD fourcc)
62 {
63     if (!fourcc) return "'null'";
64     return wine_dbg_sprintf ("\'%c%c%c%c\'",
65                 (char)(fourcc), (char)(fourcc >> 8),
66         (char)(fourcc >> 16), (char)(fourcc >> 24));
67 }
68
69 HRESULT IDirectXFileImpl_Create(IUnknown* pUnkOuter, LPVOID* ppObj)
70 {
71     IDirectXFileImpl* object;
72
73     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
74       
75     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileImpl));
76     if (!object)
77     {
78         ERR("Out of memory\n");
79         return DXFILEERR_BADALLOC;
80     }
81
82     object->lpVtbl = &IDirectXFile_Vtbl;
83     object->ref = 1;
84
85     *ppObj = object;
86     
87     return S_OK;
88 }
89
90 /*** IUnknown methods ***/
91 static HRESULT WINAPI IDirectXFileImpl_QueryInterface(IDirectXFile* iface, REFIID riid, void** ppvObject)
92 {
93   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
94
95   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
96
97   if (IsEqualGUID(riid, &IID_IUnknown)
98       || IsEqualGUID(riid, &IID_IDirectXFile))
99   {
100     IUnknown_AddRef(iface);
101     *ppvObject = This;
102     return S_OK;
103   }
104
105   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
106   return E_NOINTERFACE;
107 }
108
109 static ULONG WINAPI IDirectXFileImpl_AddRef(IDirectXFile* iface)
110 {
111   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
112   ULONG ref = InterlockedIncrement(&This->ref);
113
114   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
115
116   return ref;
117 }
118
119 static ULONG WINAPI IDirectXFileImpl_Release(IDirectXFile* iface)
120 {
121   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
122   ULONG ref = InterlockedDecrement(&This->ref);
123
124   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
125
126   if (!ref)
127     HeapFree(GetProcessHeap(), 0, This);
128
129   return ref;
130 }
131
132 /*** IDirectXFile methods ***/
133 static HRESULT WINAPI IDirectXFileImpl_CreateEnumObject(IDirectXFile* iface, LPVOID pvSource, DXFILELOADOPTIONS dwLoadOptions, LPDIRECTXFILEENUMOBJECT* ppEnumObj)
134 {
135   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
136   IDirectXFileEnumObjectImpl* object;
137   HRESULT hr;
138   DWORD* header;
139   HANDLE hFile = INVALID_HANDLE_VALUE;
140   HANDLE file_mapping = 0;
141   LPBYTE buffer = NULL;
142   HGLOBAL resource_data = 0;
143   LPBYTE file_buffer;
144   DWORD file_size;
145
146   LPDXFILELOADMEMORY lpdxflm = NULL;
147
148   TRACE("(%p/%p)->(%p,%x,%p)\n", This, iface, pvSource, dwLoadOptions, ppEnumObj);
149
150   if (!ppEnumObj)
151     return DXFILEERR_BADVALUE;
152
153   /* Only lowest 4 bits are relevant in DXFILELOADOPTIONS */
154   dwLoadOptions &= 0xF;
155
156   if (dwLoadOptions == DXFILELOAD_FROMFILE)
157   {
158     TRACE("Open source file '%s'\n", (char*)pvSource);
159
160     hFile = CreateFileA(pvSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
161     if (hFile == INVALID_HANDLE_VALUE)
162     {
163       TRACE("File '%s' not found\n", (char*)pvSource);
164       return DXFILEERR_FILENOTFOUND;
165     }
166
167     file_size = GetFileSize(hFile, NULL);
168
169     file_mapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
170     if (!file_mapping)
171     {
172       hr = DXFILEERR_BADFILETYPE;
173       goto error;
174     }
175
176     buffer = MapViewOfFile(file_mapping, FILE_MAP_READ, 0, 0, 0);
177     if (!buffer)
178     {
179       hr = DXFILEERR_BADFILETYPE;
180       goto error;
181     }
182     file_buffer = buffer;
183   }
184   else if (dwLoadOptions == DXFILELOAD_FROMRESOURCE)
185   {
186     HRSRC resource_info;
187     LPDXFILELOADRESOURCE lpdxflr = pvSource;
188
189     TRACE("Source in resource (module = %p, name = %s, type = %s\n", lpdxflr->hModule, debugstr_a(lpdxflr->lpName), debugstr_a(lpdxflr->lpType));
190
191     resource_info = FindResourceA(lpdxflr->hModule, lpdxflr->lpName, lpdxflr->lpType);
192     if (!resource_info)
193     {
194       hr = DXFILEERR_RESOURCENOTFOUND;
195       goto error;
196     }
197
198     file_size = SizeofResource(lpdxflr->hModule, resource_info);
199
200     resource_data = LoadResource(lpdxflr->hModule, resource_info);
201     if (!resource_data)
202     {
203       hr = DXFILEERR_BADRESOURCE;
204       goto error;
205     }
206
207     file_buffer = LockResource(resource_data);
208     if (!file_buffer)
209     {
210       hr = DXFILEERR_BADRESOURCE;
211       goto error;
212     }
213   }
214   else if (dwLoadOptions == DXFILELOAD_FROMMEMORY)
215   {
216     lpdxflm = pvSource;
217
218     TRACE("Source in memory at %p with size %d\n", lpdxflm->lpMemory, lpdxflm->dSize);
219
220     file_buffer = lpdxflm->lpMemory;
221     file_size = lpdxflm->dSize;
222   }
223   else
224   {
225     FIXME("Source type %d is not handled yet\n", dwLoadOptions);
226     hr = DXFILEERR_NOTDONEYET;
227     goto error;
228   }
229
230   header = (DWORD*)file_buffer;
231
232   if (TRACE_ON(d3dxof))
233   {
234     char string[17];
235     memcpy(string, header, 16);
236     string[16] = 0;
237     TRACE("header = '%s'\n", string);
238   }
239
240   if (file_size < 16)
241   {
242     hr = DXFILEERR_BADFILETYPE;
243     goto error;
244   }
245
246   if (header[0] != XOFFILE_FORMAT_MAGIC)
247   {
248     hr = DXFILEERR_BADFILETYPE;
249     goto error;
250   }
251
252   if ((header[1] != XOFFILE_FORMAT_VERSION_302) && (header[1] != XOFFILE_FORMAT_VERSION_303))
253   {
254     hr = DXFILEERR_BADFILEVERSION;
255     goto error;
256   }
257
258   if ((header[2] != XOFFILE_FORMAT_BINARY) && (header[2] != XOFFILE_FORMAT_TEXT) &&
259       (header[2] != XOFFILE_FORMAT_BINARY_MSZIP) && (header[2] != XOFFILE_FORMAT_TEXT_MSZIP))
260   {
261     WARN("File type %s unknown\n", debugstr_fourcc(header[2]));
262     hr = DXFILEERR_BADFILETYPE;
263     goto error;
264   }
265
266   if ((header[2] == XOFFILE_FORMAT_BINARY_MSZIP) || (header[2] == XOFFILE_FORMAT_TEXT_MSZIP))
267   {
268     FIXME("Compressed format %s not supported yet\n", debugstr_fourcc(header[2]));
269     hr = DXFILEERR_BADALLOC;
270     goto error;
271   }
272
273   if ((header[3] != XOFFILE_FORMAT_FLOAT_BITS_32) && (header[3] != XOFFILE_FORMAT_FLOAT_BITS_64))
274   {
275     hr = DXFILEERR_BADFILEFLOATSIZE;
276     goto error;
277   }
278
279   TRACE("Header is correct\n");
280
281   hr = IDirectXFileEnumObjectImpl_Create(&object);
282   if (FAILED(hr))
283     goto error;
284
285   object->source = dwLoadOptions;
286   object->hFile = hFile;
287   object->file_mapping = file_mapping;
288   object->buffer = buffer;
289   object->pDirectXFile = This;
290   object->buf.pdxf = This;
291   object->buf.txt = (header[2] == XOFFILE_FORMAT_TEXT);
292   object->buf.token_present = FALSE;
293
294   TRACE("File size is %d bytes\n", file_size);
295
296   /* Go to data after header */
297   object->buf.buffer = file_buffer + 16;
298   object->buf.rem_bytes = file_size - 16;
299
300   *ppEnumObj = (LPDIRECTXFILEENUMOBJECT)object;
301
302   while (object->buf.rem_bytes && is_template_available(&object->buf))
303   {
304     if (!parse_template(&object->buf))
305     {
306       WARN("Template is not correct\n");
307       hr = DXFILEERR_BADVALUE;
308       goto error;
309     }
310     else
311     {
312       TRACE("Template successfully parsed:\n");
313       if (TRACE_ON(d3dxof))
314         dump_template(This->xtemplates, &This->xtemplates[This->nb_xtemplates - 1]);
315     }
316   }
317
318   if (TRACE_ON(d3dxof))
319   {
320     int i;
321     TRACE("Registered templates (%d):\n", This->nb_xtemplates);
322     for (i = 0; i < This->nb_xtemplates; i++)
323       DPRINTF("%s - %s\n", This->xtemplates[i].name, debugstr_guid(&This->xtemplates[i].class_id));
324   }
325
326   return DXFILE_OK;
327
328 error:
329   if (buffer)
330     UnmapViewOfFile(buffer);
331   if (file_mapping)
332     CloseHandle(file_mapping);
333   if (hFile != INVALID_HANDLE_VALUE)
334     CloseHandle(hFile);
335   if (resource_data)
336     FreeResource(resource_data);
337   *ppEnumObj = NULL;
338
339   return hr;
340 }
341
342 static HRESULT WINAPI IDirectXFileImpl_CreateSaveObject(IDirectXFile* iface, LPCSTR szFileName, DXFILEFORMAT dwFileFormat, LPDIRECTXFILESAVEOBJECT* ppSaveObj)
343 {
344   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
345
346   FIXME("(%p/%p)->(%s,%x,%p) partial stub!\n", This, iface, szFileName, dwFileFormat, ppSaveObj);
347
348   if (!szFileName || !ppSaveObj)
349     return E_POINTER;
350
351   return IDirectXFileSaveObjectImpl_Create((IDirectXFileSaveObjectImpl**)ppSaveObj);
352 }
353
354 static HRESULT WINAPI IDirectXFileImpl_RegisterTemplates(IDirectXFile* iface, LPVOID pvData, DWORD cbSize)
355 {
356   IDirectXFileImpl *This = (IDirectXFileImpl *)iface;
357   DWORD token_header;
358   parse_buffer buf;
359
360   buf.buffer = pvData;
361   buf.rem_bytes = cbSize;
362   buf.txt = FALSE;
363   buf.token_present = FALSE;
364   buf.pdxf = This;
365
366   TRACE("(%p/%p)->(%p,%d)\n", This, iface, pvData, cbSize);
367
368   if (!pvData)
369     return DXFILEERR_BADVALUE;
370
371   if (cbSize < 16)
372     return DXFILEERR_BADFILETYPE;
373
374   if (TRACE_ON(d3dxof))
375   {
376     char string[17];
377     memcpy(string, pvData, 16);
378     string[16] = 0;
379     TRACE("header = '%s'\n", string);
380   }
381
382   read_bytes(&buf, &token_header, 4);
383
384   if (token_header != XOFFILE_FORMAT_MAGIC)
385     return DXFILEERR_BADFILETYPE;
386
387   read_bytes(&buf, &token_header, 4);
388
389   if ((token_header != XOFFILE_FORMAT_VERSION_302) && (token_header != XOFFILE_FORMAT_VERSION_303))
390     return DXFILEERR_BADFILEVERSION;
391
392   read_bytes(&buf, &token_header, 4);
393
394   if ((token_header != XOFFILE_FORMAT_BINARY) && (token_header != XOFFILE_FORMAT_TEXT) &&
395       (token_header != XOFFILE_FORMAT_BINARY_MSZIP) && (token_header != XOFFILE_FORMAT_TEXT_MSZIP))
396   {
397     WARN("File type %s unknown\n", debugstr_fourcc(token_header));
398     return DXFILEERR_BADFILETYPE;
399   }
400
401   if ((token_header == XOFFILE_FORMAT_BINARY_MSZIP) || (token_header == XOFFILE_FORMAT_TEXT_MSZIP))
402   {
403     FIXME("Compressed format %s not supported yet\n", debugstr_fourcc(token_header));
404     return DXFILEERR_BADALLOC;
405   }
406
407   if (token_header == XOFFILE_FORMAT_TEXT)
408     buf.txt = TRUE;
409
410   read_bytes(&buf, &token_header, 4);
411
412   if ((token_header != XOFFILE_FORMAT_FLOAT_BITS_32) && (token_header != XOFFILE_FORMAT_FLOAT_BITS_64))
413     return DXFILEERR_BADFILEFLOATSIZE;
414
415   TRACE("Header is correct\n");
416
417   while (buf.rem_bytes)
418   {
419     if (!parse_template(&buf))
420     {
421       WARN("Template is not correct\n");
422       return DXFILEERR_BADVALUE;
423     }
424     else
425     {
426       TRACE("Template successfully parsed:\n");
427       if (TRACE_ON(d3dxof))
428         dump_template(This->xtemplates, &This->xtemplates[This->nb_xtemplates - 1]);
429     }
430   }
431
432   if (TRACE_ON(d3dxof))
433   {
434     int i;
435     TRACE("Registered templates (%d):\n", This->nb_xtemplates);
436     for (i = 0; i < This->nb_xtemplates; i++)
437       DPRINTF("%s - %s\n", This->xtemplates[i].name, debugstr_guid(&This->xtemplates[i].class_id));
438   }
439
440   return DXFILE_OK;
441 }
442
443 static const IDirectXFileVtbl IDirectXFile_Vtbl =
444 {
445   IDirectXFileImpl_QueryInterface,
446   IDirectXFileImpl_AddRef,
447   IDirectXFileImpl_Release,
448   IDirectXFileImpl_CreateEnumObject,
449   IDirectXFileImpl_CreateSaveObject,
450   IDirectXFileImpl_RegisterTemplates
451 };
452
453 static HRESULT IDirectXFileBinaryImpl_Create(IDirectXFileBinaryImpl** ppObj)
454 {
455     IDirectXFileBinaryImpl* object;
456
457     TRACE("(%p)\n", ppObj);
458
459     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileBinaryImpl));
460     if (!object)
461     {
462         ERR("Out of memory\n");
463         return DXFILEERR_BADALLOC;
464     }
465
466     object->lpVtbl = &IDirectXFileBinary_Vtbl;
467     object->ref = 1;
468
469     *ppObj = object;
470
471     return DXFILE_OK;
472 }
473
474 /*** IUnknown methods ***/
475 static HRESULT WINAPI IDirectXFileBinaryImpl_QueryInterface(IDirectXFileBinary* iface, REFIID riid, void** ppvObject)
476 {
477   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
478
479   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
480
481   if (IsEqualGUID(riid, &IID_IUnknown)
482       || IsEqualGUID(riid, &IID_IDirectXFileObject)
483       || IsEqualGUID(riid, &IID_IDirectXFileBinary))
484   {
485     IUnknown_AddRef(iface);
486     *ppvObject = This;
487     return S_OK;
488   }
489
490   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
491   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
492       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
493     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
494
495   return E_NOINTERFACE;
496 }
497
498 static ULONG WINAPI IDirectXFileBinaryImpl_AddRef(IDirectXFileBinary* iface)
499 {
500   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
501   ULONG ref = InterlockedIncrement(&This->ref);
502
503   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
504
505   return ref;
506 }
507
508 static ULONG WINAPI IDirectXFileBinaryImpl_Release(IDirectXFileBinary* iface)
509 {
510   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
511   ULONG ref = InterlockedDecrement(&This->ref);
512
513   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
514
515   if (!ref)
516     HeapFree(GetProcessHeap(), 0, This);
517
518   return ref;
519 }
520
521 /*** IDirectXFileObject methods ***/
522 static HRESULT WINAPI IDirectXFileBinaryImpl_GetName(IDirectXFileBinary* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
523
524 {
525   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
526
527   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pstrNameBuf, pdwBufLen); 
528
529   return DXFILEERR_BADVALUE;
530 }
531
532 static HRESULT WINAPI IDirectXFileBinaryImpl_GetId(IDirectXFileBinary* iface, LPGUID pGuid)
533 {
534   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
535
536   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pGuid); 
537
538   return DXFILEERR_BADVALUE;
539 }
540
541 /*** IDirectXFileBinary methods ***/
542 static HRESULT WINAPI IDirectXFileBinaryImpl_GetSize(IDirectXFileBinary* iface, DWORD* pcbSize)
543 {
544   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
545
546   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pcbSize); 
547
548   return DXFILEERR_BADVALUE;
549 }
550
551 static HRESULT WINAPI IDirectXFileBinaryImpl_GetMimeType(IDirectXFileBinary* iface, LPCSTR* pszMimeType)
552 {
553   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
554
555   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pszMimeType);
556
557   return DXFILEERR_BADVALUE;
558 }
559
560 static HRESULT WINAPI IDirectXFileBinaryImpl_Read(IDirectXFileBinary* iface, LPVOID pvData, DWORD cbSize, LPDWORD pcbRead)
561 {
562   IDirectXFileBinaryImpl *This = (IDirectXFileBinaryImpl *)iface;
563
564   FIXME("(%p/%p)->(%p, %d, %p) stub!\n", This, iface, pvData, cbSize, pcbRead);
565
566   return DXFILEERR_BADVALUE;
567 }
568
569 static const IDirectXFileBinaryVtbl IDirectXFileBinary_Vtbl =
570 {
571     IDirectXFileBinaryImpl_QueryInterface,
572     IDirectXFileBinaryImpl_AddRef,
573     IDirectXFileBinaryImpl_Release,
574     IDirectXFileBinaryImpl_GetName,
575     IDirectXFileBinaryImpl_GetId,
576     IDirectXFileBinaryImpl_GetSize,
577     IDirectXFileBinaryImpl_GetMimeType,
578     IDirectXFileBinaryImpl_Read
579 };
580
581 static HRESULT IDirectXFileDataImpl_Create(IDirectXFileDataImpl** ppObj)
582 {
583     IDirectXFileDataImpl* object;
584
585     TRACE("(%p)\n", ppObj);
586       
587     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataImpl));
588     if (!object)
589     {
590         ERR("Out of memory\n");
591         return DXFILEERR_BADALLOC;
592     }
593
594     object->lpVtbl = &IDirectXFileData_Vtbl;
595     object->ref = 1;
596
597     *ppObj = object;
598     
599     return S_OK;
600 }
601
602 /*** IUnknown methods ***/
603 static HRESULT WINAPI IDirectXFileDataImpl_QueryInterface(IDirectXFileData* iface, REFIID riid, void** ppvObject)
604 {
605   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
606
607   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
608
609   if (IsEqualGUID(riid, &IID_IUnknown)
610       || IsEqualGUID(riid, &IID_IDirectXFileObject)
611       || IsEqualGUID(riid, &IID_IDirectXFileData))
612   {
613     IUnknown_AddRef(iface);
614     *ppvObject = This;
615     return S_OK;
616   }
617
618   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
619   if (!IsEqualGUID(riid, &IID_IDirectXFileBinary)
620       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
621     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
622
623   return E_NOINTERFACE;
624 }
625
626 static ULONG WINAPI IDirectXFileDataImpl_AddRef(IDirectXFileData* iface)
627 {
628   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
629   ULONG ref = InterlockedIncrement(&This->ref);
630
631   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
632
633   return ref;
634 }
635
636 static ULONG WINAPI IDirectXFileDataImpl_Release(IDirectXFileData* iface)
637 {
638   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
639   ULONG ref = InterlockedDecrement(&This->ref);
640
641   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
642
643   if (!ref)
644   {
645     if (!This->level && !This->from_ref)
646     {
647       HeapFree(GetProcessHeap(), 0, This->pstrings);
648       HeapFree(GetProcessHeap(), 0, This->pobj->pdata);
649       HeapFree(GetProcessHeap(), 0, This->pobj);
650     }
651     HeapFree(GetProcessHeap(), 0, This);
652   }
653
654   return ref;
655 }
656
657 /*** IDirectXFileObject methods ***/
658 static HRESULT WINAPI IDirectXFileDataImpl_GetName(IDirectXFileData* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
659
660 {
661   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
662
663   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
664
665   if (!pstrNameBuf)
666     return DXFILEERR_BADVALUE;
667
668   strcpy(pstrNameBuf, This->pobj->name);
669
670   return DXFILE_OK;
671 }
672
673 static HRESULT WINAPI IDirectXFileDataImpl_GetId(IDirectXFileData* iface, LPGUID pGuid)
674 {
675   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
676
677   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
678
679   if (!pGuid)
680     return DXFILEERR_BADVALUE;
681
682   memcpy(pGuid, &This->pobj->class_id, 16);
683
684   return DXFILE_OK;
685 }
686
687 /*** IDirectXFileData methods ***/
688 static HRESULT WINAPI IDirectXFileDataImpl_GetData(IDirectXFileData* iface, LPCSTR szMember, DWORD* pcbSize, void** ppvData)
689 {
690   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
691
692   TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, szMember, pcbSize, ppvData);
693
694   if (!pcbSize || !ppvData)
695     return DXFILEERR_BADVALUE;
696
697   if (szMember)
698   {
699     FIXME("Specifying a member is not supported yet!\n");
700     return DXFILEERR_BADVALUE;
701   }
702
703   *pcbSize = This->pobj->size;
704   *ppvData = This->pobj->root->pdata + This->pobj->pos_data;
705
706   return DXFILE_OK;
707 }
708
709 static HRESULT WINAPI IDirectXFileDataImpl_GetType(IDirectXFileData* iface, const GUID** pguid)
710 {
711   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
712   static GUID guid;
713
714   TRACE("(%p/%p)->(%p)\n", This, iface, pguid);
715
716   if (!pguid)
717     return DXFILEERR_BADVALUE;
718
719   memcpy(&guid, &This->pobj->type, 16);
720   *pguid = &guid;
721
722   return DXFILE_OK;
723 }
724
725 static HRESULT WINAPI IDirectXFileDataImpl_GetNextObject(IDirectXFileData* iface, LPDIRECTXFILEOBJECT* ppChildObj)
726 {
727   HRESULT hr;
728   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
729
730   TRACE("(%p/%p)->(%p)\n", This, iface, ppChildObj);
731
732   if (This->cur_enum_object >= This->pobj->nb_childs)
733     return DXFILEERR_NOMOREOBJECTS;
734
735   if (This->from_ref && (This->level >= 1))
736   {
737     /* Only 2 levels can be enumerated if the object is obtained from a reference */
738     return DXFILEERR_NOMOREOBJECTS;
739   }
740
741   if (This->pobj->childs[This->cur_enum_object]->binary)
742   {
743     IDirectXFileBinaryImpl *object;
744
745     hr = IDirectXFileBinaryImpl_Create(&object);
746     if (FAILED(hr))
747       return hr;
748
749     *ppChildObj = (LPDIRECTXFILEOBJECT)object;
750   }
751   else if (This->pobj->childs[This->cur_enum_object]->ptarget)
752   {
753     IDirectXFileDataReferenceImpl *object;
754
755     hr = IDirectXFileDataReferenceImpl_Create(&object);
756     if (FAILED(hr))
757       return hr;
758
759     object->ptarget = This->pobj->childs[This->cur_enum_object++]->ptarget;
760
761     *ppChildObj = (LPDIRECTXFILEOBJECT)object;
762   }
763   else
764   {
765     IDirectXFileDataImpl *object;
766
767     hr = IDirectXFileDataImpl_Create(&object);
768     if (FAILED(hr))
769       return hr;
770
771     object->pobj = This->pobj->childs[This->cur_enum_object++];
772     object->cur_enum_object = 0;
773     object->from_ref = This->from_ref;
774     object->level = This->level + 1;
775
776     *ppChildObj = (LPDIRECTXFILEOBJECT)object;
777   }
778
779   return DXFILE_OK;
780 }
781
782 static HRESULT WINAPI IDirectXFileDataImpl_AddDataObject(IDirectXFileData* iface, LPDIRECTXFILEDATA pDataObj)
783 {
784   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
785
786   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pDataObj); 
787
788   return DXFILEERR_BADVALUE;
789 }
790
791 static HRESULT WINAPI IDirectXFileDataImpl_AddDataReference(IDirectXFileData* iface, LPCSTR szRef, const GUID* pguidRef)
792 {
793   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
794
795   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szRef, pguidRef); 
796
797   return DXFILEERR_BADVALUE;
798 }
799
800 static HRESULT WINAPI IDirectXFileDataImpl_AddBinaryObject(IDirectXFileData* iface, LPCSTR szName, const GUID* pguid, LPCSTR szMimeType, LPVOID pvData, DWORD cbSize)
801 {
802   IDirectXFileDataImpl *This = (IDirectXFileDataImpl *)iface;
803
804   FIXME("(%p/%p)->(%s,%p,%s,%p,%d) stub!\n", This, iface, szName, pguid, szMimeType, pvData, cbSize);
805
806   return DXFILEERR_BADVALUE;
807 }
808
809 static const IDirectXFileDataVtbl IDirectXFileData_Vtbl =
810 {
811     IDirectXFileDataImpl_QueryInterface,
812     IDirectXFileDataImpl_AddRef,
813     IDirectXFileDataImpl_Release,
814     IDirectXFileDataImpl_GetName,
815     IDirectXFileDataImpl_GetId,
816     IDirectXFileDataImpl_GetData,
817     IDirectXFileDataImpl_GetType,
818     IDirectXFileDataImpl_GetNextObject,
819     IDirectXFileDataImpl_AddDataObject,
820     IDirectXFileDataImpl_AddDataReference,
821     IDirectXFileDataImpl_AddBinaryObject
822 };
823
824 static HRESULT IDirectXFileDataReferenceImpl_Create(IDirectXFileDataReferenceImpl** ppObj)
825 {
826     IDirectXFileDataReferenceImpl* object;
827
828     TRACE("(%p)\n", ppObj);
829       
830     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataReferenceImpl));
831     if (!object)
832     {
833         ERR("Out of memory\n");
834         return DXFILEERR_BADALLOC;
835     }
836     
837     object->lpVtbl = &IDirectXFileDataReference_Vtbl;
838     object->ref = 1;
839
840     *ppObj = object;
841     
842     return S_OK;
843 }
844
845 /*** IUnknown methods ***/
846 static HRESULT WINAPI IDirectXFileDataReferenceImpl_QueryInterface(IDirectXFileDataReference* iface, REFIID riid, void** ppvObject)
847 {
848   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
849
850   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
851
852   if (IsEqualGUID(riid, &IID_IUnknown)
853       || IsEqualGUID(riid, &IID_IDirectXFileObject)
854       || IsEqualGUID(riid, &IID_IDirectXFileDataReference))
855   {
856     IUnknown_AddRef(iface);
857     *ppvObject = This;
858     return S_OK;
859   }
860
861   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
862   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
863       && !IsEqualGUID(riid, &IID_IDirectXFileBinary))
864     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
865
866   return E_NOINTERFACE;
867 }
868
869 static ULONG WINAPI IDirectXFileDataReferenceImpl_AddRef(IDirectXFileDataReference* iface)
870 {
871   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
872   ULONG ref = InterlockedIncrement(&This->ref);
873
874   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
875
876   return ref;
877 }
878
879 static ULONG WINAPI IDirectXFileDataReferenceImpl_Release(IDirectXFileDataReference* iface)
880 {
881   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
882   ULONG ref = InterlockedDecrement(&This->ref);
883
884   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
885
886   if (!ref)
887     HeapFree(GetProcessHeap(), 0, This);
888
889   return ref;
890 }
891
892 /*** IDirectXFileObject methods ***/
893 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetName(IDirectXFileDataReference* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
894 {
895   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
896
897   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
898
899   if (!pstrNameBuf)
900     return DXFILEERR_BADVALUE;
901
902   strcpy(pstrNameBuf, This->ptarget->name);
903
904   return DXFILEERR_BADVALUE;
905 }
906
907 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetId(IDirectXFileDataReference* iface, LPGUID pGuid)
908 {
909   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
910
911   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
912
913   if (!pGuid)
914     return DXFILEERR_BADVALUE;
915
916   memcpy(pGuid, &This->ptarget->class_id, 16);
917
918   return DXFILE_OK;
919 }
920
921 /*** IDirectXFileDataReference ***/
922 static HRESULT WINAPI IDirectXFileDataReferenceImpl_Resolve(IDirectXFileDataReference* iface, LPDIRECTXFILEDATA* ppDataObj)
923 {
924   IDirectXFileDataReferenceImpl *This = (IDirectXFileDataReferenceImpl *)iface;
925   IDirectXFileDataImpl *object;
926   HRESULT hr;
927
928   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
929
930   if (!ppDataObj)
931     return DXFILEERR_BADVALUE;
932
933   hr = IDirectXFileDataImpl_Create(&object);
934   if (FAILED(hr))
935     return hr;
936
937   object->pobj = This->ptarget;
938   object->cur_enum_object = 0;
939   object->level = 0;
940   object->from_ref = TRUE;
941
942   *ppDataObj = (LPDIRECTXFILEDATA)object;
943
944   return DXFILE_OK;
945 }
946
947 static const IDirectXFileDataReferenceVtbl IDirectXFileDataReference_Vtbl =
948 {
949     IDirectXFileDataReferenceImpl_QueryInterface,
950     IDirectXFileDataReferenceImpl_AddRef,
951     IDirectXFileDataReferenceImpl_Release,
952     IDirectXFileDataReferenceImpl_GetName,
953     IDirectXFileDataReferenceImpl_GetId,
954     IDirectXFileDataReferenceImpl_Resolve
955 };
956
957 static HRESULT IDirectXFileEnumObjectImpl_Create(IDirectXFileEnumObjectImpl** ppObj)
958 {
959     IDirectXFileEnumObjectImpl* object;
960
961     TRACE("(%p)\n", ppObj);
962       
963     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileEnumObjectImpl));
964     if (!object)
965     {
966         ERR("Out of memory\n");
967         return DXFILEERR_BADALLOC;
968     }
969     
970     object->lpVtbl = &IDirectXFileEnumObject_Vtbl;
971     object->ref = 1;
972
973     *ppObj = object;
974     
975     return S_OK;
976 }
977
978 /*** IUnknown methods ***/
979 static HRESULT WINAPI IDirectXFileEnumObjectImpl_QueryInterface(IDirectXFileEnumObject* iface, REFIID riid, void** ppvObject)
980 {
981   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
982
983   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
984
985   if (IsEqualGUID(riid, &IID_IUnknown)
986       || IsEqualGUID(riid, &IID_IDirectXFileEnumObject))
987   {
988     IUnknown_AddRef(iface);
989     *ppvObject = This;
990     return S_OK;
991   }
992
993   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
994   return E_NOINTERFACE;
995 }
996
997 static ULONG WINAPI IDirectXFileEnumObjectImpl_AddRef(IDirectXFileEnumObject* iface)
998 {
999   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1000   ULONG ref = InterlockedIncrement(&This->ref);
1001
1002   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1003
1004   return ref;
1005 }
1006
1007 static ULONG WINAPI IDirectXFileEnumObjectImpl_Release(IDirectXFileEnumObject* iface)
1008 {
1009   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1010   ULONG ref = InterlockedDecrement(&This->ref);
1011
1012   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1013
1014   if (!ref)
1015   {
1016     int i;
1017     for (i = 0; i < This->nb_xobjects; i++)
1018       IDirectXFileData_Release(This->pRefObjects[i]);
1019     if (This->source == DXFILELOAD_FROMFILE)
1020     {
1021       UnmapViewOfFile(This->buffer);
1022       CloseHandle(This->file_mapping);
1023       CloseHandle(This->hFile);
1024     }
1025     else if (This->source == DXFILELOAD_FROMRESOURCE)
1026       FreeResource(This->resource_data);
1027     HeapFree(GetProcessHeap(), 0, This);
1028   }
1029
1030   return ref;
1031 }
1032
1033 /*** IDirectXFileEnumObject methods ***/
1034 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetNextDataObject(IDirectXFileEnumObject* iface, LPDIRECTXFILEDATA* ppDataObj)
1035 {
1036   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1037   IDirectXFileDataImpl* object;
1038   HRESULT hr;
1039   LPBYTE pstrings = NULL;
1040
1041   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
1042
1043   if (This->nb_xobjects >= MAX_OBJECTS)
1044   {
1045     ERR("Too many objects\n");
1046     return DXFILEERR_NOMOREOBJECTS;
1047   }
1048
1049   /* Check if there are templates defined before the object */
1050   while (This->buf.rem_bytes && is_template_available(&This->buf))
1051   {
1052     if (!parse_template(&This->buf))
1053     {
1054       WARN("Template is not correct\n");
1055       hr = DXFILEERR_BADVALUE;
1056       goto error;
1057     }
1058     else
1059     {
1060       TRACE("Template successfully parsed:\n");
1061       if (TRACE_ON(d3dxof))
1062         dump_template(This->pDirectXFile->xtemplates, &This->pDirectXFile->xtemplates[This->pDirectXFile->nb_xtemplates - 1]);
1063     }
1064   }
1065
1066   if (!This->buf.rem_bytes)
1067     return DXFILEERR_NOMOREOBJECTS;
1068
1069   hr = IDirectXFileDataImpl_Create(&object);
1070   if (FAILED(hr))
1071     return hr;
1072
1073   This->buf.pxo_globals = This->xobjects;
1074   This->buf.nb_pxo_globals = This->nb_xobjects;
1075   This->buf.level = 0;
1076
1077   This->buf.pxo_tab = HeapAlloc(GetProcessHeap(), 0, sizeof(xobject)*MAX_SUBOBJECTS);
1078   if (!This->buf.pxo_tab)
1079   {
1080     ERR("Out of memory\n");
1081     hr = DXFILEERR_BADALLOC;
1082     goto error;
1083   }
1084   This->buf.pxo = This->xobjects[This->nb_xobjects] = This->buf.pxo_tab;
1085
1086   This->buf.pxo->pdata = This->buf.pdata = NULL;
1087   This->buf.capacity = 0;
1088   This->buf.cur_pos_data = 0;
1089   This->buf.pxo->nb_subobjects = 1;
1090
1091   pstrings = HeapAlloc(GetProcessHeap(), 0, MAX_STRINGS_BUFFER);
1092   if (!pstrings)
1093   {
1094     ERR("Out of memory\n");
1095     hr = DXFILEERR_BADALLOC;
1096     goto error;
1097   }
1098   This->buf.cur_pstrings = This->buf.pstrings = object->pstrings = pstrings;
1099
1100   if (!parse_object(&This->buf))
1101   {
1102     WARN("Object is not correct\n");
1103     hr = DXFILEERR_PARSEERROR;
1104     goto error;
1105   }
1106
1107   if (This->buf.pxo->nb_subobjects > MAX_SUBOBJECTS)
1108   {
1109     FIXME("Too many subobjects %d\n", This->buf.pxo->nb_subobjects);
1110     hr = DXFILEERR_BADALLOC;
1111     goto error;
1112   }
1113
1114   object->pstrings = pstrings;
1115   object->pobj = This->buf.pxo;
1116   object->cur_enum_object = 0;
1117   object->level = 0;
1118   object->from_ref = FALSE;
1119
1120   *ppDataObj = (LPDIRECTXFILEDATA)object;
1121
1122   /* Get a reference to created object */
1123   This->pRefObjects[This->nb_xobjects] = (LPDIRECTXFILEDATA)object;
1124   IDirectXFileData_AddRef(This->pRefObjects[This->nb_xobjects]);
1125
1126   This->nb_xobjects++;
1127
1128   return DXFILE_OK;
1129
1130 error:
1131
1132   HeapFree(GetProcessHeap(), 0, This->buf.pxo_tab);
1133   HeapFree(GetProcessHeap(), 0, This->buf.pdata);
1134   HeapFree(GetProcessHeap(), 0, pstrings);
1135
1136   return hr;
1137 }
1138
1139 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectById(IDirectXFileEnumObject* iface, REFGUID rguid, LPDIRECTXFILEDATA* ppDataObj)
1140 {
1141   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1142
1143   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, rguid, ppDataObj); 
1144
1145   return DXFILEERR_BADVALUE;
1146 }
1147
1148 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectByName(IDirectXFileEnumObject* iface, LPCSTR szName, LPDIRECTXFILEDATA* ppDataObj)
1149 {
1150   IDirectXFileEnumObjectImpl *This = (IDirectXFileEnumObjectImpl *)iface;
1151
1152   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szName, ppDataObj); 
1153
1154   return DXFILEERR_BADVALUE;
1155 }
1156
1157 static const IDirectXFileEnumObjectVtbl IDirectXFileEnumObject_Vtbl =
1158 {
1159     IDirectXFileEnumObjectImpl_QueryInterface,
1160     IDirectXFileEnumObjectImpl_AddRef,
1161     IDirectXFileEnumObjectImpl_Release,
1162     IDirectXFileEnumObjectImpl_GetNextDataObject,
1163     IDirectXFileEnumObjectImpl_GetDataObjectById,
1164     IDirectXFileEnumObjectImpl_GetDataObjectByName
1165 };
1166
1167 static HRESULT IDirectXFileSaveObjectImpl_Create(IDirectXFileSaveObjectImpl** ppObj)
1168 {
1169     IDirectXFileSaveObjectImpl* object;
1170
1171     TRACE("(%p)\n", ppObj);
1172
1173     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileSaveObjectImpl));
1174     if (!object)
1175     {
1176         ERR("Out of memory\n");
1177         return DXFILEERR_BADALLOC;
1178     }
1179
1180     object->lpVtbl = &IDirectXFileSaveObject_Vtbl;
1181     object->ref = 1;
1182
1183     *ppObj = object;
1184
1185     return S_OK;
1186 }
1187
1188 /*** IUnknown methods ***/
1189 static HRESULT WINAPI IDirectXFileSaveObjectImpl_QueryInterface(IDirectXFileSaveObject* iface, REFIID riid, void** ppvObject)
1190 {
1191   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
1192
1193   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1194
1195   if (IsEqualGUID(riid, &IID_IUnknown)
1196       || IsEqualGUID(riid, &IID_IDirectXFileSaveObject))
1197   {
1198     IUnknown_AddRef(iface);
1199     *ppvObject = This;
1200     return S_OK;
1201   }
1202
1203   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1204   return E_NOINTERFACE;
1205 }
1206
1207 static ULONG WINAPI IDirectXFileSaveObjectImpl_AddRef(IDirectXFileSaveObject* iface)
1208 {
1209   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
1210   ULONG ref = InterlockedIncrement(&This->ref);
1211
1212   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1213
1214   return ref;
1215 }
1216
1217 static ULONG WINAPI IDirectXFileSaveObjectImpl_Release(IDirectXFileSaveObject* iface)
1218 {
1219   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
1220   ULONG ref = InterlockedDecrement(&This->ref);
1221
1222   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1223
1224   if (!ref)
1225     HeapFree(GetProcessHeap(), 0, This);
1226
1227   return ref;
1228 }
1229
1230 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveTemplates(IDirectXFileSaveObject* iface, DWORD cTemplates, const GUID** ppguidTemplates)
1231 {
1232   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
1233
1234   FIXME("(%p/%p)->(%d,%p) stub!\n", This, iface, cTemplates, ppguidTemplates);
1235
1236   return DXFILEERR_BADVALUE;
1237 }
1238
1239 static HRESULT WINAPI IDirectXFileSaveObjectImpl_CreateDataObject(IDirectXFileSaveObject* iface, REFGUID rguidTemplate, LPCSTR szName, const GUID* pguid, DWORD cbSize, LPVOID pvData, LPDIRECTXFILEDATA* ppDataObj)
1240 {
1241   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
1242
1243   FIXME("(%p/%p)->(%p,%s,%p,%d,%p,%p) stub!\n", This, iface, rguidTemplate, szName, pguid, cbSize, pvData, ppDataObj);
1244
1245   return DXFILEERR_BADVALUE;
1246 }
1247
1248 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveData(IDirectXFileSaveObject* iface, LPDIRECTXFILEDATA ppDataObj)
1249 {
1250   IDirectXFileSaveObjectImpl *This = (IDirectXFileSaveObjectImpl *)iface;
1251
1252   FIXME("(%p/%p)->(%p) stub!\n", This, iface, ppDataObj); 
1253
1254   return DXFILEERR_BADVALUE;
1255 }
1256
1257 static const IDirectXFileSaveObjectVtbl IDirectXFileSaveObject_Vtbl =
1258 {
1259     IDirectXFileSaveObjectImpl_QueryInterface,
1260     IDirectXFileSaveObjectImpl_AddRef,
1261     IDirectXFileSaveObjectImpl_Release,
1262     IDirectXFileSaveObjectImpl_SaveTemplates,
1263     IDirectXFileSaveObjectImpl_CreateDataObject,
1264     IDirectXFileSaveObjectImpl_SaveData
1265 };