xfile.c 19.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright (C) 2012 Christian Costa
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 */

#include "wine/debug.h"

#include "d3dx9.h"
#include "d3dx9xof.h"
24 25
#undef MAKE_DDHRESULT
#include "dxfile.h"
26 27 28

WINE_DEFAULT_DEBUG_CHANNEL(d3dx);

29
static HRESULT error_dxfile_to_d3dxfile(HRESULT error)
30 31 32 33 34 35 36 37 38 39 40
{
    switch (error)
    {
        case DXFILEERR_BADFILETYPE:
            return D3DXFERR_BADFILETYPE;
        case DXFILEERR_BADFILEVERSION:
            return D3DXFERR_BADFILEVERSION;
        case DXFILEERR_BADFILEFLOATSIZE:
            return D3DXFERR_BADFILEFLOATSIZE;
        case DXFILEERR_PARSEERROR:
            return D3DXFERR_PARSEERROR;
41 42
        case DXFILEERR_BADVALUE:
            return D3DXFERR_BADVALUE;
43 44 45 46 47 48
        default:
            FIXME("Cannot map error %#x\n", error);
            return E_FAIL;
    }
}

49 50
struct d3dx9_file
{
51 52
    ID3DXFile ID3DXFile_iface;
    LONG ref;
53
    IDirectXFile *dxfile;
54
};
55

56 57
struct d3dx9_file_enum_object
{
58 59
    ID3DXFileEnumObject ID3DXFileEnumObject_iface;
    LONG ref;
60 61
    ULONG nb_children;
    ID3DXFileData **children;
62
};
63

64 65
struct d3dx9_file_data
{
66 67
    ID3DXFileData ID3DXFileData_iface;
    LONG ref;
68
    BOOL reference;
69
    IDirectXFileData *dxfile_data;
70 71
    ULONG nb_children;
    ID3DXFileData **children;
72
};
73

74
static inline struct d3dx9_file *impl_from_ID3DXFile(ID3DXFile *iface)
75
{
76
    return CONTAINING_RECORD(iface, struct d3dx9_file, ID3DXFile_iface);
77 78
}

79
static inline struct d3dx9_file_enum_object *impl_from_ID3DXFileEnumObject(ID3DXFileEnumObject *iface)
80
{
81
    return CONTAINING_RECORD(iface, struct d3dx9_file_enum_object, ID3DXFileEnumObject_iface);
82 83
}

84
static inline struct d3dx9_file_data *impl_from_ID3DXFileData(ID3DXFileData *iface)
85
{
86
    return CONTAINING_RECORD(iface, struct d3dx9_file_data, ID3DXFileData_iface);
87 88
}

89
static HRESULT WINAPI d3dx9_file_data_QueryInterface(ID3DXFileData *iface, REFIID riid, void **out)
90
{
91
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
92

93 94
    if (IsEqualGUID(riid, &IID_ID3DXFileData)
            || IsEqualGUID(riid, &IID_IUnknown))
95 96
    {
        iface->lpVtbl->AddRef(iface);
97
        *out = iface;
98 99 100
        return S_OK;
    }

101 102 103
    WARN("Interface %s not found.\n", debugstr_guid(riid));

    *out = NULL;
104 105 106
    return E_NOINTERFACE;
}

107
static ULONG WINAPI d3dx9_file_data_AddRef(ID3DXFileData *iface)
108
{
109 110
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
    ULONG refcount = InterlockedIncrement(&file_data->ref);
111

112
    TRACE("%p increasing refcount to %u.\n", file_data, refcount);
113

114
    return refcount;
115 116
}

117
static ULONG WINAPI d3dx9_file_data_Release(ID3DXFileData *iface)
118
{
119 120
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
    ULONG refcount = InterlockedDecrement(&file_data->ref);
121

122
    TRACE("%p decreasing refcount to %u.\n", file_data, refcount);
123

124
    if (!refcount)
125
    {
126 127
        ULONG i;

128 129 130 131 132 133 134 135
        for (i = 0; i < file_data->nb_children; ++i)
        {
            ID3DXFileData *child = file_data->children[i];
            child->lpVtbl->Release(child);
        }
        HeapFree(GetProcessHeap(), 0, file_data->children);
        IDirectXFileData_Release(file_data->dxfile_data);
        HeapFree(GetProcessHeap(), 0, file_data);
136 137
    }

138
    return refcount;
139 140
}

