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