xfile.c 20.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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"

22
#define COBJMACROS
23 24
#include "d3dx9.h"
#include "d3dx9xof.h"
25 26
#undef MAKE_DDHRESULT
#include "dxfile.h"
27 28 29

WINE_DEFAULT_DEBUG_CHANNEL(d3dx);

30
static HRESULT error_dxfile_to_d3dxfile(HRESULT error)
31 32 33 34 35 36 37 38 39 40 41
{
    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;
42 43
        case DXFILEERR_BADVALUE:
            return D3DXFERR_BADVALUE;
44 45 46 47 48 49
        default:
            FIXME("Cannot map error %#x\n", error);
            return E_FAIL;
    }
}

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

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

65 66
struct d3dx9_file_data
{
67 68
    ID3DXFileData ID3DXFileData_iface;
    LONG ref;
69
    BOOL reference;
70
    IDirectXFileData *dxfile_data;
71 72
    ULONG nb_children;
    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 95
    if (IsEqualGUID(riid, &IID_ID3DXFileData)
            || IsEqualGUID(riid, &IID_IUnknown))
96 97
    {
        iface->lpVtbl->AddRef(iface);
98
        *out = iface;
99 100 101
        return S_OK;
    }

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

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

108
static ULONG WINAPI d3dx9_file_data_AddRef(ID3DXFileData *iface)
109
{
110 111
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
    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 121
    struct d3dx9_file_data *file_data = impl_from_ID3DXFileData(iface);
    ULONG refcount = InterlockedDecrement(&file_data->ref);
122

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

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

129 130 131 132 133 134 135 136
        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);
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 147 148

    return E_NOTIMPL;
}

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 153
    DWORD dxfile_size;
    HRESULT ret;
154

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

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

    dxfile_size = *size;

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

166 167 168 169 170 171 172 173 174
    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;
    }

175 176 177
    *size = dxfile_size;

    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 188 189

    if (!guid)
        return E_POINTER;

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

    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 201
    DWORD dxfile_size;
    HRESULT ret;
202

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

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

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

    *size = dxfile_size;

    return S_OK;
215 216
}

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

221 222 223
    /* Nothing to do */

    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 230
    const GUID *dxfile_guid;
    HRESULT ret;
231

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

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

    *guid = *dxfile_guid;

    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 259 260

    if (!children)
        return E_POINTER;

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 273 274

    if (!object)
        return E_POINTER;

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

    return S_OK;
279 280
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294
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,
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 307

    *ret_iface = NULL;

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

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

    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);
324
            IUnknown_Release(reference);
325 326 327 328 329
            if (FAILED(ret))
            {
                HeapFree(GetProcessHeap(), 0, object);
                return E_FAIL;
            }
330
            object->reference = TRUE;
331 332 333
        }
        else
        {
334
            FIXME("Don't know what to do with binary object\n");
335 336 337 338 339 340 341
            HeapFree(GetProcessHeap(), 0, object);
            return E_FAIL;
        }
    }

    while (SUCCEEDED(ret = IDirectXFileData_GetNextObject(object->dxfile_data, &data_object)))
    {
342
        if (object->nb_children >= children_array_size)
343
        {
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
            ID3DXFileData **new_children;

            if (object->children)
            {
                children_array_size *= 2;
                new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
                        sizeof(*object->children) * children_array_size);
            }
            else
            {
                children_array_size = 4;
                new_children = HeapAlloc(GetProcessHeap(), 0, sizeof(*object->children) * children_array_size);
            }
            if (!new_children)
            {
                ret = E_OUTOFMEMORY;
                break;
            }
            object->children = new_children;
363
        }
364 365 366
        ret = d3dx9_file_data_create(data_object, &object->children[object->nb_children]);
        IUnknown_Release(data_object);
        if (FAILED(ret))
367 368 369 370 371 372 373 374
            break;
        object->nb_children++;
    }
    if (ret != DXFILEERR_NOMOREOBJECTS)
    {
        (&object->ID3DXFileData_iface)->lpVtbl->Release(&object->ID3DXFileData_iface);
        return ret;
    }