141
static HRESULT WINAPI d3dx9_file_data_GetEnum(ID3DXFileData *iface, ID3DXFileEnumObject **enum_object)
142
{
143
    FIXME("iface %p, enum_object %p stub!\n", iface, enum_object);
144 145 146 147

    return E_NOTIMPL;
}

148
static HRESULT WINAPI d3dx9_file_data_GetName(ID3DXFileData *iface, char *name, SIZE_T *size)
149
{
150
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
151 152
    DWORD dxfile_size;
    HRESULT ret;
153

154
    TRACE("iface %p, name %p, size %p.\n", iface, name, size);
155

156 157
    if (!size)
        return D3DXFERR_BADVALUE;
158 159 160

    dxfile_size = *size;

161
    ret = IDirectXFileData_GetName(file_data->dxfile_data, name, &dxfile_size);
162 163 164
    if (ret != DXFILE_OK)
        return error_dxfile_to_d3dxfile(ret);

165 166 167 168 169 170 171 172 173
    if (!dxfile_size)
    {
        /* Contrary to d3dxof, d3dx9_36 returns an empty string with a null byte when no name is available.
         * If the input size is 0, it returns a length of 1 without touching the buffer */
        dxfile_size = 1;
        if (name && *size)
            name[0] = 0;
    }

174 175 176
    *size = dxfile_size;

    return S_OK;
177 178
}

179
static HRESULT WINAPI d3dx9_file_data_GetId(ID3DXFileData *iface, GUID *guid)
180
{
181
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
182
    HRESULT ret;
183

184
    TRACE("iface %p, guid %p.\n", iface, guid);
185 186 187 188

    if (!guid)
        return E_POINTER;

189
    ret = IDirectXFileData_GetId(file_data->dxfile_data, guid);
190 191 192 193
    if (ret != DXFILE_OK)
        return error_dxfile_to_d3dxfile(ret);

    return S_OK;
194 195
}

196
static HRESULT WINAPI d3dx9_file_data_Lock(ID3DXFileData *iface, SIZE_T *size, const void **data)
197
{
198
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
199 200
    DWORD dxfile_size;
    HRESULT ret;
201

202
    TRACE("iface %p, size %p, data %p.\n", iface, size, data);
203 204 205 206

    if (!size || !data)
        return E_POINTER;

207
    ret = IDirectXFileData_GetData(file_data->dxfile_data, NULL, &dxfile_size, (void **)data);
208 209 210 211 212 213
    if (ret != DXFILE_OK)
        return error_dxfile_to_d3dxfile(ret);

    *size = dxfile_size;

    return S_OK;
214 215
}

216
static HRESULT WINAPI d3dx9_file_data_Unlock(ID3DXFileData *iface)
217
{
218
    TRACE("iface %p.\n", iface);
219

220 221 222
    /* Nothing to do */

    return S_OK;
223 224
}

225
static HRESULT WINAPI d3dx9_file_data_GetType(ID3DXFileData *iface, GUID *guid)
226
{
227
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
228 229
    const GUID *dxfile_guid;
    HRESULT ret;
230

231
    TRACE("iface %p, guid %p.\n", iface, guid);
232

233
    ret = IDirectXFileData_GetType(file_data->dxfile_data, &dxfile_guid);
234 235 236 237 238 239
    if (ret != DXFILE_OK)
        return error_dxfile_to_d3dxfile(ret);

    *guid = *dxfile_guid;

    return S_OK;
240 241
}

242
static BOOL WINAPI d3dx9_file_data_IsReference(ID3DXFileData *iface)
243
{
244
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
245

246
    TRACE("iface %p.\n", iface);
247

248
    return file_data->reference;
249 250
}

