1 /* 2 * Copyright 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 #include <stdio.h> 20 21 #include "wine/test.h" 22 #include "d3dx9.h" 23 #include "d3dx9xof.h" 24 25 static const char templates_bad_file_type1[] = 26 "xOf 0302txt 0064\n"; 27 28 static const char templates_bad_file_version[] = 29 "xof 0102txt 0064\n"; 30 31 static const char templates_bad_file_type2[] = 32 "xof 0302foo 0064\n"; 33 34 static const char templates_bad_file_float_size[] = 35 "xof 0302txt 0050\n"; 36 37 static const char templates_parse_error[] = 38 "xof 0302txt 0064" 39 "foobar;\n"; 40 41 static const char templates[] = 42 "xof 0302txt 0064" 43 "template Header" 44 "{" 45 "<3D82AB43-62DA-11CF-AB39-0020AF71E433>" 46 "WORD major;" 47 "WORD minor;" 48 "DWORD flags;" 49 "}\n"; 50 51 static char objects[] = 52 "xof 0302txt 0064\n" 53 "Header Object\n" 54 "{\n" 55 "1; 2; 3;\n" 56 "}\n"; 57 58 static char object_noname[] = 59 "xof 0302txt 0064\n" 60 "Header\n" 61 "{\n" 62 "1; 2; 3;\n" 63 "}\n"; 64 65 static char template_using_index_color_lower[] = 66 "xof 0302txt 0064\n" 67 "template MeshVertexColors\n" 68 "{\n" 69 "<1630B821-7842-11cf-8F52-0040333594A3>\n" 70 "DWORD nVertexColors;\n" 71 "array indexColor vertexColors[nVertexColors];\n" 72 "}\n"; 73 74 static char template_using_index_color_upper[] = 75 "xof 0302txt 0064\n" 76 "template MeshVertexColors\n" 77 "{\n" 78 "<1630B821-7842-11cf-8F52-0040333594A3>\n" 79 "DWORD nVertexColors;\n" 80 "array IndexColor vertexColors[nVertexColors];\n" 81 "}\n"; 82 83 static void test_templates(void) 84 { 85 ID3DXFile *d3dxfile; 86 HRESULT ret; 87 88 ret = D3DXFileCreate(NULL); 89 ok(ret == E_POINTER, "D3DXCreateFile returned %#x, expected %#x\n", ret, E_POINTER); 90 91 ret = D3DXFileCreate(&d3dxfile); 92 ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); 93 94 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_type1, sizeof(templates_bad_file_type1) - 1); 95 ok(ret == D3DXFERR_BADFILETYPE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILETYPE); 96 97 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_version, sizeof(templates_bad_file_version) - 1); 98 ok(ret == D3DXFERR_BADFILEVERSION, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILEVERSION); 99 100 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_type2, sizeof(templates_bad_file_type2) - 1); 101 ok(ret == D3DXFERR_BADFILETYPE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILETYPE); 102 103 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_float_size, sizeof(templates_bad_file_float_size) - 1); 104 ok(ret == D3DXFERR_BADFILEFLOATSIZE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILEFLOATSIZE); 105 106 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_parse_error, sizeof(templates_parse_error) - 1); 107 ok(ret == D3DXFERR_PARSEERROR, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_PARSEERROR); 108 109 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1); 110 ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); 111 112 d3dxfile->lpVtbl->Release(d3dxfile); 113 } 114 115 static void test_lock_unlock(void) 116 { 117 ID3DXFile *d3dxfile; 118 D3DXF_FILELOADMEMORY memory; 119 ID3DXFileEnumObject *enum_object; 120 ID3DXFileData *data_object; 121 const void *data; 122 SIZE_T size; 123 HRESULT ret; 124 125 ret = D3DXFileCreate(&d3dxfile); 126 ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); 127 128 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1); 129 ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); 130 131 memory.lpMemory = objects; 132 memory.dSize = sizeof(objects) - 1; 133 134 ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object); 135 ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret); 136 137 ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object); 138 ok(ret == S_OK, "GetChild failed with %#x\n", ret); 139 140 ret = data_object->lpVtbl->Unlock(data_object); 141 ok(ret == S_OK, "Unlock failed with %#x\n", ret); 142 ret = data_object->lpVtbl->Lock(data_object, &size, &data); 143 ok(ret == S_OK, "Lock failed with %#x\n", ret); 144 ret = data_object->lpVtbl->Lock(data_object, &size, &data); 145 ok(ret == S_OK, "Lock failed with %#x\n", ret); 146 ret = data_object->lpVtbl->Unlock(data_object); 147 ok(ret == S_OK, "Unlock failed with %#x\n", ret); 148 ret = data_object->lpVtbl->Unlock(data_object); 149 ok(ret == S_OK, "Unlock failed with %#x\n", ret); 150 151 data_object->lpVtbl->Release(data_object); 152 enum_object->lpVtbl->Release(enum_object); 153 d3dxfile->lpVtbl->Release(d3dxfile); 154 } 155 156 static void test_getname(void) 157 { 158 ID3DXFile *d3dxfile; 159 D3DXF_FILELOADMEMORY memory; 160 ID3DXFileEnumObject *enum_object; 161 ID3DXFileData *data_object; 162 SIZE_T length; 163 char name[100]; 164 HRESULT ret; 165 166 ret = D3DXFileCreate(&d3dxfile); 167 ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); 168 169 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1); 170 ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); 171 172 /* Check object with name */ 173 memory.lpMemory = objects; 174 memory.dSize = sizeof(objects) - 1; 175 ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object); 176 ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret); 177 ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object); 178 ok(ret == S_OK, "GetChild failed with %#x\n", ret); 179 180 ret = data_object->lpVtbl->GetName(data_object, NULL, NULL); 181 ok(ret == D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE); 182 ret = data_object->lpVtbl->GetName(data_object, name, NULL); 183 ok(ret == D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE); 184 ret = data_object->lpVtbl->GetName(data_object, NULL, &length); 185 ok(ret == S_OK, "GetName failed with %#x\n", ret); 186 ok(length == 7, "Returned length should be 7 instead of %ld\n", length); 187 length = sizeof(name); 188 ret = data_object->lpVtbl->GetName(data_object, name, &length); 189 ok(ret == S_OK, "GetName failed with %#x\n", ret); 190 ok(length == 7, "Returned length should be 7 instead of %ld\n", length); 191 ok(!strcmp(name, "Object"), "Returned string should be 'Object' instead of '%s'\n", name); 192 length = 3; 193 ret = data_object->lpVtbl->GetName(data_object, name, &length); 194 ok(ret== D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE); 195 196 data_object->lpVtbl->Release(data_object); 197 enum_object->lpVtbl->Release(enum_object); 198 199 /* Check object without name */ 200 memory.lpMemory = object_noname; 201 memory.dSize = sizeof(object_noname) - 1; 202 ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object); 203 ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret); 204 ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object); 205 ok(ret == S_OK, "GetChild failed with %#x\n", ret); 206 207 /* Contrary to d3dxof, d3dx9_36 returns an empty string with a null byte when no name is available. 208 * If the input size is 0, it returns a length of 1 without touching the buffer */ 209 ret = data_object->lpVtbl->GetName(data_object, NULL, &length); 210 ok(ret == S_OK, "GetName failed with %#x\n", ret); 211 ok(length == 1, "Returned length should be 1 instead of %ld\n", length); 212 length = 0; 213 name[0] = 0x7f; 214 ret = data_object->lpVtbl->GetName(data_object, name, &length); 215 ok(ret == S_OK, "GetName failed with %#x\n", ret); 216 ok(length == 1, "Returned length should be 1 instead of %ld\n", length); 217 ok(name[0] == 0x7f, "First character is %#x instead of 0x7f\n", name[0]); 218 length = sizeof(name); 219 name[0] = 0x7f; 220 ret = data_object->lpVtbl->GetName(data_object, name, &length); 221 ok(ret == S_OK, "GetName failed with %#x\n", ret); 222 ok(length == 1, "Returned length should be 1 instead of %ld\n", length); 223 ok(name[0] == 0, "First character is %#x instead of 0x00\n", name[0]); 224 225 data_object->lpVtbl->Release(data_object); 226 enum_object->lpVtbl->Release(enum_object); 227 d3dxfile->lpVtbl->Release(d3dxfile); 228 } 229 230 static void test_type_index_color(void) 231 { 232 ID3DXFile *d3dxfile; 233 HRESULT ret; 234 235 ret = D3DXFileCreate(&d3dxfile); 236 ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); 237 238 /* Test that 'indexColor' can be used (same as IndexedColor in standard templates) and is case sensitive */ 239 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, template_using_index_color_lower, sizeof(template_using_index_color_lower) - 1); 240 ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret); 241 ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, template_using_index_color_upper, sizeof(template_using_index_color_upper) - 1); 242 ok(ret == D3DXFERR_PARSEERROR, "RegisterTemplates returned %#x instead of %#x\n", ret, D3DXFERR_PARSEERROR); 243 244 d3dxfile->lpVtbl->Release(d3dxfile); 245 } 246 247 static void process_data(ID3DXFileData *xfile_data, int level) 248 { 249 HRESULT ret; 250 char name[100]; 251 GUID clsid; 252 GUID clsid_type; 253 SIZE_T len = sizeof(name); 254 int i; 255 const BYTE *data; 256 SIZE_T size; 257 SIZE_T children; 258 259 ret = xfile_data->lpVtbl->GetId(xfile_data, &clsid); 260 ok(ret == S_OK, "ID3DXFileData_GetId failed with %#x\n", ret); 261 ret = xfile_data->lpVtbl->GetName(xfile_data, name, &len); 262 ok(ret == S_OK, "ID3DXFileData_GetName failed with %#x\n", ret); 263 ret = xfile_data->lpVtbl->GetType(xfile_data, &clsid_type); 264 ok(ret == S_OK, "IDirectXFileData_GetType failed with %#x\n", ret); 265 ret = xfile_data->lpVtbl->Lock(xfile_data, &size, (const void**)&data); 266 ok(ret == S_OK, "IDirectXFileData_Lock failed with %#x\n", ret); 267 268 for (i = 0; i < level; i++) 269 printf(" "); 270 271 printf("Found object '%s' - %s - %s - %lu\n", 272 len ? name : "", wine_dbgstr_guid(&clsid), wine_dbgstr_guid(&clsid_type), size); 273 274 if (size) 275 { 276 int j; 277 for (j = 0; j < size; j++) 278 { 279 if (j && !(j%16)) 280 printf("\n"); 281 printf("%02x ", data[j]); 282 } 283 printf("\n"); 284 } 285 286 ret = xfile_data->lpVtbl->Unlock(xfile_data); 287 ok(ret == S_OK, "ID3DXFileData_Unlock failed with %#x\n", ret); 288 289 ret = xfile_data->lpVtbl->GetChildren(xfile_data, &children); 290 ok(ret == S_OK, "ID3DXFileData_GetChildren failed with %#x\n", ret); 291 292 level++; 293 294 for (i = 0; i < children; i++) 295 { 296 ID3DXFileData *child; 297 int j; 298 299 ret = xfile_data->lpVtbl->GetChild(xfile_data, i, &child); 300 ok(ret == S_OK, "ID3DXFileData_GetChild failed with %#x\n", ret); 301 for (j = 0; j < level; j++) 302 printf(" "); 303 if (child->lpVtbl->IsReference(child)) 304 printf("Found Data Reference (%d)\n", i + 1); 305 else 306 printf("Found Data (%d)\n", i + 1); 307 308 process_data(child, level); 309 310 child->lpVtbl->Release(child); 311 } 312 } 313 314 /* Dump an X file 'objects.x' and its related templates file 'templates.x' if they are both presents 315 * Useful for debug by comparing outputs from native and builtin dlls */ 316 static void test_dump(void) 317 { 318 HRESULT ret; 319 ULONG ref; 320 ID3DXFile *xfile = NULL; 321 ID3DXFileEnumObject *xfile_enum_object = NULL; 322 HANDLE file; 323 void *data; 324 DWORD size; 325 SIZE_T children; 326 int i; 327 328 /* Dump data only if there is an object and a template */ 329 file = CreateFileA("objects.x", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 330 if (file == INVALID_HANDLE_VALUE) 331 return; 332 CloseHandle(file); 333 334 file = CreateFileA("templates.x", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 335 if (file == INVALID_HANDLE_VALUE) 336 return; 337 338 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 10000); 339 340 if (!ReadFile(file, data, 10000, &size, NULL)) 341 { 342 skip("Templates file is too big\n"); 343 goto exit; 344 } 345 346 printf("Load templates file (%u bytes)\n", size); 347 348 ret = D3DXFileCreate(&xfile); 349 ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret); 350 351 ret = xfile->lpVtbl->RegisterTemplates(xfile, data, size); 352 ok(ret == S_OK, "ID3DXFileImpl_RegisterTemplates failed with %#x\n", ret); 353 354 ret = xfile->lpVtbl->CreateEnumObject(xfile, (void*)"objects.x", D3DXF_FILELOAD_FROMFILE, &xfile_enum_object); 355 ok(ret == S_OK, "ID3DXFile_CreateEnumObject failed with %#x\n", ret); 356 357 ret = xfile_enum_object->lpVtbl->GetChildren(xfile_enum_object, &children); 358 ok(ret == S_OK, "ID3DXFileEnumObject_GetChildren failed with %#x\n", ret); 359 360 for (i = 0; i < children; i++) 361 { 362 ID3DXFileData *child; 363 ret = xfile_enum_object->lpVtbl->GetChild(xfile_enum_object, i, &child); 364 ok(ret == S_OK, "ID3DXFileEnumObject_GetChild failed with %#x\n", ret); 365 printf("\n"); 366 process_data(child, 0); 367 child->lpVtbl->Release(child); 368 } 369 370 ref = xfile_enum_object->lpVtbl->Release(xfile_enum_object); 371 ok(ref == 0, "Got refcount %u, expected 0\n", ref); 372 373 ref = xfile->lpVtbl->Release(xfile); 374 ok(ref == 0, "Got refcount %u, expected 0\n", ref); 375 376 377 exit: 378 CloseHandle(file); 379 HeapFree(GetProcessHeap(), 0, data); 380 } 381 382 START_TEST(xfile) 383 { 384 test_templates(); 385 test_lock_unlock(); 386 test_getname(); 387 test_type_index_color(); 388 test_dump(); 389 } 390