375 376 377 378 379 380 381 382 383
    if (object->children)
    {
        ID3DXFileData **new_children;

        new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
                sizeof(*object->children) * object->nb_children);
        if (new_children)
            object->children = new_children;
    }
384 385

    TRACE("Found %u children\n", object->nb_children);
386 387 388 389 390 391

    *ret_iface = &object->ID3DXFileData_iface;

    return S_OK;
}

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 397
    if (IsEqualGUID(riid, &IID_ID3DXFileEnumObject)
            || IsEqualGUID(riid, &IID_IUnknown))
398 399
    {
        iface->lpVtbl->AddRef(iface);
400
        *out = iface;
401 402 403
        return S_OK;
    }

404 405 406
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

    *out = NULL;
407 408 409
    return E_NOINTERFACE;
}

410
static ULONG WINAPI d3dx9_file_enum_object_AddRef(ID3DXFileEnumObject *iface)
411
{
412 413
    struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
    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 423
    struct d3dx9_file_enum_object *file_enum = impl_from_ID3DXFileEnumObject(iface);
    ULONG refcount = InterlockedDecrement(&file_enum->ref);
424

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

427
    if (!refcount)
428 429 430
    {
        ULONG i;

431 432 433 434 435 436 437
        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);
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 448 449

    return E_NOTIMPL;
}

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 457 458

    if (!children)
        return E_POINTER;

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 471 472

    if (!object)
        return E_POINTER;

473
    *object = file_enum->children[id];
474 475 476
    (*object)->lpVtbl->AddRef(*object);

    return S_OK;
477 478
}

479 480
static HRESULT WINAPI d3dx9_file_enum_object_GetDataObjectById(ID3DXFileEnumObject *iface,
        REFGUID guid, ID3DXFileData **object)
481
{
482
    FIXME("iface %p, guid %s, object %p stub!\n", iface, debugstr_guid(guid), object);
483 484 485 486

    return E_NOTIMPL;
}

487 488
static HRESULT WINAPI d3dx9_file_enum_object_GetDataObjectByName(ID3DXFileEnumObject *iface,
        const char *name, ID3DXFileData **object)
489
{
490
    FIXME("iface %p, name %s, object %p stub!\n", iface, debugstr_a(name), object);
491 492 493 494

    return E_NOTIMPL;
}

495
static const ID3DXFileEnumObjectVtbl d3dx9_file_enum_object_vtbl =
496
{
497 498 499 500 501 502 503 504
    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,
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 512
    if (IsEqualGUID(riid, &IID_ID3DXFile)
            || IsEqualGUID(riid, &IID_IUnknown))
513 514
    {
        iface->lpVtbl->AddRef(iface);
515
        *out = iface;
516 517 518
        return S_OK;
    }

519 520 521
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

    *out = NULL;
522 523 524
    return E_NOINTERFACE;
}

525
static ULONG WINAPI d3dx9_file_AddRef(ID3DXFile *iface)
526
{
527 528
    struct d3dx9_file *file = impl_from_ID3DXFile(iface);
    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 538
    struct d3dx9_file *file = impl_from_ID3DXFile(iface);
    ULONG refcount = InterlockedDecrement(&file->ref);
539

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

542
    if (!refcount)
543
    {
544 545
        IDirectXFile_Release(file->dxfile);
        HeapFree(GetProcessHeap(), 0, file);
546
    }
547

548
    return refcount;
549 550
}

551 552
static HRESULT WINAPI d3dx9_file_CreateEnumObject(ID3DXFile *iface, const void *source,
        D3DXF_FILELOADOPTIONS options, ID3DXFileEnumObject **enum_object)
553
{
554
    struct d3dx9_file *file = impl_from_ID3DXFile(iface);
555
    struct d3dx9_file_enum_object *object;
556 557 558 559 560 561
    IDirectXFileEnumObject *dxfile_enum_object;
    void *dxfile_source;
    DXFILELOADOPTIONS dxfile_options;
    DXFILELOADRESOURCE dxfile_resource;
    DXFILELOADMEMORY dxfile_memory;
    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 568 569 570 571

    if (!enum_object)
        return E_POINTER;

    *enum_object = NULL;

572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
    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;
    }