251
static HRESULT WINAPI d3dx9_file_data_GetChildren(ID3DXFileData *iface, SIZE_T *children)
252
{
253
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
254

255
    TRACE("iface %p, children %p.\n", iface, children);
256 257 258 259

    if (!children)
        return E_POINTER;

260
    *children = file_data->nb_children;
261 262

    return S_OK;
263 264
}

265
static HRESULT WINAPI d3dx9_file_data_GetChild(ID3DXFileData *iface, SIZE_T id, ID3DXFileData **object)
266
{
267
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
268

269
    TRACE("iface %p, id %#lx, object %p.\n", iface, id, object);
270 271 272 273

    if (!object)
        return E_POINTER;

274
    *object = file_data->children[id];
275 276 277
    (*object)->lpVtbl->AddRef(*object);

    return S_OK;
278 279
}

280 281 282 283 284 285 286 287 288 289 290 291 292 293
static const ID3DXFileDataVtbl d3dx9_file_data_vtbl =
{
    d3dx9_file_data_QueryInterface,
    d3dx9_file_data_AddRef,
    d3dx9_file_data_Release,
    d3dx9_file_data_GetEnum,
    d3dx9_file_data_GetName,
    d3dx9_file_data_GetId,
    d3dx9_file_data_Lock,
    d3dx9_file_data_Unlock,
    d3dx9_file_data_GetType,
    d3dx9_file_data_IsReference,
    d3dx9_file_data_GetChildren,
    d3dx9_file_data_GetChild,
294 295
};

296
static HRESULT d3dx9_file_data_create(IDirectXFileObject *dxfile_object, ID3DXFileData **ret_iface)
297
{
298
    struct d3dx9_file_data *object;
299 300
    IDirectXFileObject *data_object;
    HRESULT ret;
301

302
    TRACE("dxfile_object %p, ret_iface %p.\n", dxfile_object, ret_iface);
303 304 305

    *ret_iface = NULL;

306
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
307 308 309
    if (!object)
        return E_OUTOFMEMORY;

310
    object->ID3DXFileData_iface.lpVtbl = &d3dx9_file_data_vtbl;
311
    object->ref = 1;
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326

    ret = IDirectXFileObject_QueryInterface(dxfile_object, &IID_IDirectXFileData, (void **)&object->dxfile_data);
    if (FAILED(ret))
    {
        IDirectXFileDataReference *reference;

        ret = IDirectXFileObject_QueryInterface(dxfile_object, &IID_IDirectXFileDataReference, (void **)&reference);
        if (SUCCEEDED(ret))
        {
            ret = IDirectXFileDataReference_Resolve(reference, &object->dxfile_data);
            if (FAILED(ret))
            {
                HeapFree(GetProcessHeap(), 0, object);
                return E_FAIL;
            }
327
            object->reference = TRUE;
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
        }
        else
        {
            FIXME("Don't known what to do with binary object\n");
            HeapFree(GetProcessHeap(), 0, object);
            return E_FAIL;
        }
    }

    while (SUCCEEDED(ret = IDirectXFileData_GetNextObject(object->dxfile_data, &data_object)))
    {
        if (object->children)
            object->children = HeapReAlloc(GetProcessHeap(), 0, object->children, sizeof(ID3DXFileData*) * (object->nb_children + 1));
        else
            object->children = HeapAlloc(GetProcessHeap(), 0, sizeof(ID3DXFileData*));
        if (!object->children)
        {
            ret = E_OUTOFMEMORY;
            break;
        }
348
        if (FAILED(ret = d3dx9_file_data_create(data_object, &object->children[object->nb_children])))
349 350 351 352 353 354 355 356 357 358 359
            break;
        object->nb_children++;
    }

    if (ret != DXFILEERR_NOMOREOBJECTS)
    {
        (&object->ID3DXFileData_iface)->lpVtbl->Release(&object->ID3DXFileData_iface);
        return ret;
    }

    TRACE("Found %u children\n", object->nb_children);
360 361 362 363 364 365

    *ret_iface = &object->ID3DXFileData_iface;

    return S_OK;
}

