xref: /reactos/dll/directx/wine/d3dx9_36/xfile.c (revision 3476cdae)
1 #ifdef __REACTOS__
2 #include "precomp.h"
3 #else
4 /*
5  * Copyright (C) 2012 Christian Costa
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  */
22 
23 
24 #include "d3dx9_private.h"
25 #include "d3dx9xof.h"
26 #undef MAKE_DDHRESULT
27 #include "dxfile.h"
28 #endif /* __REACTOS__ */
29 
30 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
31 
32 static HRESULT error_dxfile_to_d3dxfile(HRESULT error)
33 {
34     switch (error)
35     {
36         case DXFILEERR_BADFILETYPE:
37             return D3DXFERR_BADFILETYPE;
38         case DXFILEERR_BADFILEVERSION:
39             return D3DXFERR_BADFILEVERSION;
40         case DXFILEERR_BADFILEFLOATSIZE:
41             return D3DXFERR_BADFILEFLOATSIZE;
42         case DXFILEERR_PARSEERROR:
43             return D3DXFERR_PARSEERROR;
44         case DXFILEERR_BADVALUE:
45             return D3DXFERR_BADVALUE;
46         default:
47             FIXME("Cannot map error %#x\n", error);
48             return E_FAIL;
49     }
50 }
51 
52 struct d3dx9_file
53 {
54     ID3DXFile ID3DXFile_iface;
55     LONG ref;
56     IDirectXFile *dxfile;
57 };
58 
59 struct d3dx9_file_enum_object
60 {
61     ID3DXFileEnumObject ID3DXFileEnumObject_iface;
62     LONG ref;
63     ULONG nb_children;
64     ID3DXFileData **children;
65 };
66 
67 struct d3dx9_file_data
68 {
69     ID3DXFileData ID3DXFileData_iface;
70     LONG ref;
71     BOOL reference;
72     IDirectXFileData *dxfile_data;
73     ULONG nb_children;
74     ID3DXFileData **children;
75 };
76 
77 static inline struct d3dx9_file *impl_from_ID3DXFile(ID3DXFile *iface)
78 {
79     return CONTAINING_RECORD(iface, struct d3dx9_file, ID3DXFile_iface);
80 }
81 
82 static inline struct d3dx9_file_enum_object *impl_from_ID3DXFileEnumObject(ID3DXFileEnumObject *iface)
83 {
84     return CONTAINING_RECORD(iface, struct d3dx9_file_enum_object, ID3DXFileEnumObject_iface);
85 }
86 
87 static inline struct d3dx9_file_data *impl_from_ID3DXFileData(ID3DXFileData *iface)
88 {
89     return CONTAINING_RECORD(iface, struct d3dx9_file_data, ID3DXFileData_iface);
90 }
91 
92 static HRESULT WINAPI d3dx9_file_data_QueryInterface(ID3DXFileData *iface, REFIID riid, void **out)
93 {
94     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
95 
96     if (IsEqualGUID(riid, &IID_ID3DXFileData)
97             || IsEqualGUID(riid, &IID_IUnknown))
98     {
99         iface->lpVtbl->AddRef(iface);
100         *out = iface;
101         return S_OK;
102     }
103 
104     WARN("Interface %s not found.\n", debugstr_guid(riid));
105 
106     *out = NULL;
107     return E_NOINTERFACE;
108 }
109 
110 static ULONG WINAPI d3dx9_file_data_AddRef(ID3DXFileData *iface)
111 {
112     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
113     ULONG refcount = InterlockedIncrement(&file_data->ref);
114 
115     TRACE("%p increasing refcount to %u.\n", file_data, refcount);
116 
117     return refcount;
118 }
119 
120 static ULONG WINAPI d3dx9_file_data_Release(ID3DXFileData *iface)
121 {
122     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
123     ULONG refcount = InterlockedDecrement(&file_data->ref);
124 
125     TRACE("%p decreasing refcount to %u.\n", file_data, refcount);
126 
127     if (!refcount)
128     {
129         ULONG i;
130 
131         for (i = 0; i < file_data->nb_children; ++i)
132         {
133             ID3DXFileData *child = file_data->children[i];
134             child->lpVtbl->Release(child);
135         }
136         HeapFree(GetProcessHeap(), 0, file_data->children);
137         IDirectXFileData_Release(file_data->dxfile_data);
138         HeapFree(GetProcessHeap(), 0, file_data);
139     }
140 
141     return refcount;
142 }
143 
144 static HRESULT WINAPI d3dx9_file_data_GetEnum(ID3DXFileData *iface, ID3DXFileEnumObject **enum_object)
145 {
146     FIXME("iface %p, enum_object %p stub!\n", iface, enum_object);
147 
148     return E_NOTIMPL;
149 }
150 
151 static HRESULT WINAPI d3dx9_file_data_GetName(ID3DXFileData *iface, char *name, SIZE_T *size)
152 {
153     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
154     DWORD dxfile_size;
155     HRESULT ret;
156 
157     TRACE("iface %p, name %p, size %p.\n", iface, name, size);
158 
159     if (!size)
160         return D3DXFERR_BADVALUE;
161 
162     dxfile_size = *size;
163 
164     ret = IDirectXFileData_GetName(file_data->dxfile_data, name, &dxfile_size);
165     if (ret != DXFILE_OK)
166         return error_dxfile_to_d3dxfile(ret);
167 
168     if (!dxfile_size)
169     {
170         /* Contrary to d3dxof, d3dx9_36 returns an empty string with a null byte when no name is available.
171          * If the input size is 0, it returns a length of 1 without touching the buffer */
172         dxfile_size = 1;
173         if (name && *size)
174             name[0] = 0;
175     }
176 
177     *size = dxfile_size;
178 
179     return S_OK;
180 }
181 
182 static HRESULT WINAPI d3dx9_file_data_GetId(ID3DXFileData *iface, GUID *guid)
183 {
184     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
185     HRESULT ret;
186 
187     TRACE("iface %p, guid %p.\n", iface, guid);
188 
189     if (!guid)
190         return E_POINTER;
191 
192     ret = IDirectXFileData_GetId(file_data->dxfile_data, guid);
193     if (ret != DXFILE_OK)
194         return error_dxfile_to_d3dxfile(ret);
195 
196     return S_OK;
197 }
198 
199 static HRESULT WINAPI d3dx9_file_data_Lock(ID3DXFileData *iface, SIZE_T *size, const void **data)
200 {
201     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
202     DWORD dxfile_size;
203     HRESULT ret;
204 
205     TRACE("iface %p, size %p, data %p.\n", iface, size, data);
206 
207     if (!size || !data)
208         return E_POINTER;
209 
210     ret = IDirectXFileData_GetData(file_data->dxfile_data, NULL, &dxfile_size, (void **)data);
211     if (ret != DXFILE_OK)
212         return error_dxfile_to_d3dxfile(ret);
213 
214     *size = dxfile_size;
215 
216     return S_OK;
217 }
218 
219 static HRESULT WINAPI d3dx9_file_data_Unlock(ID3DXFileData *iface)
220 {
221     TRACE("iface %p.\n", iface);
222 
223     /* Nothing to do */
224 
225     return S_OK;
226 }
227 
228 static HRESULT WINAPI d3dx9_file_data_GetType(ID3DXFileData *iface, GUID *guid)
229 {
230     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
231     const GUID *dxfile_guid;
232     HRESULT ret;
233 
234     TRACE("iface %p, guid %p.\n", iface, guid);
235 
236     ret = IDirectXFileData_GetType(file_data->dxfile_data, &dxfile_guid);
237     if (ret != DXFILE_OK)
238         return error_dxfile_to_d3dxfile(ret);
239 
240     *guid = *dxfile_guid;
241 
242     return S_OK;
243 }
244 
245 static BOOL WINAPI d3dx9_file_data_IsReference(ID3DXFileData *iface)
246 {
247     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
248 
249     TRACE("iface %p.\n", iface);
250 
251     return file_data->reference;
252 }
253 
254 static HRESULT WINAPI d3dx9_file_data_GetChildren(ID3DXFileData *iface, SIZE_T *children)
255 {
256     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
257 
258     TRACE("iface %p, children %p.\n", iface, children);
259 
260     if (!children)
261         return E_POINTER;
262 
263     *children = file_data->nb_children;
264 
265     return S_OK;
266 }
267 
268 static HRESULT WINAPI d3dx9_file_data_GetChild(ID3DXFileData *iface, SIZE_T id, ID3DXFileData **object)
269 {
270     struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
271 
272     TRACE("iface %p, id %#lx, object %p.\n", iface, id, object);
273 
274     if (!object)
275         return E_POINTER;
276 
277     *object = file_data->children[id];
278     (*object)->lpVtbl->AddRef(*object);
279 
280     return S_OK;
281 }
282 
283 static const ID3DXFileDataVtbl d3dx9_file_data_vtbl =
284 {
285     d3dx9_file_data_QueryInterface,
286     d3dx9_file_data_AddRef,
287     d3dx9_file_data_Release,
288     d3dx9_file_data_GetEnum,
289     d3dx9_file_data_GetName,
290     d3dx9_file_data_GetId,
291     d3dx9_file_data_Lock,
292     d3dx9_file_data_Unlock,
293     d3dx9_file_data_GetType,
294     d3dx9_file_data_IsReference,
295     d3dx9_file_data_GetChildren,
296     d3dx9_file_data_GetChild,
297 };
298 
299 static HRESULT d3dx9_file_data_create(IDirectXFileObject *dxfile_object, ID3DXFileData **ret_iface)
300 {
301     struct d3dx9_file_data *object;
302     IDirectXFileObject *data_object;
303     unsigned int children_array_size = 0;
304     HRESULT ret;
305 
306     TRACE("dxfile_object %p, ret_iface %p.\n", dxfile_object, ret_iface);
307 
308     *ret_iface = NULL;
309 
310     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
311     if (!object)
312         return E_OUTOFMEMORY;
313 
314     object->ID3DXFileData_iface.lpVtbl = &d3dx9_file_data_vtbl;
315     object->ref = 1;
316 
317     ret = IDirectXFileObject_QueryInterface(dxfile_object, &IID_IDirectXFileData, (void **)&object->dxfile_data);
318     if (FAILED(ret))
319     {
320         IDirectXFileDataReference *reference;
321 
322         ret = IDirectXFileObject_QueryInterface(dxfile_object, &IID_IDirectXFileDataReference, (void **)&reference);
323         if (SUCCEEDED(ret))
324         {
325             ret = IDirectXFileDataReference_Resolve(reference, &object->dxfile_data);
326             IUnknown_Release(reference);
327             if (FAILED(ret))
328             {
329                 HeapFree(GetProcessHeap(), 0, object);
330                 return E_FAIL;
331             }
332             object->reference = TRUE;
333         }
334         else
335         {
336             FIXME("Don't know what to do with binary object\n");
337             HeapFree(GetProcessHeap(), 0, object);
338             return E_FAIL;
339         }
340     }
341 
342     while (SUCCEEDED(ret = IDirectXFileData_GetNextObject(object->dxfile_data, &data_object)))
343     {
344         if (object->nb_children >= children_array_size)
345         {
346             ID3DXFileData **new_children;
347 
348             if (object->children)
349             {
350                 children_array_size *= 2;
351                 new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
352                         sizeof(*object->children) * children_array_size);
353             }
354             else
355             {
356                 children_array_size = 4;
357                 new_children = HeapAlloc(GetProcessHeap(), 0, sizeof(*object->children) * children_array_size);
358             }
359             if (!new_children)
360             {
361                 ret = E_OUTOFMEMORY;
362                 break;
363             }
364             object->children = new_children;
365         }
366         ret = d3dx9_file_data_create(data_object, &object->children[object->nb_children]);
367         IUnknown_Release(data_object);
368         if (FAILED(ret))
369             break;
370         object->nb_children++;
371     }
372     if (ret != DXFILEERR_NOMOREOBJECTS)
373     {
374         (&object->ID3DXFileData_iface)->lpVtbl->Release(&object->ID3DXFileData_iface);
375         return ret;
376     }
377     if (object->children)
378     {
379         ID3DXFileData **new_children;
380 
381         new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
382                 sizeof(*object->children) * object->nb_children);
383         if (new_children)
384             object->children = new_children;
385     }
386 
387     TRACE("Found %u children\n", object->nb_children);
388 
389     *ret_iface = &object->ID3DXFileData_iface;
390 
391     return S_OK;
392 }
393 
394 static HRESULT WINAPI d3dx9_file_enum_object_QueryInterface(ID3DXFileEnumObject *iface, REFIID riid, void **out)
395 {
396     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
397 
398     if (IsEqualGUID(riid, &IID_ID3DXFileEnumObject)
399             || IsEqualGUID(riid, &IID_IUnknown))
400     {
401         iface->lpVtbl->AddRef(iface);
402         *out = iface;
403         return S_OK;
404     }
405 
406     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
407 
408     *out = NULL;
409     return E_NOINTERFACE;
410 }
411 
412 static ULONG WINAPI d3dx9_file_enum_object_AddRef(ID3DXFileEnumObject *iface)
413 {
414     struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
415     ULONG refcount = InterlockedIncrement(&file_enum->ref);
416 
417     TRACE("%p increasing refcount to %u.\n", file_enum, refcount);
418 
419     return refcount;
420 }
421 
422 static ULONG WINAPI d3dx9_file_enum_object_Release(ID3DXFileEnumObject *iface)
423 {
424     struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
425     ULONG refcount = InterlockedDecrement(&file_enum->ref);
426 
427     TRACE("%p decreasing refcount to %u.\n", file_enum, refcount);
428 
429     if (!refcount)
430     {
431         ULONG i;
432 
433         for (i = 0; i < file_enum->nb_children; ++i)
434         {
435             ID3DXFileData *child = file_enum->children[i];
436             child->lpVtbl->Release(child);
437         }
438         HeapFree(GetProcessHeap(), 0, file_enum->children);
439         HeapFree(GetProcessHeap(), 0, file_enum);
440     }
441 
442     return refcount;
443 }
444 
445 static HRESULT WINAPI d3dx9_file_enum_object_GetFile(ID3DXFileEnumObject *iface, ID3DXFile **file)
446 {
447     FIXME("iface %p, file %p stub!\n", iface, file);
448 
449     return E_NOTIMPL;
450 }
451 
452 static HRESULT WINAPI d3dx9_file_enum_object_GetChildren(ID3DXFileEnumObject *iface, SIZE_T *children)
453 {
454     struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
455 
456     TRACE("iface %p, children %p.\n", iface, children);
457 
458     if (!children)
459         return E_POINTER;
460 
461     *children = file_enum->nb_children;
462 
463     return S_OK;
464 }
465 
466 static HRESULT WINAPI d3dx9_file_enum_object_GetChild(ID3DXFileEnumObject *iface, SIZE_T id, ID3DXFileData **object)
467 {
468     struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
469 
470     TRACE("iface %p, id %#lx, object %p.\n", iface, id, object);
471 
472     if (!object)
473         return E_POINTER;
474 
475     *object = file_enum->children[id];
476     (*object)->lpVtbl->AddRef(*object);
477 
478     return S_OK;
479 }
480 
481 static HRESULT WINAPI d3dx9_file_enum_object_GetDataObjectById(ID3DXFileEnumObject *iface,
482         REFGUID guid, ID3DXFileData **object)
483 {
484     FIXME("iface %p, guid %s, object %p stub!\n", iface, debugstr_guid(guid), object);
485 
486     return E_NOTIMPL;
487 }
488 
489 static HRESULT WINAPI d3dx9_file_enum_object_GetDataObjectByName(ID3DXFileEnumObject *iface,
490         const char *name, ID3DXFileData **object)
491 {
492     FIXME("iface %p, name %s, object %p stub!\n", iface, debugstr_a(name), object);
493 
494     return E_NOTIMPL;
495 }
496 
497 static const ID3DXFileEnumObjectVtbl d3dx9_file_enum_object_vtbl =
498 {
499     d3dx9_file_enum_object_QueryInterface,
500     d3dx9_file_enum_object_AddRef,
501     d3dx9_file_enum_object_Release,
502     d3dx9_file_enum_object_GetFile,
503     d3dx9_file_enum_object_GetChildren,
504     d3dx9_file_enum_object_GetChild,
505     d3dx9_file_enum_object_GetDataObjectById,
506     d3dx9_file_enum_object_GetDataObjectByName,
507 };
508 
509 static HRESULT WINAPI d3dx9_file_QueryInterface(ID3DXFile *iface, REFIID riid, void **out)
510 {
511     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
512 
513     if (IsEqualGUID(riid, &IID_ID3DXFile)
514             || IsEqualGUID(riid, &IID_IUnknown))
515     {
516         iface->lpVtbl->AddRef(iface);
517         *out = iface;
518         return S_OK;
519     }
520 
521     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
522 
523     *out = NULL;
524     return E_NOINTERFACE;
525 }
526 
527 static ULONG WINAPI d3dx9_file_AddRef(ID3DXFile *iface)
528 {
529     struct d3dx9_file *file = impl_from_ID3DXFile(iface);
530     ULONG refcount = InterlockedIncrement(&file->ref);
531 
532     TRACE("%p increasing refcount to %u.\n", file, refcount);
533 
534     return refcount;
535 }
536 
537 static ULONG WINAPI d3dx9_file_Release(ID3DXFile *iface)
538 {
539     struct d3dx9_file *file = impl_from_ID3DXFile(iface);
540     ULONG refcount = InterlockedDecrement(&file->ref);
541 
542     TRACE("%p decreasing refcount to %u.\n", file, refcount);
543 
544     if (!refcount)
545     {
546         IDirectXFile_Release(file->dxfile);
547         HeapFree(GetProcessHeap(), 0, file);
548     }
549 
550     return refcount;
551 }
552 
553 static HRESULT WINAPI d3dx9_file_CreateEnumObject(ID3DXFile *iface, const void *source,
554         D3DXF_FILELOADOPTIONS options, ID3DXFileEnumObject **enum_object)
555 {
556     struct d3dx9_file *file = impl_from_ID3DXFile(iface);
557     struct d3dx9_file_enum_object *object;
558     IDirectXFileEnumObject *dxfile_enum_object;
559     void *dxfile_source;
560     DXFILELOADOPTIONS dxfile_options;
561     DXFILELOADRESOURCE dxfile_resource;
562     DXFILELOADMEMORY dxfile_memory;
563     IDirectXFileData *data_object;
564     unsigned children_array_size = 0;
565     HRESULT ret;
566 
567     TRACE("iface %p, source %p, options %#x, enum_object %p.\n", iface, source, options, enum_object);
568 
569     if (!enum_object)
570         return E_POINTER;
571 
572     *enum_object = NULL;
573 
574     if (options == D3DXF_FILELOAD_FROMFILE)
575     {
576         dxfile_source = (void*)source;
577         dxfile_options = DXFILELOAD_FROMFILE;
578     }
579     else if (options == D3DXF_FILELOAD_FROMRESOURCE)
580     {
581         D3DXF_FILELOADRESOURCE *resource = (D3DXF_FILELOADRESOURCE*)source;
582 
583         dxfile_resource.hModule = resource->hModule;
584         dxfile_resource.lpName = resource->lpName;
585         dxfile_resource.lpType = resource->lpType;
586         dxfile_source = &dxfile_resource;
587         dxfile_options = DXFILELOAD_FROMRESOURCE;
588     }
589     else if (options == D3DXF_FILELOAD_FROMMEMORY)
590     {
591         D3DXF_FILELOADMEMORY *memory = (D3DXF_FILELOADMEMORY*)source;
592 
593         dxfile_memory.lpMemory = (void *)memory->lpMemory;
594         dxfile_memory.dSize = memory->dSize;
595         dxfile_source = &dxfile_memory;
596         dxfile_options = DXFILELOAD_FROMMEMORY;
597     }
598     else
599     {
600         FIXME("Source type %u is not handled yet\n", options);
601         return E_NOTIMPL;
602     }
603 
604     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
605     if (!object)
606         return E_OUTOFMEMORY;
607 
608     object->ID3DXFileEnumObject_iface.lpVtbl = &d3dx9_file_enum_object_vtbl;
609     object->ref = 1;
610 
611     ret = IDirectXFile_CreateEnumObject(file->dxfile, dxfile_source, dxfile_options, &dxfile_enum_object);
612 
613     if (ret != S_OK)
614     {
615         HeapFree(GetProcessHeap(), 0, object);
616         return ret;
617     }
618 
619     /* Fill enum object with top level data objects */
620     while (SUCCEEDED(ret = IDirectXFileEnumObject_GetNextDataObject(dxfile_enum_object, &data_object)))
621     {
622         if (object->nb_children >= children_array_size)
623         {
624             ID3DXFileData **new_children;
625 
626             if (object->children)
627             {
628                 children_array_size *= 2;
629                 new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
630                         sizeof(*object->children) * children_array_size);
631             }
632             else
633             {
634                 children_array_size = 4;
635                 new_children = HeapAlloc(GetProcessHeap(), 0, sizeof(*object->children) * children_array_size);
636             }
637             if (!new_children)
638             {
639                 ret = E_OUTOFMEMORY;
640                 break;
641             }
642             object->children = new_children;
643         }
644         ret = d3dx9_file_data_create((IDirectXFileObject*)data_object,
645                 &object->children[object->nb_children]);
646         IUnknown_Release(data_object);
647         if (FAILED(ret))
648             break;
649         object->nb_children++;
650     }
651     if (object->children)
652     {
653         ID3DXFileData **new_children;
654 
655         new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
656                 sizeof(*object->children) * object->nb_children);
657         if (new_children)
658             object->children = new_children;
659     }
660 
661     IDirectXFileEnumObject_Release(dxfile_enum_object);
662 
663     if (ret != DXFILEERR_NOMOREOBJECTS)
664         WARN("Cannot get all top level data objects\n");
665 
666     TRACE("Found %u children\n", object->nb_children);
667 
668     *enum_object = &object->ID3DXFileEnumObject_iface;
669 
670     return S_OK;
671 }
672 
673 static HRESULT WINAPI d3dx9_file_CreateSaveObject(ID3DXFile *iface, const void *data,
674         D3DXF_FILESAVEOPTIONS options, D3DXF_FILEFORMAT format, ID3DXFileSaveObject **save_object)
675 {
676     FIXME("iface %p, data %p, options %#x, format %#x, save_object %p stub!\n",
677             iface, data, options, format, save_object);
678 
679     return E_NOTIMPL;
680 }
681 
682 static HRESULT WINAPI d3dx9_file_RegisterTemplates(ID3DXFile *iface, const void *data, SIZE_T size)
683 {
684     struct d3dx9_file *file = impl_from_ID3DXFile(iface);
685     HRESULT ret;
686 
687     TRACE("iface %p, data %p, size %lu.\n", iface, data, size);
688 
689     ret = IDirectXFile_RegisterTemplates(file->dxfile, (void *)data, size);
690     if (ret != DXFILE_OK)
691     {
692         WARN("Error %#x\n", ret);
693         return error_dxfile_to_d3dxfile(ret);
694     }
695 
696     return S_OK;
697 }
698 
699 static HRESULT WINAPI d3dx9_file_RegisterEnumTemplates(ID3DXFile *iface, ID3DXFileEnumObject *enum_object)
700 {
701     FIXME("iface %p, enum_object %p stub!\n", iface, enum_object);
702 
703     return E_NOTIMPL;
704 }
705 
706 static const ID3DXFileVtbl d3dx9_file_vtbl =
707 {
708     d3dx9_file_QueryInterface,
709     d3dx9_file_AddRef,
710     d3dx9_file_Release,
711     d3dx9_file_CreateEnumObject,
712     d3dx9_file_CreateSaveObject,
713     d3dx9_file_RegisterTemplates,
714     d3dx9_file_RegisterEnumTemplates,
715 };
716 
717 HRESULT WINAPI D3DXFileCreate(ID3DXFile **d3dxfile)
718 {
719     struct d3dx9_file *object;
720     HRESULT ret;
721 
722     TRACE("d3dxfile %p.\n", d3dxfile);
723 
724     if (!d3dxfile)
725         return E_POINTER;
726 
727     *d3dxfile = NULL;
728 
729     object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object));
730     if (!object)
731         return E_OUTOFMEMORY;
732 
733     ret = DirectXFileCreate(&object->dxfile);
734     if (ret != S_OK)
735     {
736         HeapFree(GetProcessHeap(), 0, object);
737         if (ret == E_OUTOFMEMORY)
738             return ret;
739         return E_FAIL;
740     }
741 
742     object->ID3DXFile_iface.lpVtbl = &d3dx9_file_vtbl;
743     object->ref = 1;
744 
745     *d3dxfile = &object->ID3DXFile_iface;
746 
747     return S_OK;
748 }
749