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