366
static HRESULT WINAPI d3dx9_file_enum_object_QueryInterface(ID3DXFileEnumObject *iface, REFIID riid, void **out)
367
{
368
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
369

370 371
    if (IsEqualGUID(riid, &IID_ID3DXFileEnumObject)
            || IsEqualGUID(riid, &IID_IUnknown))
372 373
    {
        iface->lpVtbl->AddRef(iface);
374
        *out = iface;
375 376 377
        return S_OK;
    }

378 379 380
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

    *out = NULL;
381 382 383
    return E_NOINTERFACE;
}

384
static ULONG WINAPI d3dx9_file_enum_object_AddRef(ID3DXFileEnumObject *iface)
385
{
386 387
    struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
    ULONG refcount = InterlockedIncrement(&file_enum->ref);
388

389
    TRACE("%p increasing refcount to %u.\n", file_enum, refcount);
390

391
    return refcount;
392 393
}

394
static ULONG WINAPI d3dx9_file_enum_object_Release(ID3DXFileEnumObject *iface)
395
{
396 397
    struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
    ULONG refcount = InterlockedDecrement(&file_enum->ref);
398

399
    TRACE("%p decreasing refcount to %u.\n", file_enum, refcount);
400

401
    if (!refcount)
402 403 404
    {
        ULONG i;

405 406 407 408 409 410 411
        for (i = 0; i < file_enum->nb_children; ++i)
        {
            ID3DXFileData *child = file_enum->children[i];
            child->lpVtbl->Release(child);
        }
        HeapFree(GetProcessHeap(), 0, file_enum->children);
        HeapFree(GetProcessHeap(), 0, file_enum);
412
    }
413

414
    return refcount;
415 416
}

417
static HRESULT WINAPI d3dx9_file_enum_object_GetFile(ID3DXFileEnumObject *iface, ID3DXFile **file)
418
{
419
    FIXME("iface %p, file %p stub!\n", iface, file);
420 421 422 423

    return E_NOTIMPL;
}

424
static HRESULT WINAPI d3dx9_file_enum_object_GetChildren(ID3DXFileEnumObject *iface, SIZE_T *children)
425
{
426
    struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
427

428
    TRACE("iface %p, children %p.\n", iface, children);
429 430 431 432

    if (!children)
        return E_POINTER;

433
    *children = file_enum->nb_children;
434 435

    return S_OK;
436 437
}

438
static HRESULT WINAPI d3dx9_file_enum_object_GetChild(ID3DXFileEnumObject *iface, SIZE_T id, ID3DXFileData **object)
439
{
440
    struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
441

442
    TRACE("iface %p, id %#lx, object %p.\n", iface, id, object);
443 444 445 446

    if (!object)
        return E_POINTER;

447
    *object = file_enum->children[id];
448 449 450
    (*object)->lpVtbl->AddRef(*object);

    return S_OK;
451 452
}

453 454
static HRESULT WINAPI d3dx9_file_enum_object_GetDataObjectById(ID3DXFileEnumObject *iface,
        REFGUID guid, ID3DXFileData **object)
455
{
456
    FIXME("iface %p, guid %s, object %p stub!\n", iface, debugstr_guid(guid), object);
457 458 459 460

    return E_NOTIMPL;
}

461 462
static HRESULT WINAPI d3dx9_file_enum_object_GetDataObjectByName(ID3DXFileEnumObject *iface,
        const char *name, ID3DXFileData **object)
463
{
464
    FIXME("iface %p, name %s, object %p stub!\n", iface, debugstr_a(name), object);
465 466 467 468

    return E_NOTIMPL;
}

469
static const ID3DXFileEnumObjectVtbl d3dx9_file_enum_object_vtbl =
470
{
471 472 473 474 475 476 477 478
    d3dx9_file_enum_object_QueryInterface,
    d3dx9_file_enum_object_AddRef,
    d3dx9_file_enum_object_Release,
    d3dx9_file_enum_object_GetFile,
    d3dx9_file_enum_object_GetChildren,
    d3dx9_file_enum_object_GetChild,
    d3dx9_file_enum_object_GetDataObjectById,
    d3dx9_file_enum_object_GetDataObjectByName,
479 480
};