602
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
603 604 605
    if (!object)
        return E_OUTOFMEMORY;

606
    object->ID3DXFileEnumObject_iface.lpVtbl = &d3dx9_file_enum_object_vtbl;
607 608
    object->ref = 1;

609
    ret = IDirectXFile_CreateEnumObject(file->dxfile, dxfile_source, dxfile_options, &dxfile_enum_object);
610 611 612 613 614 615 616 617 618 619

    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)))
    {
620
        if (object->nb_children >= children_array_size)
621
        {
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
            ID3DXFileData **new_children;

            if (object->children)
            {
                children_array_size *= 2;
                new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
                        sizeof(*object->children) * children_array_size);
            }
            else
            {
                children_array_size = 4;
                new_children = HeapAlloc(GetProcessHeap(), 0, sizeof(*object->children) * children_array_size);
            }
            if (!new_children)
            {
                ret = E_OUTOFMEMORY;
                break;
            }
            object->children = new_children;
641
        }
642 643 644 645
        ret = d3dx9_file_data_create((IDirectXFileObject*)data_object,
                &object->children[object->nb_children]);
        IUnknown_Release(data_object);
        if (FAILED(ret))
646 647 648
            break;
        object->nb_children++;
    }
649 650 651 652 653 654 655 656 657
    if (object->children)
    {
        ID3DXFileData **new_children;

        new_children = HeapReAlloc(GetProcessHeap(), 0, object->children,
                sizeof(*object->children) * object->nb_children);
        if (new_children)
            object->children = new_children;
    }
658 659 660 661 662 663 664 665

    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);

666 667 668
    *enum_object = &object->ID3DXFileEnumObject_iface;

    return S_OK;
669 670
}

671 672
static HRESULT WINAPI d3dx9_file_CreateSaveObject(ID3DXFile *iface, const void *data,
        D3DXF_FILESAVEOPTIONS options, D3DXF_FILEFORMAT format, ID3DXFileSaveObject **save_object)
673
{
674 675
    FIXME("iface %p, data %p, options %#x, format %#x, save_object %p stub!\n",
            iface, data, options, format, save_object);
676 677 678 679

    return E_NOTIMPL;
}

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 689 690 691 692 693 694
    if (ret != DXFILE_OK)
    {
        WARN("Error %#x\n", ret);
        return error_dxfile_to_d3dxfile(ret);
    }

    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 702 703

    return E_NOTIMPL;
}

704
static const ID3DXFileVtbl d3dx9_file_vtbl =
705
{
706 707 708 709 710 711 712
    d3dx9_file_QueryInterface,
    d3dx9_file_AddRef,
    d3dx9_file_Release,
    d3dx9_file_CreateEnumObject,
    d3dx9_file_CreateSaveObject,
    d3dx9_file_RegisterTemplates,
    d3dx9_file_RegisterEnumTemplates,
713 714 715 716
};

HRESULT WINAPI D3DXFileCreate(ID3DXFile **d3dxfile)
{
717
    struct d3dx9_file *object;
718
    HRESULT ret;
719

720
    TRACE("d3dxfile %p.\n", d3dxfile);
721 722 723 724 725 726 727 728 729 730

    if (!d3dxfile)
        return E_POINTER;

    *d3dxfile = NULL;

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

731 732 733 734 735 736 737 738 739
    ret = DirectXFileCreate(&object->dxfile);
    if (ret != S_OK)
    {
        HeapFree(GetProcessHeap(), 0, object);
        if (ret == E_OUTOFMEMORY)
            return ret;
        return E_FAIL;
    }

740
    object->ID3DXFile_iface.lpVtbl = &d3dx9_file_vtbl;
741 742 743 744 745 746
    object->ref = 1;

    *d3dxfile = &object->ID3DXFile_iface;

    return S_OK;
}