1 /* 2 * X Files parsing 3 * 4 * Copyright 2008 Christian Costa 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "wine/debug.h" 22 23 #define COBJMACROS 24 25 #include "winbase.h" 26 #include "wingdi.h" 27 #include "wine/winternl.h" 28 29 #include "d3dxof_private.h" 30 #include "dxfile.h" 31 32 #include <stdio.h> 33 34 WINE_DEFAULT_DEBUG_CHANNEL(d3dxof_parsing); 35 36 #define MAKEFOUR(a,b,c,d) ((DWORD)a + ((DWORD)b << 8) + ((DWORD)c << 16) + ((DWORD)d << 24)) 37 #define XOFFILE_FORMAT_MAGIC MAKEFOUR('x','o','f',' ') 38 #define XOFFILE_FORMAT_VERSION_302 MAKEFOUR('0','3','0','2') 39 #define XOFFILE_FORMAT_VERSION_303 MAKEFOUR('0','3','0','3') 40 #define XOFFILE_FORMAT_BINARY MAKEFOUR('b','i','n',' ') 41 #define XOFFILE_FORMAT_TEXT MAKEFOUR('t','x','t',' ') 42 #define XOFFILE_FORMAT_BINARY_MSZIP MAKEFOUR('b','z','i','p') 43 #define XOFFILE_FORMAT_TEXT_MSZIP MAKEFOUR('t','z','i','p') 44 #define XOFFILE_FORMAT_COMPRESSED MAKEFOUR('c','m','p',' ') 45 #define XOFFILE_FORMAT_FLOAT_BITS_32 MAKEFOUR('0','0','3','2') 46 #define XOFFILE_FORMAT_FLOAT_BITS_64 MAKEFOUR('0','0','6','4') 47 48 #define TOKEN_ERROR 0xffff 49 #define TOKEN_NONE 0 50 #define TOKEN_NAME 1 51 #define TOKEN_STRING 2 52 #define TOKEN_INTEGER 3 53 #define TOKEN_GUID 5 54 #define TOKEN_INTEGER_LIST 6 55 #define TOKEN_FLOAT_LIST 7 56 #define TOKEN_OBRACE 10 57 #define TOKEN_CBRACE 11 58 #define TOKEN_OPAREN 12 59 #define TOKEN_CPAREN 13 60 #define TOKEN_OBRACKET 14 61 #define TOKEN_CBRACKET 15 62 #define TOKEN_OANGLE 16 63 #define TOKEN_CANGLE 17 64 #define TOKEN_DOT 18 65 #define TOKEN_COMMA 19 66 #define TOKEN_SEMICOLON 20 67 #define TOKEN_TEMPLATE 31 68 #define TOKEN_WORD 40 69 #define TOKEN_DWORD 41 70 #define TOKEN_FLOAT 42 71 #define TOKEN_DOUBLE 43 72 #define TOKEN_CHAR 44 73 #define TOKEN_UCHAR 45 74 #define TOKEN_SWORD 46 75 #define TOKEN_SDWORD 47 76 #define TOKEN_VOID 48 77 #define TOKEN_LPSTR 49 78 #define TOKEN_UNICODE 50 79 #define TOKEN_CSTRING 51 80 #define TOKEN_ARRAY 52 81 82 #define CLSIDFMT "<%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>" 83 84 /* FOURCC to string conversion for debug messages */ 85 static const char *debugstr_fourcc(DWORD fourcc) 86 { 87 if (!fourcc) return "'null'"; 88 return wine_dbg_sprintf ("\'%c%c%c%c\'", 89 (char)(fourcc), (char)(fourcc >> 8), 90 (char)(fourcc >> 16), (char)(fourcc >> 24)); 91 } 92 93 static const char* get_primitive_string(DWORD token) 94 { 95 switch(token) 96 { 97 case TOKEN_WORD: 98 return "WORD"; 99 case TOKEN_DWORD: 100 return "DWORD"; 101 case TOKEN_FLOAT: 102 return "FLOAT"; 103 case TOKEN_DOUBLE: 104 return "DOUBLE"; 105 case TOKEN_CHAR: 106 return "CHAR"; 107 case TOKEN_UCHAR: 108 return "UCHAR"; 109 case TOKEN_SWORD: 110 return "SWORD"; 111 case TOKEN_SDWORD: 112 return "SDWORD"; 113 case TOKEN_VOID: 114 return "VOID"; 115 case TOKEN_LPSTR: 116 return "STRING"; 117 case TOKEN_UNICODE: 118 return "UNICODE"; 119 case TOKEN_CSTRING: 120 return "CSTRING "; 121 default: 122 break; 123 } 124 return NULL; 125 } 126 127 static void dump_template(xtemplate* templates_array, xtemplate* ptemplate) 128 { 129 ULONG j, k; 130 GUID* clsid; 131 132 clsid = &ptemplate->class_id; 133 134 wine_dbg_printf("template %s\n", ptemplate->name); 135 wine_dbg_printf("{\n"); 136 wine_dbg_printf(CLSIDFMT "\n", clsid->Data1, clsid->Data2, clsid->Data3, clsid->Data4[0], 137 clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7]); 138 for (j = 0; j < ptemplate->nb_members; j++) 139 { 140 if (ptemplate->members[j].nb_dims) 141 wine_dbg_printf("array "); 142 if (ptemplate->members[j].type == TOKEN_NAME) 143 wine_dbg_printf("%s ", templates_array[ptemplate->members[j].idx_template].name); 144 else 145 wine_dbg_printf("%s ", get_primitive_string(ptemplate->members[j].type)); 146 wine_dbg_printf("%s", ptemplate->members[j].name); 147 for (k = 0; k < ptemplate->members[j].nb_dims; k++) 148 { 149 if (ptemplate->members[j].dim_fixed[k]) 150 wine_dbg_printf("[%d]", ptemplate->members[j].dim_value[k]); 151 else 152 wine_dbg_printf("[%s]", ptemplate->members[ptemplate->members[j].dim_value[k]].name); 153 } 154 wine_dbg_printf(";\n"); 155 } 156 if (ptemplate->open) 157 wine_dbg_printf("[...]\n"); 158 else if (ptemplate->nb_children) 159 { 160 wine_dbg_printf("[%s", ptemplate->children[0]); 161 for (j = 1; j < ptemplate->nb_children; j++) 162 wine_dbg_printf(",%s", ptemplate->children[j]); 163 wine_dbg_printf("]\n"); 164 } 165 wine_dbg_printf("}\n"); 166 } 167 168 static BOOL read_bytes(parse_buffer * buf, LPVOID data, DWORD size) 169 { 170 if (buf->rem_bytes < size) 171 return FALSE; 172 memcpy(data, buf->buffer, size); 173 buf->buffer += size; 174 buf->rem_bytes -= size; 175 return TRUE; 176 } 177 178 static void rewind_bytes(parse_buffer * buf, DWORD size) 179 { 180 buf->buffer -= size; 181 buf->rem_bytes += size; 182 } 183 184 HRESULT parse_header(parse_buffer * buf, BYTE ** decomp_buffer_ptr) 185 { 186 /* X File common header: 187 * 0-3 -> Magic Number (format identifier) 188 * 4-7 -> Format Version 189 * 8-11 -> Format Type (text or binary, decompressed or compressed) 190 * 12-15 -> Float Size (32 or 64 bits) */ 191 DWORD header[4]; 192 193 if (!read_bytes(buf, header, sizeof(header))) 194 return DXFILEERR_BADFILETYPE; 195 196 if (TRACE_ON(d3dxof_parsing)) 197 { 198 char string[17]; 199 memcpy(string, header, 16); 200 string[16] = 0; 201 TRACE("header = '%s'\n", string); 202 } 203 204 if (header[0] != XOFFILE_FORMAT_MAGIC) 205 return DXFILEERR_BADFILETYPE; 206 207 if (header[1] != XOFFILE_FORMAT_VERSION_302 && header[1] != XOFFILE_FORMAT_VERSION_303) 208 return DXFILEERR_BADFILEVERSION; 209 210 if (header[2] != XOFFILE_FORMAT_BINARY && header[2] != XOFFILE_FORMAT_TEXT && 211 header[2] != XOFFILE_FORMAT_BINARY_MSZIP && header[2] != XOFFILE_FORMAT_TEXT_MSZIP) 212 { 213 WARN("File type %s unknown\n", debugstr_fourcc(header[2])); 214 return DXFILEERR_BADFILETYPE; 215 } 216 217 if (header[3] != XOFFILE_FORMAT_FLOAT_BITS_32 && header[3] != XOFFILE_FORMAT_FLOAT_BITS_64) 218 return DXFILEERR_BADFILEFLOATSIZE; 219 220 buf->txt = header[2] == XOFFILE_FORMAT_TEXT || header[2] == XOFFILE_FORMAT_TEXT_MSZIP; 221 222 if (header[2] == XOFFILE_FORMAT_BINARY_MSZIP || header[2] == XOFFILE_FORMAT_TEXT_MSZIP) 223 { 224 /* Extended header for compressed data: 225 * 16-19 -> size of decompressed file including xof header, 226 * 20-21 -> size of first decompressed MSZIP chunk, 22-23 -> size of first compressed MSZIP chunk 227 * 24-xx -> compressed MSZIP data chunk 228 * xx-xx -> size of next decompressed MSZIP chunk, xx-xx -> size of next compressed MSZIP chunk 229 * xx-xx -> compressed MSZIP data chunk 230 * .............................................................................................. */ 231 int err; 232 DWORD decomp_file_size; 233 WORD decomp_chunk_size; 234 WORD comp_chunk_size; 235 LPBYTE decomp_buffer; 236 237 if (!read_bytes(buf, &decomp_file_size, sizeof(decomp_file_size))) 238 return DXFILEERR_BADFILETYPE; 239 240 TRACE("Compressed format %s detected: decompressed file size with xof header = %d\n", 241 debugstr_fourcc(header[2]), decomp_file_size); 242 243 /* Does not take xof header into account */ 244 decomp_file_size -= 16; 245 246 decomp_buffer = HeapAlloc(GetProcessHeap(), 0, decomp_file_size); 247 if (!decomp_buffer) 248 { 249 ERR("Out of memory\n"); 250 return DXFILEERR_BADALLOC; 251 } 252 *decomp_buffer_ptr = decomp_buffer; 253 254 while (buf->rem_bytes) 255 { 256 if (!read_bytes(buf, &decomp_chunk_size, sizeof(decomp_chunk_size))) 257 return DXFILEERR_BADFILETYPE; 258 if (!read_bytes(buf, &comp_chunk_size, sizeof(comp_chunk_size))) 259 return DXFILEERR_BADFILETYPE; 260 261 TRACE("Process chunk: compressed_size = %d, decompressed_size = %d\n", 262 comp_chunk_size, decomp_chunk_size); 263 264 err = mszip_decompress(comp_chunk_size, decomp_chunk_size, (char*)buf->buffer, (char*)decomp_buffer); 265 if (err) 266 { 267 WARN("Error while decompressing MSZIP chunk %d\n", err); 268 HeapFree(GetProcessHeap(), 0, decomp_buffer); 269 return DXFILEERR_BADALLOC; 270 } 271 buf->rem_bytes -= comp_chunk_size; 272 buf->buffer += comp_chunk_size; 273 decomp_buffer += decomp_chunk_size; 274 } 275 276 if ((decomp_buffer - *decomp_buffer_ptr) != decomp_file_size) 277 ERR("Size of all decompressed chunks (%u) does not match decompressed file size (%u)\n", 278 (DWORD)(decomp_buffer - *decomp_buffer_ptr), decomp_file_size); 279 280 /* Use decompressed data */ 281 buf->buffer = *decomp_buffer_ptr; 282 buf->rem_bytes = decomp_file_size; 283 } 284 285 TRACE("Header is correct\n"); 286 287 return S_OK; 288 } 289 290 static void dump_TOKEN(WORD token) 291 { 292 #define DUMP_TOKEN(t) case t: TRACE(#t "\n"); break 293 switch(token) 294 { 295 DUMP_TOKEN(TOKEN_NAME); 296 DUMP_TOKEN(TOKEN_STRING); 297 DUMP_TOKEN(TOKEN_INTEGER); 298 DUMP_TOKEN(TOKEN_GUID); 299 DUMP_TOKEN(TOKEN_INTEGER_LIST); 300 DUMP_TOKEN(TOKEN_FLOAT_LIST); 301 DUMP_TOKEN(TOKEN_OBRACE); 302 DUMP_TOKEN(TOKEN_CBRACE); 303 DUMP_TOKEN(TOKEN_OPAREN); 304 DUMP_TOKEN(TOKEN_CPAREN); 305 DUMP_TOKEN(TOKEN_OBRACKET); 306 DUMP_TOKEN(TOKEN_CBRACKET); 307 DUMP_TOKEN(TOKEN_OANGLE); 308 DUMP_TOKEN(TOKEN_CANGLE); 309 DUMP_TOKEN(TOKEN_DOT); 310 DUMP_TOKEN(TOKEN_COMMA); 311 DUMP_TOKEN(TOKEN_SEMICOLON); 312 DUMP_TOKEN(TOKEN_TEMPLATE); 313 DUMP_TOKEN(TOKEN_WORD); 314 DUMP_TOKEN(TOKEN_DWORD); 315 DUMP_TOKEN(TOKEN_FLOAT); 316 DUMP_TOKEN(TOKEN_DOUBLE); 317 DUMP_TOKEN(TOKEN_CHAR); 318 DUMP_TOKEN(TOKEN_UCHAR); 319 DUMP_TOKEN(TOKEN_SWORD); 320 DUMP_TOKEN(TOKEN_SDWORD); 321 DUMP_TOKEN(TOKEN_VOID); 322 DUMP_TOKEN(TOKEN_LPSTR); 323 DUMP_TOKEN(TOKEN_UNICODE); 324 DUMP_TOKEN(TOKEN_CSTRING); 325 DUMP_TOKEN(TOKEN_ARRAY); 326 default: 327 if (0) 328 TRACE("Unknown token %d\n", token); 329 break; 330 } 331 #undef DUMP_TOKEN 332 } 333 334 static BOOL is_space(char c) 335 { 336 switch (c) 337 { 338 case 0x00: 339 case 0x0D: 340 case 0x0A: 341 case ' ': 342 case '\t': 343 return TRUE; 344 } 345 return FALSE; 346 } 347 348 static BOOL is_operator(char c) 349 { 350 switch(c) 351 { 352 case '{': 353 case '}': 354 case '[': 355 case ']': 356 case '(': 357 case ')': 358 case '<': 359 case '>': 360 case ',': 361 case ';': 362 return TRUE; 363 } 364 return FALSE; 365 } 366 367 static inline BOOL is_separator(char c) 368 { 369 return is_space(c) || is_operator(c); 370 } 371 372 static WORD get_operator_token(char c) 373 { 374 switch(c) 375 { 376 case '{': 377 return TOKEN_OBRACE; 378 case '}': 379 return TOKEN_CBRACE; 380 case '[': 381 return TOKEN_OBRACKET; 382 case ']': 383 return TOKEN_CBRACKET; 384 case '(': 385 return TOKEN_OPAREN; 386 case ')': 387 return TOKEN_CPAREN; 388 case '<': 389 return TOKEN_OANGLE; 390 case '>': 391 return TOKEN_CANGLE; 392 case ',': 393 return TOKEN_COMMA; 394 case ';': 395 return TOKEN_SEMICOLON; 396 } 397 return 0; 398 } 399 400 static BOOL is_keyword(parse_buffer* buf, const char* keyword) 401 { 402 char tmp[8]; /* longest keyword size (template) */ 403 DWORD len = strlen(keyword); 404 405 if (!read_bytes(buf, tmp, len)) 406 return FALSE; 407 if (_strnicmp(tmp, keyword, len)) 408 { 409 rewind_bytes(buf, len); 410 return FALSE; 411 } 412 413 if (!read_bytes(buf, tmp, 1)) 414 return TRUE; 415 if (is_separator(tmp[0])) 416 { 417 rewind_bytes(buf, 1); 418 return TRUE; 419 } 420 rewind_bytes(buf, len+1); 421 return FALSE; 422 } 423 424 static WORD get_keyword_token(parse_buffer* buf) 425 { 426 if (is_keyword(buf, "template")) 427 return TOKEN_TEMPLATE; 428 if (is_keyword(buf, "WORD")) 429 return TOKEN_WORD; 430 if (is_keyword(buf, "DWORD")) 431 return TOKEN_DWORD; 432 if (is_keyword(buf, "FLOAT")) 433 return TOKEN_FLOAT; 434 if (is_keyword(buf, "DOUBLE")) 435 return TOKEN_DOUBLE; 436 if (is_keyword(buf, "CHAR")) 437 return TOKEN_CHAR; 438 if (is_keyword(buf, "UCHAR")) 439 return TOKEN_UCHAR; 440 if (is_keyword(buf, "SWORD")) 441 return TOKEN_SWORD; 442 if (is_keyword(buf, "SDWORD")) 443 return TOKEN_SDWORD; 444 if (is_keyword(buf, "VOID")) 445 return TOKEN_VOID; 446 if (is_keyword(buf, "STRING")) 447 return TOKEN_LPSTR; 448 if (is_keyword(buf, "UNICODE")) 449 return TOKEN_UNICODE; 450 if (is_keyword(buf, "CSTRING")) 451 return TOKEN_CSTRING; 452 if (is_keyword(buf, "array")) 453 return TOKEN_ARRAY; 454 455 return 0; 456 } 457 458 static BOOL is_guid(parse_buffer* buf) 459 { 460 char tmp[50]; 461 DWORD pos = 1; 462 GUID class_id; 463 DWORD tab[10]; 464 int ret; 465 466 if (buf->rem_bytes < 38 || *buf->buffer != '<') 467 return FALSE; 468 tmp[0] = '<'; 469 while (pos < sizeof(tmp) - 2 && *(buf->buffer+pos) != '>') 470 { 471 tmp[pos] = *(buf->buffer+pos); 472 pos++; 473 } 474 tmp[pos++] = '>'; 475 tmp[pos] = 0; 476 if (pos != 38 /* <+36+> */) 477 { 478 TRACE("Wrong guid %s (%d)\n", tmp, pos); 479 return FALSE; 480 } 481 buf->buffer += pos; 482 buf->rem_bytes -= pos; 483 484 ret = sscanf(tmp, CLSIDFMT, &class_id.Data1, tab, tab+1, tab+2, tab+3, tab+4, tab+5, tab+6, tab+7, tab+8, tab+9); 485 if (ret != 11) 486 { 487 TRACE("Wrong guid %s (%d)\n", tmp, pos); 488 return FALSE; 489 } 490 TRACE("Found guid %s (%d)\n", tmp, pos); 491 492 class_id.Data2 = tab[0]; 493 class_id.Data3 = tab[1]; 494 class_id.Data4[0] = tab[2]; 495 class_id.Data4[1] = tab[3]; 496 class_id.Data4[2] = tab[4]; 497 class_id.Data4[3] = tab[5]; 498 class_id.Data4[4] = tab[6]; 499 class_id.Data4[5] = tab[7]; 500 class_id.Data4[6] = tab[8]; 501 class_id.Data4[7] = tab[9]; 502 503 *(GUID*)buf->value = class_id; 504 505 return TRUE; 506 } 507 508 static BOOL is_name(parse_buffer* buf) 509 { 510 char tmp[512]; 511 DWORD pos = 0; 512 char c; 513 BOOL error = FALSE; 514 while (pos < buf->rem_bytes && !is_separator(c = *(buf->buffer+pos))) 515 { 516 if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '_') || (c == '-'))) 517 error = TRUE; 518 if (pos < sizeof(tmp)) 519 tmp[pos] = c; 520 pos++; 521 } 522 tmp[min(pos, sizeof(tmp) - 1)] = 0; 523 524 if (error) 525 { 526 TRACE("Wrong name %s\n", tmp); 527 return FALSE; 528 } 529 530 buf->buffer += pos; 531 buf->rem_bytes -= pos; 532 533 TRACE("Found name %s\n", tmp); 534 strcpy((char*)buf->value, tmp); 535 536 return TRUE; 537 } 538 539 static BOOL is_float(parse_buffer* buf) 540 { 541 char tmp[512]; 542 DWORD pos = 0; 543 char c; 544 float decimal; 545 BOOL dot = FALSE; 546 547 while (pos < buf->rem_bytes && !is_separator(c = *(buf->buffer+pos))) 548 { 549 if (!((!pos && (c == '-')) || ((c >= '0') && (c <= '9')) || (!dot && (c == '.')))) 550 return FALSE; 551 if (c == '.') 552 dot = TRUE; 553 if (pos < sizeof(tmp)) 554 tmp[pos] = c; 555 pos++; 556 } 557 tmp[min(pos, sizeof(tmp) - 1)] = 0; 558 559 buf->buffer += pos; 560 buf->rem_bytes -= pos; 561 562 sscanf(tmp, "%f", &decimal); 563 564 TRACE("Found float %s - %f\n", tmp, decimal); 565 566 *(float*)buf->value = decimal; 567 568 return TRUE; 569 } 570 571 static BOOL is_integer(parse_buffer* buf) 572 { 573 char tmp[512]; 574 DWORD pos = 0; 575 char c; 576 DWORD integer; 577 578 while (pos < buf->rem_bytes && !is_separator(c = *(buf->buffer+pos))) 579 { 580 if (!((c >= '0') && (c <= '9'))) 581 return FALSE; 582 if (pos < sizeof(tmp)) 583 tmp[pos] = c; 584 pos++; 585 } 586 tmp[min(pos, sizeof(tmp) - 1)] = 0; 587 588 buf->buffer += pos; 589 buf->rem_bytes -= pos; 590 591 sscanf(tmp, "%d", &integer); 592 593 TRACE("Found integer %s - %d\n", tmp, integer); 594 595 *(DWORD*)buf->value = integer; 596 597 return TRUE; 598 } 599 600 static BOOL is_string(parse_buffer* buf) 601 { 602 char tmp[512]; 603 DWORD pos = 0; 604 char c; 605 BOOL ok = FALSE; 606 607 if (*buf->buffer != '"') 608 return FALSE; 609 610 while ((pos+1) < buf->rem_bytes) 611 { 612 c = *(buf->buffer+pos+1); 613 if (c == '"') 614 { 615 ok = TRUE; 616 break; 617 } 618 if (pos < sizeof(tmp)) 619 tmp[pos] = c; 620 pos++; 621 } 622 tmp[min(pos, sizeof(tmp) - 1)] = 0; 623 624 if (!ok) 625 { 626 TRACE("Wrong string %s\n", tmp); 627 return FALSE; 628 } 629 630 buf->buffer += pos + 2; 631 buf->rem_bytes -= pos + 2; 632 633 TRACE("Found string %s\n", tmp); 634 strcpy((char*)buf->value, tmp); 635 636 return TRUE; 637 } 638 639 static WORD parse_TOKEN(parse_buffer * buf) 640 { 641 WORD token; 642 643 if (buf->txt) 644 { 645 while(1) 646 { 647 char c; 648 if (!read_bytes(buf, &c, 1)) 649 return TOKEN_NONE; 650 if ((c == '#') || (c == '/')) 651 { 652 /* Handle comment (# or //) */ 653 if (c == '/') 654 { 655 if (!read_bytes(buf, &c, 1)) 656 return TOKEN_ERROR; 657 if (c != '/') 658 return TOKEN_ERROR; 659 } 660 c = 0; 661 while (c != 0x0A) 662 { 663 if (!read_bytes(buf, &c, 1)) 664 return TOKEN_NONE; 665 } 666 continue; 667 } 668 if (is_space(c)) 669 continue; 670 if (is_operator(c) && (c != '<')) 671 { 672 token = get_operator_token(c); 673 break; 674 } 675 else if (c == '.') 676 { 677 token = TOKEN_DOT; 678 break; 679 } 680 else 681 { 682 rewind_bytes(buf, 1); 683 684 if ((token = get_keyword_token(buf))) 685 break; 686 687 if (is_guid(buf)) 688 { 689 token = TOKEN_GUID; 690 break; 691 } 692 if (is_integer(buf)) 693 { 694 token = TOKEN_INTEGER; 695 break; 696 } 697 if (is_float(buf)) 698 { 699 token = TOKEN_FLOAT; 700 break; 701 } 702 if (is_string(buf)) 703 { 704 token = TOKEN_LPSTR; 705 break; 706 } 707 if (is_name(buf)) 708 { 709 token = TOKEN_NAME; 710 break; 711 } 712 713 FIXME("Unrecognize element\n"); 714 return TOKEN_ERROR; 715 } 716 } 717 } 718 else 719 { 720 if (!buf->list_nb_elements) 721 { 722 if (!read_bytes(buf, &token, 2)) 723 return TOKEN_NONE; 724 725 /* Convert integer and float list into separate elements */ 726 if (token == TOKEN_INTEGER_LIST) 727 { 728 if (!read_bytes(buf, &buf->list_nb_elements, 4)) 729 return TOKEN_ERROR; 730 token = TOKEN_INTEGER; 731 buf->list_type_float = FALSE; 732 TRACE("Integer list (TOKEN_INTEGER_LIST) of size %d\n", buf->list_nb_elements); 733 } 734 else if (token == TOKEN_FLOAT_LIST) 735 { 736 if (!read_bytes(buf, &buf->list_nb_elements, 4)) 737 return TOKEN_ERROR; 738 token = TOKEN_FLOAT; 739 buf->list_type_float = TRUE; 740 TRACE("Float list (TOKEN_FLOAT_LIST) of size %d\n", buf->list_nb_elements); 741 } 742 } 743 744 if (buf->list_nb_elements) 745 { 746 if (buf->list_separator) 747 { 748 buf->list_nb_elements--; 749 buf->list_separator = FALSE; 750 /* Insert separator between each value, and since list does not accept separator at the end 751 use a comma so any extra separator will generate an error */ 752 token = TOKEN_COMMA; 753 } 754 else 755 { 756 DWORD value; 757 758 if (!read_bytes(buf, &value, 4)) 759 return TOKEN_ERROR; 760 *(DWORD*)buf->value = value; 761 762 buf->list_separator = TRUE; 763 /* Convert list into a series of their basic type counterpart */ 764 token = buf->list_type_float ? TOKEN_FLOAT : TOKEN_INTEGER; 765 } 766 dump_TOKEN(token); 767 return token; 768 } 769 770 switch (token) 771 { 772 case TOKEN_NAME: 773 { 774 DWORD count; 775 char *name = (char*)buf->value; 776 777 if (!read_bytes(buf, &count, 4)) 778 return TOKEN_ERROR; 779 if (!read_bytes(buf, name, count)) 780 return TOKEN_ERROR; 781 name[count] = 0; 782 TRACE("name = %s\n", name); 783 } 784 break; 785 case TOKEN_INTEGER: 786 { 787 DWORD integer; 788 789 if (!read_bytes(buf, &integer, 4)) 790 return TOKEN_ERROR; 791 TRACE("integer = %u\n", integer); 792 793 *(DWORD*)buf->value = integer; 794 } 795 break; 796 case TOKEN_GUID: 797 { 798 char strguid[39]; 799 GUID class_id; 800 801 if (!read_bytes(buf, &class_id, 16)) 802 return TOKEN_ERROR; 803 sprintf(strguid, CLSIDFMT, class_id.Data1, class_id.Data2, class_id.Data3, class_id.Data4[0], 804 class_id.Data4[1], class_id.Data4[2], class_id.Data4[3], class_id.Data4[4], class_id.Data4[5], 805 class_id.Data4[6], class_id.Data4[7]); 806 TRACE("guid = %s\n", strguid); 807 808 *(GUID*)buf->value = class_id; 809 } 810 break; 811 case TOKEN_STRING: 812 { 813 DWORD count; 814 char *string = (char*)buf->value; 815 816 if (!read_bytes(buf, &count, 4)) 817 return TOKEN_ERROR; 818 if (!read_bytes(buf, string, count)) 819 return TOKEN_ERROR; 820 string[count] = 0; 821 TRACE("string = %s\n", string); 822 823 token = TOKEN_LPSTR; 824 } 825 break; 826 case TOKEN_OBRACE: 827 case TOKEN_CBRACE: 828 case TOKEN_OPAREN: 829 case TOKEN_CPAREN: 830 case TOKEN_OBRACKET: 831 case TOKEN_CBRACKET: 832 case TOKEN_OANGLE: 833 case TOKEN_CANGLE: 834 case TOKEN_DOT: 835 case TOKEN_COMMA: 836 case TOKEN_SEMICOLON: 837 case TOKEN_TEMPLATE: 838 case TOKEN_WORD: 839 case TOKEN_DWORD: 840 case TOKEN_FLOAT: 841 case TOKEN_DOUBLE: 842 case TOKEN_CHAR: 843 case TOKEN_UCHAR: 844 case TOKEN_SWORD: 845 case TOKEN_SDWORD: 846 case TOKEN_VOID: 847 case TOKEN_LPSTR: 848 case TOKEN_UNICODE: 849 case TOKEN_CSTRING: 850 case TOKEN_ARRAY: 851 break; 852 default: 853 return TOKEN_ERROR; 854 } 855 } 856 857 dump_TOKEN(token); 858 859 return token; 860 } 861 862 static WORD get_TOKEN(parse_buffer * buf) 863 { 864 if (buf->token_present) 865 { 866 buf->token_present = FALSE; 867 return buf->current_token; 868 } 869 870 buf->current_token = parse_TOKEN(buf); 871 872 return buf->current_token; 873 } 874 875 static WORD check_TOKEN(parse_buffer * buf) 876 { 877 if (buf->token_present) 878 return buf->current_token; 879 880 buf->current_token = parse_TOKEN(buf); 881 buf->token_present = TRUE; 882 883 return buf->current_token; 884 } 885 886 static inline BOOL is_primitive_type(WORD token) 887 { 888 BOOL ret; 889 switch(token) 890 { 891 case TOKEN_WORD: 892 case TOKEN_DWORD: 893 case TOKEN_FLOAT: 894 case TOKEN_DOUBLE: 895 case TOKEN_CHAR: 896 case TOKEN_UCHAR: 897 case TOKEN_SWORD: 898 case TOKEN_SDWORD: 899 case TOKEN_LPSTR: 900 case TOKEN_UNICODE: 901 case TOKEN_CSTRING: 902 ret = TRUE; 903 break; 904 default: 905 ret = FALSE; 906 break; 907 } 908 return ret; 909 } 910 911 static BOOL parse_template_option_info(parse_buffer * buf) 912 { 913 xtemplate* cur_template = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates]; 914 915 if (check_TOKEN(buf) == TOKEN_DOT) 916 { 917 get_TOKEN(buf); 918 if (get_TOKEN(buf) != TOKEN_DOT) 919 return FALSE; 920 if (get_TOKEN(buf) != TOKEN_DOT) 921 return FALSE; 922 cur_template->open = TRUE; 923 } 924 else 925 { 926 while (1) 927 { 928 if (get_TOKEN(buf) != TOKEN_NAME) 929 return FALSE; 930 strcpy(cur_template->children[cur_template->nb_children], (char*)buf->value); 931 if (check_TOKEN(buf) == TOKEN_GUID) 932 get_TOKEN(buf); 933 cur_template->nb_children++; 934 if (check_TOKEN(buf) != TOKEN_COMMA) 935 break; 936 get_TOKEN(buf); 937 } 938 cur_template->open = FALSE; 939 } 940 941 return TRUE; 942 } 943 944 static BOOL parse_template_members_list(parse_buffer * buf) 945 { 946 int idx_member = 0; 947 member* cur_member; 948 949 while (1) 950 { 951 BOOL array = FALSE; 952 int nb_dims = 0; 953 cur_member = &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[idx_member]; 954 955 if (check_TOKEN(buf) == TOKEN_ARRAY) 956 { 957 get_TOKEN(buf); 958 array = TRUE; 959 } 960 961 if (check_TOKEN(buf) == TOKEN_NAME) 962 { 963 cur_member->type = get_TOKEN(buf); 964 if (!strcmp((char*)buf->value, "indexColor")) 965 { 966 /* Case sensitive legacy type indexColor is described in the first template */ 967 cur_member->idx_template = 0; 968 } 969 else 970 { 971 cur_member->idx_template = 1; 972 while (cur_member->idx_template < buf->pdxf->nb_xtemplates) 973 { 974 if (!_strnicmp((char*)buf->value, buf->pdxf->xtemplates[cur_member->idx_template].name, -1)) 975 break; 976 cur_member->idx_template++; 977 } 978 if (cur_member->idx_template == buf->pdxf->nb_xtemplates) 979 { 980 WARN("Reference to a nonexistent template '%s'\n", (char*)buf->value); 981 return FALSE; 982 } 983 } 984 } 985 else if (is_primitive_type(check_TOKEN(buf))) 986 cur_member->type = get_TOKEN(buf); 987 else 988 break; 989 990 if (get_TOKEN(buf) != TOKEN_NAME) 991 return FALSE; 992 strcpy(cur_member->name, (char*)buf->value); 993 994 if (array) 995 { 996 while (check_TOKEN(buf) == TOKEN_OBRACKET) 997 { 998 if (nb_dims >= MAX_ARRAY_DIM) 999 { 1000 FIXME("Too many dimensions (%d) for multi-dimensional array\n", nb_dims + 1); 1001 return FALSE; 1002 } 1003 get_TOKEN(buf); 1004 if (check_TOKEN(buf) == TOKEN_INTEGER) 1005 { 1006 get_TOKEN(buf); 1007 cur_member->dim_fixed[nb_dims] = TRUE; 1008 cur_member->dim_value[nb_dims] = *(DWORD*)buf->value; 1009 } 1010 else 1011 { 1012 int i; 1013 if (get_TOKEN(buf) != TOKEN_NAME) 1014 return FALSE; 1015 for (i = 0; i < idx_member; i++) 1016 { 1017 if (!strcmp((char*)buf->value, buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].name)) 1018 { 1019 if (buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].nb_dims) 1020 { 1021 ERR("Array cannot be used to specify variable array size\n"); 1022 return FALSE; 1023 } 1024 if (buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].members[i].type != TOKEN_DWORD) 1025 { 1026 FIXME("Only DWORD supported to specify variable array size\n"); 1027 return FALSE; 1028 } 1029 break; 1030 } 1031 } 1032 if (i == idx_member) 1033 { 1034 ERR("Reference to unknown member %s\n", (char*)buf->value); 1035 return FALSE; 1036 } 1037 cur_member->dim_fixed[nb_dims] = FALSE; 1038 cur_member->dim_value[nb_dims] = i; 1039 } 1040 if (get_TOKEN(buf) != TOKEN_CBRACKET) 1041 return FALSE; 1042 nb_dims++; 1043 } 1044 if (!nb_dims) 1045 return FALSE; 1046 cur_member->nb_dims = nb_dims; 1047 } 1048 if (get_TOKEN(buf) != TOKEN_SEMICOLON) 1049 return FALSE; 1050 1051 idx_member++; 1052 } 1053 1054 buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].nb_members = idx_member; 1055 1056 return TRUE; 1057 } 1058 1059 static BOOL parse_template_parts(parse_buffer * buf) 1060 { 1061 if (!parse_template_members_list(buf)) 1062 return FALSE; 1063 if (check_TOKEN(buf) == TOKEN_OBRACKET) 1064 { 1065 get_TOKEN(buf); 1066 if (!parse_template_option_info(buf)) 1067 return FALSE; 1068 if (get_TOKEN(buf) != TOKEN_CBRACKET) 1069 return FALSE; 1070 } 1071 1072 return TRUE; 1073 } 1074 1075 static BOOL parse_template(parse_buffer * buf) 1076 { 1077 if (get_TOKEN(buf) != TOKEN_TEMPLATE) 1078 return FALSE; 1079 if (get_TOKEN(buf) != TOKEN_NAME) 1080 return FALSE; 1081 strcpy(buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].name, (char*)buf->value); 1082 if (get_TOKEN(buf) != TOKEN_OBRACE) 1083 return FALSE; 1084 if (get_TOKEN(buf) != TOKEN_GUID) 1085 return FALSE; 1086 buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].class_id = *(GUID*)buf->value; 1087 if (!parse_template_parts(buf)) 1088 return FALSE; 1089 if (get_TOKEN(buf) != TOKEN_CBRACE) 1090 return FALSE; 1091 1092 TRACE("%d - %s - %s\n", buf->pdxf->nb_xtemplates, buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].name, debugstr_guid(&buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates].class_id)); 1093 buf->pdxf->nb_xtemplates++; 1094 1095 return TRUE; 1096 } 1097 1098 BOOL parse_templates(parse_buffer * buf, BOOL templates_only) 1099 { 1100 while (check_TOKEN(buf) != TOKEN_NONE) 1101 { 1102 if (templates_only && (check_TOKEN(buf) != TOKEN_TEMPLATE)) 1103 return TRUE; 1104 if (!parse_template(buf)) 1105 { 1106 WARN("Template is not correct\n"); 1107 return FALSE; 1108 } 1109 else 1110 { 1111 TRACE("Template successfully parsed:\n"); 1112 if (TRACE_ON(d3dxof_parsing)) 1113 dump_template(buf->pdxf->xtemplates, &buf->pdxf->xtemplates[buf->pdxf->nb_xtemplates - 1]); 1114 } 1115 } 1116 return TRUE; 1117 } 1118 1119 static BOOL check_buffer(parse_buffer * buf, ULONG size) 1120 { 1121 if ((buf->cur_pos_data + size) > buf->capacity) 1122 { 1123 LPBYTE pdata; 1124 ULONG new_capacity = buf->capacity ? 2 * buf->capacity : 100000; 1125 1126 pdata = HeapAlloc(GetProcessHeap(), 0, new_capacity); 1127 if (!pdata) 1128 return FALSE; 1129 memcpy(pdata, buf->pdata, buf->cur_pos_data); 1130 HeapFree(GetProcessHeap(), 0, buf->pdata); 1131 buf->capacity = new_capacity; 1132 buf->pdata = pdata; 1133 buf->pxo->root->pdata = pdata; 1134 } 1135 return TRUE; 1136 } 1137 1138 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional); 1139 static BOOL parse_object_members_list(parse_buffer * buf) 1140 { 1141 DWORD token; 1142 ULONG i; 1143 xtemplate* pt = buf->pxt[buf->level]; 1144 1145 buf->pxo->nb_members = pt->nb_members; 1146 1147 for (i = 0; i < pt->nb_members; i++) 1148 { 1149 ULONG k; 1150 ULONG nb_elems = 1; 1151 BOOL basic_type = TRUE; 1152 1153 buf->pxo->members[i].name = pt->members[i].name; 1154 buf->pxo->members[i].start = buf->cur_pos_data; 1155 1156 for (k = 0; k < pt->members[i].nb_dims; k++) 1157 { 1158 if (pt->members[i].dim_fixed[k]) 1159 nb_elems *= pt->members[i].dim_value[k]; 1160 else 1161 nb_elems *= *(DWORD*)(buf->pxo->root->pdata + buf->pxo->members[pt->members[i].dim_value[k]].start); 1162 } 1163 1164 TRACE("Elements to consider: %u\n", nb_elems); 1165 1166 for (k = 0; k < nb_elems; k++) 1167 { 1168 if (pt->members[i].type == TOKEN_NAME) 1169 { 1170 ULONG j; 1171 1172 TRACE("Found sub-object %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name); 1173 basic_type = FALSE; 1174 buf->level++; 1175 /* To do template lookup */ 1176 for (j = 0; j < buf->pdxf->nb_xtemplates; j++) 1177 { 1178 if (!_strnicmp(buf->pdxf->xtemplates[pt->members[i].idx_template].name, buf->pdxf->xtemplates[j].name, -1)) 1179 { 1180 buf->pxt[buf->level] = &buf->pdxf->xtemplates[j]; 1181 break; 1182 } 1183 } 1184 if (j == buf->pdxf->nb_xtemplates) 1185 { 1186 ERR("Unknown template %s\n", (char*)buf->value); 1187 buf->level--; 1188 return FALSE; 1189 } 1190 TRACE("Enter %s\n", buf->pdxf->xtemplates[pt->members[i].idx_template].name); 1191 if (!parse_object_parts(buf, FALSE)) 1192 { 1193 buf->level--; 1194 return FALSE; 1195 } 1196 buf->level--; 1197 } 1198 else 1199 { 1200 token = check_TOKEN(buf); 1201 if (token == TOKEN_INTEGER) 1202 { 1203 get_TOKEN(buf); 1204 TRACE("%s = %d\n", pt->members[i].name, *(DWORD*)buf->value); 1205 /* Assume larger size */ 1206 if (!check_buffer(buf, 4)) 1207 return FALSE; 1208 if (pt->members[i].type == TOKEN_WORD) 1209 { 1210 *(WORD *)(buf->pdata + buf->cur_pos_data) = *(DWORD *)buf->value; 1211 buf->cur_pos_data += 2; 1212 } 1213 else if (pt->members[i].type == TOKEN_DWORD) 1214 { 1215 *(DWORD *)(buf->pdata + buf->cur_pos_data) = *(DWORD *)buf->value; 1216 buf->cur_pos_data += 4; 1217 } 1218 else 1219 { 1220 FIXME("Token %d not supported\n", pt->members[i].type); 1221 return FALSE; 1222 } 1223 } 1224 else if (token == TOKEN_FLOAT) 1225 { 1226 get_TOKEN(buf); 1227 TRACE("%s = %f\n", pt->members[i].name, *(float*)buf->value); 1228 if (!check_buffer(buf, 4)) 1229 return FALSE; 1230 if (pt->members[i].type == TOKEN_FLOAT) 1231 { 1232 *(float *)(buf->pdata + buf->cur_pos_data) = *(float *)buf->value; 1233 buf->cur_pos_data += 4; 1234 } 1235 else 1236 { 1237 FIXME("Token %d not supported\n", pt->members[i].type); 1238 return FALSE; 1239 } 1240 } 1241 else if (token == TOKEN_LPSTR) 1242 { 1243 get_TOKEN(buf); 1244 TRACE("%s = %s\n", pt->members[i].name, (char*)buf->value); 1245 if (!check_buffer(buf, sizeof(LPSTR))) 1246 return FALSE; 1247 if (pt->members[i].type == TOKEN_LPSTR) 1248 { 1249 int len = strlen((char*)buf->value) + 1; 1250 if ((buf->cur_pstrings - buf->pstrings + len) > MAX_STRINGS_BUFFER) 1251 { 1252 FIXME("Buffer too small %p %p %d\n", buf->cur_pstrings, buf->pstrings, len); 1253 return FALSE; 1254 } 1255 strcpy((char*)buf->cur_pstrings, (char*)buf->value); 1256 *(((LPCSTR*)(buf->pdata + buf->cur_pos_data))) = (char*)buf->cur_pstrings; 1257 buf->cur_pstrings += len; 1258 buf->cur_pos_data += sizeof(LPSTR); 1259 } 1260 else 1261 { 1262 FIXME("Token %d not supported\n", pt->members[i].type); 1263 return FALSE; 1264 } 1265 } 1266 else 1267 { 1268 WARN("Unexpected token %d\n", token); 1269 return FALSE; 1270 } 1271 } 1272 1273 if (basic_type) 1274 { 1275 /* Handle separator only for basic types */ 1276 token = check_TOKEN(buf); 1277 if ((token != TOKEN_COMMA) && (token != TOKEN_SEMICOLON)) 1278 return FALSE; 1279 /* Allow multi-semicolons + single comma separator */ 1280 while (check_TOKEN(buf) == TOKEN_SEMICOLON) 1281 get_TOKEN(buf); 1282 if (check_TOKEN(buf) == TOKEN_COMMA) 1283 get_TOKEN(buf); 1284 } 1285 } 1286 1287 buf->pxo->members[i].size = buf->cur_pos_data - buf->pxo->members[i].start; 1288 } 1289 1290 return TRUE; 1291 } 1292 1293 static BOOL parse_object_parts(parse_buffer * buf, BOOL allow_optional) 1294 { 1295 buf->pxo->nb_children = 0; 1296 1297 if (!parse_object_members_list(buf)) 1298 return FALSE; 1299 1300 if (allow_optional) 1301 { 1302 buf->pxo->size = buf->cur_pos_data - buf->pxo->pos_data; 1303 1304 while (1) 1305 { 1306 if (check_TOKEN(buf) == TOKEN_OBRACE) 1307 { 1308 ULONG i, j; 1309 get_TOKEN(buf); 1310 if (get_TOKEN(buf) != TOKEN_NAME) 1311 return FALSE; 1312 if (get_TOKEN(buf) != TOKEN_CBRACE) 1313 return FALSE; 1314 TRACE("Found optional reference %s\n", (char*)buf->value); 1315 for (i = 0; i < (buf->nb_pxo_globals+1); i++) 1316 { 1317 for (j = 0; j < (buf->pxo_globals[i])[0].nb_subobjects; j++) 1318 { 1319 if (!strcmp((buf->pxo_globals[i])[j].name, (char*)buf->value)) 1320 goto _exit; 1321 } 1322 } 1323 _exit: 1324 if (i == (buf->nb_pxo_globals+1)) 1325 { 1326 ERR("Reference to unknown object %s\n", (char*)buf->value); 1327 return FALSE; 1328 } 1329 1330 if (buf->pxo->root->nb_subobjects >= MAX_SUBOBJECTS) 1331 { 1332 FIXME("Too many sub-objects\n"); 1333 return FALSE; 1334 } 1335 1336 buf->pxo->children[buf->pxo->nb_children] = &buf->pxo_tab[buf->pxo->root->nb_subobjects++]; 1337 buf->pxo->children[buf->pxo->nb_children]->ptarget = &(buf->pxo_globals[i])[j]; 1338 buf->pxo->children[buf->pxo->nb_children]->binary = FALSE; 1339 buf->pxo->nb_children++; 1340 } 1341 else if (check_TOKEN(buf) == TOKEN_NAME) 1342 { 1343 xobject* pxo = buf->pxo; 1344 1345 if (buf->pxo->root->nb_subobjects >= MAX_SUBOBJECTS) 1346 { 1347 FIXME("Too many sub-objects\n"); 1348 return FALSE; 1349 } 1350 1351 buf->pxo = buf->pxo->children[buf->pxo->nb_children] = &buf->pxo_tab[buf->pxo->root->nb_subobjects]; 1352 pxo->root->nb_subobjects++; 1353 1354 TRACE("Enter optional %s\n", (char*)buf->value); 1355 buf->level++; 1356 if (!parse_object(buf)) 1357 { 1358 buf->level--; 1359 return FALSE; 1360 } 1361 buf->level--; 1362 buf->pxo = pxo; 1363 buf->pxo->nb_children++; 1364 } 1365 else 1366 break; 1367 } 1368 } 1369 1370 if (buf->pxo->nb_children > MAX_CHILDREN) 1371 { 1372 FIXME("Too many children %d\n", buf->pxo->nb_children); 1373 return FALSE; 1374 } 1375 1376 return TRUE; 1377 } 1378 1379 BOOL parse_object(parse_buffer * buf) 1380 { 1381 ULONG i; 1382 1383 buf->pxo->pos_data = buf->cur_pos_data; 1384 buf->pxo->ptarget = NULL; 1385 buf->pxo->binary = FALSE; 1386 buf->pxo->root = buf->pxo_tab; 1387 1388 if (get_TOKEN(buf) != TOKEN_NAME) 1389 return FALSE; 1390 1391 /* To do template lookup */ 1392 for (i = 0; i < buf->pdxf->nb_xtemplates; i++) 1393 { 1394 if (!_strnicmp((char*)buf->value, buf->pdxf->xtemplates[i].name, -1)) 1395 { 1396 buf->pxt[buf->level] = &buf->pdxf->xtemplates[i]; 1397 memcpy(&buf->pxo->type, &buf->pdxf->xtemplates[i].class_id, 16); 1398 break; 1399 } 1400 } 1401 if (i == buf->pdxf->nb_xtemplates) 1402 { 1403 ERR("Unknown template %s\n", (char*)buf->value); 1404 return FALSE; 1405 } 1406 1407 if (check_TOKEN(buf) == TOKEN_NAME) 1408 { 1409 get_TOKEN(buf); 1410 strcpy(buf->pxo->name, (char*)buf->value); 1411 } 1412 else 1413 buf->pxo->name[0] = 0; 1414 1415 if (get_TOKEN(buf) != TOKEN_OBRACE) 1416 return FALSE; 1417 if (check_TOKEN(buf) == TOKEN_GUID) 1418 { 1419 get_TOKEN(buf); 1420 memcpy(&buf->pxo->class_id, buf->value, 16); 1421 } 1422 else 1423 memset(&buf->pxo->class_id, 0, 16); 1424 1425 if (!parse_object_parts(buf, TRUE)) 1426 return FALSE; 1427 if (get_TOKEN(buf) != TOKEN_CBRACE) 1428 return FALSE; 1429 1430 /* For seeking to a possibly eof to avoid parsing another object next time */ 1431 check_TOKEN(buf); 1432 1433 return TRUE; 1434 } 1435