481
static HRESULT WINAPI d3dx9_file_QueryInterface(ID3DXFile *iface, REFIID riid, void **out)
482
{
483
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
484

485 486
    if (IsEqualGUID(riid, &IID_ID3DXFile)
            || IsEqualGUID(riid, &IID_IUnknown))
487 488
    {
        iface->lpVtbl->AddRef(iface);
489
        *out = iface;
490 491 492
        return S_OK;
    }

493 494 495
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

    *out = NULL;
496 497 498
    return E_NOINTERFACE;
}

499
static ULONG WINAPI d3dx9_file_AddRef(ID3DXFile *iface)
500
{
501 502
    struct d3dx9_file *file = impl_from_ID3DXFile(iface);
    ULONG refcount = InterlockedIncrement(&file->ref);
503

504
    TRACE("%p increasing refcount to %u.\n", file, refcount);
505

506
    return refcount;
507 508
}

509
static ULONG WINAPI d3dx9_file_Release(ID3DXFile *iface)
510
{
511 512
    struct d3dx9_file *file = impl_from_ID3DXFile(iface);
    ULONG refcount = InterlockedDecrement(&file->ref);
513

514
    TRACE("%p decreasing refcount to %u.\n", file, refcount);
515

516
    if (!refcount)
517
    {
518 519
        IDirectXFile_Release(file->dxfile);
        HeapFree(GetProcessHeap(), 0, file);
520
    }
521

522
    return refcount;
523 524
}

525 526
static HRESULT WINAPI d3dx9_file_CreateEnumObject(ID3DXFile *iface, const void *source,
        D3DXF_FILELOADOPTIONS options, ID3DXFileEnumObject **enum_object)
527
{
528
    struct d3dx9_file *file = impl_from_ID3DXFile(iface);
529
    struct d3dx9_file_enum_object *object;
530 531 532 533 534 535 536
    IDirectXFileEnumObject *dxfile_enum_object;
    void *dxfile_source;
    DXFILELOADOPTIONS dxfile_options;
    DXFILELOADRESOURCE dxfile_resource;
    DXFILELOADMEMORY dxfile_memory;
    IDirectXFileData *data_object;
    HRESULT ret;
537

538
    TRACE("iface %p, source %p, options %#x, enum_object %p.\n", iface, source, options, enum_object);
539 540 541 542 543 544

    if (!enum_object)
        return E_POINTER;

    *enum_object = NULL;

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    if (options == D3DXF_FILELOAD_FROMFILE)
    {
        dxfile_source = (void*)source;
        dxfile_options = DXFILELOAD_FROMFILE;
    }
    else if (options == D3DXF_FILELOAD_FROMRESOURCE)
    {
        D3DXF_FILELOADRESOURCE *resource = (D3DXF_FILELOADRESOURCE*)source;

        dxfile_resource.hModule = resource->hModule;
        dxfile_resource.lpName = resource->lpName;
        dxfile_resource.lpType = resource->lpType;
        dxfile_source = &dxfile_resource;
        dxfile_options = DXFILELOAD_FROMRESOURCE;
    }
    else if (options == D3DXF_FILELOAD_FROMMEMORY)
    {
        D3DXF_FILELOADMEMORY *memory = (D3DXF_FILELOADMEMORY*)source;

        dxfile_memory.lpMemory = memory->lpMemory;
        dxfile_memory.dSize = memory->dSize;
        dxfile_source = &dxfile_memory;
        dxfile_options = DXFILELOAD_FROMMEMORY;
    }
    else
    {
        FIXME("Source type %u is not handled yet\n", options);
        return E_NOTIMPL;
    }

575
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
576 577 578
    if (!object)
        return E_OUTOFMEMORY;

579
    object->ID3DXFileEnumObject_iface.lpVtbl = &d3dx9_file_enum_object_vtbl;
580 581
    object->ref = 1;

582
    ret = IDirectXFile_CreateEnumObject(file->dxfile, dxfile_source, dxfile_options, &dxfile_enum_object);
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601

    if (ret != S_OK)
    {
        HeapFree(GetProcessHeap(), 0, object);
        return ret;
    }

    /* Fill enum object with top level data objects */
    while (SUCCEEDED(ret = IDirectXFileEnumObject_GetNextDataObject(dxfile_enum_object, &data_object)))
    {
        if (object->children)
            object->children = HeapReAlloc(GetProcessHeap(), 0, object->children, sizeof(*object->children) * (object->nb_children + 1));
        else
            object->children = HeapAlloc(GetProcessHeap(), 0, sizeof(*object->children));
        if (!object->children)
        {
            ret = E_OUTOFMEMORY;
            break;
        }
602 603
        if (FAILED(ret = d3dx9_file_data_create((IDirectXFileObject*)data_object,
                &object->children[object->nb_children])))
604 605 606 607 608 609 610 611 612 613 614
            break;
        object->nb_children++;
    }

    IDirectXFileEnumObject_Release(dxfile_enum_object);

    if (ret != DXFILEERR_NOMOREOBJECTS)
        WARN("Cannot get all top level data objects\n");

    TRACE("Found %u children\n", object->nb_children);

615 616 617
    *enum_object = &object->ID3DXFileEnumObject_iface;

    return S_OK;
618 619
}

