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