/* * Copyright 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 #include "wine/test.h" #include "d3dx9.h" #include "d3dx9xof.h" static const char templates_bad_file_type1[] = "xOf 0302txt 0064\n"; static const char templates_bad_file_version[] = "xof 0102txt 0064\n"; static const char templates_bad_file_type2[] = "xof 0302foo 0064\n"; static const char templates_bad_file_float_size[] = "xof 0302txt 0050\n"; static const char templates_parse_error[] = "xof 0302txt 0064" "foobar;\n"; static const char templates[] = "xof 0302txt 0064" "template Header" "{" "<3D82AB43-62DA-11CF-AB39-0020AF71E433>" "WORD major;" "WORD minor;" "DWORD flags;" "}\n"; static char objects[] = "xof 0302txt 0064\n" "Header Object\n" "{\n" "1; 2; 3;\n" "}\n"; static char object_noname[] = "xof 0302txt 0064\n" "Header\n" "{\n" "1; 2; 3;\n" "}\n"; static char template_using_index_color_lower[] = "xof 0302txt 0064\n" "template MeshVertexColors\n" "{\n" "<1630B821-7842-11cf-8F52-0040333594A3>\n" "DWORD nVertexColors;\n" "array indexColor vertexColors[nVertexColors];\n" "}\n"; static char template_using_index_color_upper[] = "xof 0302txt 0064\n" "template MeshVertexColors\n" "{\n" "<1630B821-7842-11cf-8F52-0040333594A3>\n" "DWORD nVertexColors;\n" "array IndexColor vertexColors[nVertexColors];\n" "}\n"; static void test_templates(void) { ID3DXFile *d3dxfile; HRESULT ret; ret = D3DXFileCreate(NULL); ok(ret == E_POINTER, "D3DXCreateFile returned %#x, expected %#x\n", ret, E_POINTER); ret = D3DXFileCreate(&d3dxfile); ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_type1, sizeof(templates_bad_file_type1) - 1); ok(ret == D3DXFERR_BADFILETYPE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILETYPE); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_version, sizeof(templates_bad_file_version) - 1); ok(ret == D3DXFERR_BADFILEVERSION, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILEVERSION); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_type2, sizeof(templates_bad_file_type2) - 1); ok(ret == D3DXFERR_BADFILETYPE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILETYPE); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_float_size, sizeof(templates_bad_file_float_size) - 1); ok(ret == D3DXFERR_BADFILEFLOATSIZE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILEFLOATSIZE); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_parse_error, sizeof(templates_parse_error) - 1); ok(ret == D3DXFERR_PARSEERROR, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_PARSEERROR); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1); ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); d3dxfile->lpVtbl->Release(d3dxfile); } static void test_lock_unlock(void) { ID3DXFile *d3dxfile; D3DXF_FILELOADMEMORY memory; ID3DXFileEnumObject *enum_object; ID3DXFileData *data_object; const void *data; SIZE_T size; HRESULT ret; ret = D3DXFileCreate(&d3dxfile); ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1); ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); memory.lpMemory = objects; memory.dSize = sizeof(objects) - 1; ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object); ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret); ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object); ok(ret == S_OK, "GetChild failed with %#x\n", ret); ret = data_object->lpVtbl->Unlock(data_object); ok(ret == S_OK, "Unlock failed with %#x\n", ret); ret = data_object->lpVtbl->Lock(data_object, &size, &data); ok(ret == S_OK, "Lock failed with %#x\n", ret); ret = data_object->lpVtbl->Lock(data_object, &size, &data); ok(ret == S_OK, "Lock failed with %#x\n", ret); ret = data_object->lpVtbl->Unlock(data_object); ok(ret == S_OK, "Unlock failed with %#x\n", ret); ret = data_object->lpVtbl->Unlock(data_object); ok(ret == S_OK, "Unlock failed with %#x\n", ret); data_object->lpVtbl->Release(data_object); enum_object->lpVtbl->Release(enum_object); d3dxfile->lpVtbl->Release(d3dxfile); } static void test_getname(void) { ID3DXFile *d3dxfile; D3DXF_FILELOADMEMORY memory; ID3DXFileEnumObject *enum_object; ID3DXFileData *data_object; SIZE_T length; char name[100]; HRESULT ret; ret = D3DXFileCreate(&d3dxfile); ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1); ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); /* Check object with name */ memory.lpMemory = objects; memory.dSize = sizeof(objects) - 1; ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object); ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret); ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object); ok(ret == S_OK, "GetChild failed with %#x\n", ret); ret = data_object->lpVtbl->GetName(data_object, NULL, NULL); ok(ret == D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE); ret = data_object->lpVtbl->GetName(data_object, name, NULL); ok(ret == D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE); ret = data_object->lpVtbl->GetName(data_object, NULL, &length); ok(ret == S_OK, "GetName failed with %#x\n", ret); ok(length == 7, "Returned length should be 7 instead of %ld\n", length); length = sizeof(name); ret = data_object->lpVtbl->GetName(data_object, name, &length); ok(ret == S_OK, "GetName failed with %#x\n", ret); ok(length == 7, "Returned length should be 7 instead of %ld\n", length); ok(!strcmp(name, "Object"), "Returned string should be 'Object' intead of '%s'\n", name); length = 3; ret = data_object->lpVtbl->GetName(data_object, name, &length); ok(ret== D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE); data_object->lpVtbl->Release(data_object); enum_object->lpVtbl->Release(enum_object); /* Check object without name */ memory.lpMemory = object_noname; memory.dSize = sizeof(object_noname) - 1; ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object); ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret); ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object); ok(ret == S_OK, "GetChild failed with %#x\n", ret); /* 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 */ ret = data_object->lpVtbl->GetName(data_object, NULL, &length); ok(ret == S_OK, "GetName failed with %#x\n", ret); ok(length == 1, "Returned length should be 1 instead of %ld\n", length); length = 0; name[0] = 0x7f; ret = data_object->lpVtbl->GetName(data_object, name, &length); ok(ret == S_OK, "GetName failed with %#x\n", ret); ok(length == 1, "Returned length should be 1 instead of %ld\n", length); ok(name[0] == 0x7f, "First character is %#x instead of 0x7f\n", name[0]); length = sizeof(name); name[0] = 0x7f; ret = data_object->lpVtbl->GetName(data_object, name, &length); ok(ret == S_OK, "GetName failed with %#x\n", ret); ok(length == 1, "Returned length should be 1 instead of %ld\n", length); ok(name[0] == 0, "First character is %#x instead of 0x00\n", name[0]); data_object->lpVtbl->Release(data_object); enum_object->lpVtbl->Release(enum_object); d3dxfile->lpVtbl->Release(d3dxfile); } static void test_type_index_color(void) { ID3DXFile *d3dxfile; HRESULT ret; ret = D3DXFileCreate(&d3dxfile); ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); /* Test that 'indexColor' can be used (same as IndexedColor in standard templates) and is case sensitive */ ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, template_using_index_color_lower, sizeof(template_using_index_color_lower) - 1); ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, template_using_index_color_upper, sizeof(template_using_index_color_upper) - 1); ok(ret == D3DXFERR_PARSEERROR, "RegisterTemplates returned %#x instead of %#x\n", ret, D3DXFERR_PARSEERROR); d3dxfile->lpVtbl->Release(d3dxfile); } static inline void debugstr_guid(char* buf, const GUID *id) { sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", id->Data1, id->Data2, id->Data3, id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); } static void process_data(ID3DXFileData *xfile_data, int level) { HRESULT ret; char name[100]; GUID clsid; GUID clsid_type; char str_clsid[40]; char str_clsid_type[40]; SIZE_T len = sizeof(name); int i; const BYTE *data; SIZE_T size; SIZE_T children; ret = xfile_data->lpVtbl->GetId(xfile_data, &clsid); ok(ret == S_OK, "ID3DXFileData_GetId failed with %#x\n", ret); ret = xfile_data->lpVtbl->GetName(xfile_data, name, &len); ok(ret == S_OK, "ID3DXFileData_GetName failed with %#x\n", ret); ret = xfile_data->lpVtbl->GetType(xfile_data, &clsid_type); ok(ret == S_OK, "IDirectXFileData_GetType failed with %#x\n", ret); ret = xfile_data->lpVtbl->Lock(xfile_data, &size, (const void**)&data); ok(ret == S_OK, "IDirectXFileData_Lock failed with %#x\n", ret); for (i = 0; i < level; i++) printf(" "); debugstr_guid(str_clsid, &clsid); debugstr_guid(str_clsid_type, &clsid_type); printf("Found object '%s' - %s - %s - %lu\n", len ? name : "", str_clsid, str_clsid_type, size); if (size) { int j; for (j = 0; j < size; j++) { if (j && !(j%16)) printf("\n"); printf("%02x ", data[j]); } printf("\n"); } ret = xfile_data->lpVtbl->Unlock(xfile_data); ok(ret == S_OK, "ID3DXFileData_Unlock failed with %#x\n", ret); ret = xfile_data->lpVtbl->GetChildren(xfile_data, &children); ok(ret == S_OK, "ID3DXFileData_GetChildren failed with %#x\n", ret); level++; for (i = 0; i < children; i++) { ID3DXFileData *child; int j; ret = xfile_data->lpVtbl->GetChild(xfile_data, i, &child); ok(ret == S_OK, "ID3DXFileData_GetChild failed with %#x\n", ret); for (j = 0; j < level; j++) printf(" "); if (child->lpVtbl->IsReference(child)) printf("Found Data Reference (%d)\n", i + 1); else printf("Found Data (%d)\n", i + 1); process_data(child, level); child->lpVtbl->Release(child); } } /* Dump an X file 'objects.x' and its related templates file 'templates.x' if they are both presents * Useful for debug by comparing outputs from native and builtin dlls */ static void test_dump(void) { HRESULT ret; ULONG ref; ID3DXFile *xfile = NULL; ID3DXFileEnumObject *xfile_enum_object = NULL; HANDLE file; void *data; DWORD size; SIZE_T children; int i; /* Dump data only if there is an object and a template */ file = CreateFileA("objects.x", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (file == INVALID_HANDLE_VALUE) return; CloseHandle(file); file = CreateFileA("templates.x", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (file == INVALID_HANDLE_VALUE) return; data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 10000); if (!ReadFile(file, data, 10000, &size, NULL)) { skip("Templates file is too big\n"); goto exit; } printf("Load templates file (%d bytes)\n", size); ret = D3DXFileCreate(&xfile); ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); ret = xfile->lpVtbl->RegisterTemplates(xfile, data, size); ok(ret == S_OK, "ID3DXFileImpl_RegisterTemplates failed with %#x\n", ret); ret = xfile->lpVtbl->CreateEnumObject(xfile, (void*)"objects.x", D3DXF_FILELOAD_FROMFILE, &xfile_enum_object); ok(ret == S_OK, "ID3DXFile_CreateEnumObject failed with %#x\n", ret); ret = xfile_enum_object->lpVtbl->GetChildren(xfile_enum_object, &children); ok(ret == S_OK, "ID3DXFileEnumObject_GetChildren failed with %#x\n", ret); for (i = 0; i < children; i++) { ID3DXFileData *child; ret = xfile_enum_object->lpVtbl->GetChild(xfile_enum_object, i, &child); ok(ret == S_OK, "ID3DXFileEnumObject_GetChild failed with %#x\n", ret); printf("\n"); process_data(child, 0); child->lpVtbl->Release(child); } ref = xfile_enum_object->lpVtbl->Release(xfile_enum_object); ok(ref == 0, "Got refcount %u, expected 0\n", ref); ref = xfile->lpVtbl->Release(xfile); ok(ref == 0, "Got refcount %u, expected 0\n", ref); exit: CloseHandle(file); HeapFree(GetProcessHeap(), 0, data); } START_TEST(xfile) { test_templates(); test_lock_unlock(); test_getname(); test_type_index_color(); test_dump(); }