620 621
static HRESULT WINAPI d3dx9_file_CreateSaveObject(ID3DXFile *iface, const void *data,
        D3DXF_FILESAVEOPTIONS options, D3DXF_FILEFORMAT format, ID3DXFileSaveObject **save_object)
622
{
623 624
    FIXME("iface %p, data %p, options %#x, format %#x, save_object %p stub!\n",
            iface, data, options, format, save_object);
625 626 627 628

    return E_NOTIMPL;
}

629
static HRESULT WINAPI d3dx9_file_RegisterTemplates(ID3DXFile *iface, const void *data, SIZE_T size)
630
{
631
    struct d3dx9_file *file = impl_from_ID3DXFile(iface);
632
    HRESULT ret;
633

634
    TRACE("iface %p, data %p, size %lu.\n", iface, data, size);
635

636
    ret = IDirectXFile_RegisterTemplates(file->dxfile, (void *)data, size);
637 638 639 640 641 642 643
    if (ret != DXFILE_OK)
    {
        WARN("Error %#x\n", ret);
        return error_dxfile_to_d3dxfile(ret);
    }

    return S_OK;
644 645
}

646
static HRESULT WINAPI d3dx9_file_RegisterEnumTemplates(ID3DXFile *iface, ID3DXFileEnumObject *enum_object)
647
{
648
    FIXME("iface %p, enum_object %p stub!\n", iface, enum_object);
649 650 651 652

    return E_NOTIMPL;
}

653
static const ID3DXFileVtbl d3dx9_file_vtbl =
654
{
655 656 657 658 659 660 661
    d3dx9_file_QueryInterface,
    d3dx9_file_AddRef,
    d3dx9_file_Release,
    d3dx9_file_CreateEnumObject,
    d3dx9_file_CreateSaveObject,
    d3dx9_file_RegisterTemplates,
    d3dx9_file_RegisterEnumTemplates,
662 663 664 665
};

HRESULT WINAPI D3DXFileCreate(ID3DXFile **d3dxfile)
{
666
    struct d3dx9_file *object;
667
    HRESULT ret;
668

669
    TRACE("d3dxfile %p.\n", d3dxfile);
670 671 672 673 674 675 676 677 678 679

    if (!d3dxfile)
        return E_POINTER;

    *d3dxfile = NULL;

    object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object));
    if (!object)
        return E_OUTOFMEMORY;

680 681 682 683 684 685 686 687 688
    ret = DirectXFileCreate(&object->dxfile);
    if (ret != S_OK)
    {
        HeapFree(GetProcessHeap(), 0, object);
        if (ret == E_OUTOFMEMORY)
            return ret;
        return E_FAIL;
    }

689
    object->ID3DXFile_iface.lpVtbl = &d3dx9_file_vtbl;
690 691 692 693 694 695
    object->ref = 1;

    *d3dxfile = &object->ID3DXFile_iface;

    return S_OK;
}