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