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