the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 963 lines 30 kB view raw
1// 4J-PB - 2// The ATG Framework is a common set of C++ class libraries that is used by the samples in the XDK, and was developed by the Advanced Technology Group (ATG). 3// The ATG Framework offers a clean and consistent format for the samples. These classes define functions used by all the samples. 4// The ATG Framework together with the samples demonstrates best practices and innovative techniques for Xbox 360. There are many useful sections of code in the samples. 5// You are encouraged to incorporate this code into your titles. 6 7 8//------------------------------------------------------------------------------------- 9// AtgXmlParser.cpp 10// 11// Simple callback non-validating XML parser implementation. 12// 13// Xbox Advanced Technology Group. 14// Copyright (C) Microsoft Corporation. All rights reserved. 15//------------------------------------------------------------------------------------- 16 17#include "stdafx.h" 18#include "AtgXmlParser.h" 19 20namespace ATG 21{ 22 23//------------------------------------------------------------------------------------- 24// Name: XMLParser::XMLParser 25//------------------------------------------------------------------------------------- 26XMLParser::XMLParser() 27{ 28 m_pWritePtr = m_pWriteBuf; 29 m_pReadPtr = m_pReadBuf; 30 m_pISAXCallback = NULL; 31 m_hFile = INVALID_HANDLE_VALUE; 32} 33 34//------------------------------------------------------------------------------------- 35// Name: XMLParser::~XMLParser 36//------------------------------------------------------------------------------------- 37XMLParser::~XMLParser() 38{ 39} 40 41 42//------------------------------------------------------------------------------------- 43// Name: XMLParser::FillBuffer 44// Desc: Reads a block from the current open file 45//------------------------------------------------------------------------------------- 46VOID XMLParser::FillBuffer() 47{ 48 DWORD NChars; 49 50 m_pReadPtr = m_pReadBuf; 51 52 if( m_hFile == NULL ) 53 { 54 if( m_uInXMLBufferCharsLeft > XML_READ_BUFFER_SIZE ) 55 NChars = XML_READ_BUFFER_SIZE; 56 else 57 NChars = m_uInXMLBufferCharsLeft; 58 59 CopyMemory( m_pReadBuf, m_pInXMLBuffer, NChars ); 60 m_uInXMLBufferCharsLeft -= NChars; 61 m_pInXMLBuffer += NChars; 62 } 63 else 64 { 65 if( !ReadFile( m_hFile, m_pReadBuf, XML_READ_BUFFER_SIZE, &NChars, NULL )) 66 { 67 return; 68 } 69 } 70 71 m_dwCharsConsumed += NChars; 72 __int64 iProgress = m_dwCharsTotal ? (( (__int64)m_dwCharsConsumed * 1000 ) / (__int64)m_dwCharsTotal) : 0; 73 m_pISAXCallback->SetParseProgress( (DWORD)iProgress ); 74 75 m_pReadBuf[ NChars ] = '\0'; 76 m_pReadBuf[ NChars + 1] = '\0'; 77} 78 79 80//------------------------------------------------------------------------------------- 81// Name: XMLParser::SkipNextAdvance 82// Desc: Puts the last character read back on the input stream 83//------------------------------------------------------------------------------------- 84VOID XMLParser::SkipNextAdvance() 85{ 86 m_bSkipNextAdvance = TRUE; 87} 88 89 90//------------------------------------------------------------------------------------- 91// Name: XMLParser::ConsumeSpace 92// Desc: Skips spaces in the current stream 93//------------------------------------------------------------------------------------- 94HRESULT XMLParser::ConsumeSpace() 95{ 96 HRESULT hr; 97 98 // Skip spaces 99 if( FAILED( hr = AdvanceCharacter() ) ) 100 return hr; 101 102 while ( ( m_Ch == ' ' ) || ( m_Ch == '\t' ) || 103 ( m_Ch == '\n' ) || ( m_Ch == '\r' ) ) 104 { 105 if( FAILED( hr = AdvanceCharacter() ) ) 106 return hr; 107 } 108 SkipNextAdvance(); 109 return S_OK; 110} 111 112 113//------------------------------------------------------------------------------------- 114// Name: XMLParser::ConvertEscape 115// Desc: Copies and converts an escape sequence into m_pWriteBuf 116//------------------------------------------------------------------------------------- 117HRESULT XMLParser::ConvertEscape() 118{ 119 HRESULT hr; 120 WCHAR wVal = 0; 121 122 if( FAILED( hr = AdvanceCharacter() ) ) 123 return hr; 124 125 // all escape sequences start with &, so ignore the first character 126 127 if( FAILED( hr = AdvanceCharacter() ) ) 128 return hr; 129 130 if ( m_Ch == '#' ) // character as hex or decimal 131 { 132 if( FAILED( hr = AdvanceCharacter() ) ) 133 return hr; 134 if ( m_Ch == 'x' ) // hex number 135 { 136 if( FAILED( hr = AdvanceCharacter() ) ) 137 return hr; 138 139 while ( m_Ch != ';' ) 140 { 141 wVal *= 16; 142 143 if ( ( m_Ch >= '0' ) && ( m_Ch <= '9' ) ) 144 { 145 wVal += m_Ch - '0'; 146 } 147 else if ( ( m_Ch >= 'a' ) && ( m_Ch <= 'f' ) ) 148 { 149 wVal += m_Ch - 'a' + 10; 150 } 151 else if ( ( m_Ch >= 'A' ) && ( m_Ch <= 'F' ) ) 152 { 153 wVal += m_Ch - 'A' + 10; 154 } 155 else 156 { 157 Error( E_INVALID_XML_SYNTAX, "Expected hex digit as part of &#x escape sequence" ); 158 return E_INVALID_XML_SYNTAX; 159 } 160 161 if( FAILED( hr = AdvanceCharacter() ) ) 162 return hr; 163 } 164 } 165 else // decimal number 166 { 167 while ( m_Ch != ';' ) 168 { 169 wVal *= 10; 170 171 if ( ( m_Ch >= '0' ) && ( m_Ch <= '9' ) ) 172 { 173 wVal += m_Ch - '0'; 174 } 175 else 176 { 177 Error( E_INVALID_XML_SYNTAX, "Expected decimal digit as part of &# escape sequence" ); 178 return E_INVALID_XML_SYNTAX; 179 } 180 181 if( FAILED( hr = AdvanceCharacter() ) ) 182 return hr; 183 } 184 } 185 186 // copy character into the buffer 187 m_Ch = wVal; 188 189 return S_OK; 190 } 191 192 // must be an entity reference 193 194 WCHAR *pEntityRefVal = m_pWritePtr; 195 UINT EntityRefLen; 196 197 SkipNextAdvance(); 198 if( FAILED( hr = AdvanceName() ) ) 199 return hr; 200 201 EntityRefLen = (UINT)( m_pWritePtr - pEntityRefVal ); 202 m_pWritePtr = pEntityRefVal; 203 204 if ( EntityRefLen == 0 ) 205 { 206 Error( E_INVALID_XML_SYNTAX, "Expecting entity name after &" ); 207 return E_INVALID_XML_SYNTAX; 208 } 209 210 if( !wcsncmp( pEntityRefVal, L"lt", EntityRefLen ) ) 211 wVal = '<'; 212 else if( !wcsncmp( pEntityRefVal, L"gt", EntityRefLen ) ) 213 wVal = '>'; 214 else if( !wcsncmp( pEntityRefVal, L"amp", EntityRefLen ) ) 215 wVal = '&'; 216 else if( !wcsncmp( pEntityRefVal, L"apos", EntityRefLen ) ) 217 wVal = '\''; 218 else if( !wcsncmp( pEntityRefVal, L"quot", EntityRefLen ) ) 219 wVal = '"'; 220 else 221 { 222 Error( E_INVALID_XML_SYNTAX, "Unrecognized entity name after & - (should be lt, gt, amp, apos, or quot)" ); 223 return E_INVALID_XML_SYNTAX; // return false if unrecognized token sequence 224 } 225 226 if( FAILED( hr = AdvanceCharacter() ) ) 227 return hr; 228 229 if( m_Ch != ';' ) 230 { 231 Error( E_INVALID_XML_SYNTAX, "Expected terminating ; for entity reference" ); 232 return E_INVALID_XML_SYNTAX; // malformed reference - needs terminating ; 233 } 234 235 m_Ch = wVal; 236 return S_OK; 237} 238 239 240//------------------------------------------------------------------------------------- 241// Name: XMLParser::AdvanceAttrVal 242// Desc: Copies an attribute value into m_pWrite buf, skipping surrounding quotes 243//------------------------------------------------------------------------------------- 244HRESULT XMLParser::AdvanceAttrVal() 245{ 246 HRESULT hr; 247 WCHAR wQuoteChar; 248 249 if( FAILED( hr = AdvanceCharacter() ) ) 250 return hr; 251 252 if( ( m_Ch != '"' ) && ( m_Ch != '\'' ) ) 253 { 254 Error( E_INVALID_XML_SYNTAX, "Attribute values must be enclosed in quotes" ); 255 return E_INVALID_XML_SYNTAX; 256 } 257 258 wQuoteChar = m_Ch; 259 260 for( ;; ) 261 { 262 if( FAILED( hr = AdvanceCharacter() ) ) 263 return hr; 264 else if( m_Ch == wQuoteChar ) 265 break; 266 else if( m_Ch == '&' ) 267 { 268 SkipNextAdvance(); 269 if( FAILED( hr = ConvertEscape() ) ) 270 return hr; 271 } 272 else if( m_Ch == '<' ) 273 { 274 Error( E_INVALID_XML_SYNTAX, "Illegal character '<' in element tag" ); 275 return E_INVALID_XML_SYNTAX; 276 } 277 278 // copy character into the buffer 279 280 if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE ) 281 { 282 Error( E_INVALID_XML_SYNTAX, "Total element tag size may not be more than %d characters", XML_WRITE_BUFFER_SIZE ); 283 return E_INVALID_XML_SYNTAX; 284 } 285 286 *m_pWritePtr = m_Ch; 287 m_pWritePtr++; 288 } 289 return S_OK; 290} 291 292 293//------------------------------------------------------------------------------------- 294// Name: XMLParser::AdvanceName 295// Desc: Copies a name into the m_pWriteBuf - returns TRUE on success, FALSE on failure 296// Ignores leading whitespace. Currently does not support unicode names 297//------------------------------------------------------------------------------------- 298HRESULT XMLParser::AdvanceName() 299{ 300 HRESULT hr; 301 302 if( FAILED( hr = AdvanceCharacter() ) ) 303 return hr; 304 305 if( ( ( m_Ch < 'A' ) || ( m_Ch > 'Z' ) ) && 306 ( ( m_Ch < 'a' ) || ( m_Ch > 'z' ) ) && 307 ( m_Ch != '_' ) && ( m_Ch != ':' ) ) 308 { 309 Error( E_INVALID_XML_SYNTAX, "Names must start with an alphabetic character or _ or :" ); 310 return E_INVALID_XML_SYNTAX; 311 } 312 313 while( ( ( m_Ch >= 'A' ) && ( m_Ch <= 'Z' ) ) || 314 ( ( m_Ch >= 'a' ) && ( m_Ch <= 'z' ) ) || 315 ( ( m_Ch >= '0' ) && ( m_Ch <= '9' ) ) || 316 ( m_Ch == '_' ) || ( m_Ch == ':' ) || 317 ( m_Ch == '-' ) || ( m_Ch == '.' ) ) 318 { 319 320 if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE ) 321 { 322 Error( E_INVALID_XML_SYNTAX, "Total element tag size may not be more than %d characters", XML_WRITE_BUFFER_SIZE ); 323 return E_INVALID_XML_SYNTAX; 324 } 325 326 *m_pWritePtr = m_Ch; 327 m_pWritePtr++; 328 329 if( FAILED( hr = AdvanceCharacter() ) ) 330 return hr; 331 } 332 333 SkipNextAdvance(); 334 return S_OK; 335} 336 337 338//------------------------------------------------------------------------------------- 339// Name: XMLParser::AdvanceCharacter 340// Desc: Copies the character at *m_pReadPtr to m_Ch 341// handling difference in UTF16 / UTF8, and big/little endian 342// and getting another chunk of the file if needed 343// Returns S_OK if there are more characters, E_ABORT for no characters to read 344//------------------------------------------------------------------------------------- 345HRESULT XMLParser::AdvanceCharacter( BOOL bOkToFail ) 346{ 347 if( m_bSkipNextAdvance ) 348 { 349 m_bSkipNextAdvance = FALSE; 350 return S_OK; 351 } 352 353 // If we hit EOF in the middle of a character, 354 // it's ok-- we'll just have a corrupt last character 355 // (the buffer is padded with double NULLs ) 356 357 if ( ( m_pReadPtr[0] == '\0' ) && ( m_pReadPtr[1] == '\0' ) ) 358 { 359 // Read more from the file 360 FillBuffer(); 361 362 // We are at EOF if it is still NULL 363 if ( ( m_pReadPtr[0] == '\0' ) && ( m_pReadPtr[1] == '\0' ) ) 364 { 365 if( !bOkToFail ) 366 { 367 Error( E_INVALID_XML_SYNTAX, "Unexpected EOF while parsing XML file" ); 368 return E_INVALID_XML_SYNTAX; 369 } 370 else 371 { 372 return E_FAIL; 373 } 374 } 375 } 376 377 if( m_bUnicode == FALSE ) 378 { 379 m_Ch = *((CHAR *)m_pReadPtr); 380 m_pReadPtr++; 381 } 382 else // if( m_bUnicode == TRUE ) 383 { 384 m_Ch = *((WCHAR *)m_pReadPtr); 385 386 if( m_bReverseBytes ) 387 { 388 m_Ch = ( m_Ch << 8 ) + ( m_Ch >> 8 ); 389 } 390 391 m_pReadPtr += 2; 392 } 393 394 if( m_Ch == '\n' ) 395 { 396 m_pISAXCallback->m_LineNum++; 397 m_pISAXCallback->m_LinePos = 0; 398 } 399 else if( m_Ch != '\r' ) 400 m_pISAXCallback->m_LinePos++; 401 402 return S_OK; 403} 404 405 406//------------------------------------------------------------------------------------- 407// Name: XMLParser::AdvanceElement 408// Desc: Builds <element> data, calls callback 409//------------------------------------------------------------------------------------- 410HRESULT XMLParser::AdvanceElement() 411{ 412 HRESULT hr; 413 414 // write ptr at the beginning of the buffer 415 m_pWritePtr = m_pWriteBuf; 416 417 if( FAILED( hr = AdvanceCharacter() ) ) 418 return hr; 419 420 // if first character wasn't '<', we wouldn't be here 421 422 if( FAILED( hr = AdvanceCharacter() ) ) 423 return hr; 424 425 if( m_Ch == '!' ) 426 { 427 if( FAILED( hr = AdvanceCharacter() ) ) 428 return hr; 429 if ( m_Ch == '-' ) 430 { 431 if( FAILED( hr = AdvanceCharacter() ) ) 432 return hr; 433 if( m_Ch != '-' ) 434 { 435 Error( E_INVALID_XML_SYNTAX, "Expecting '-' after '<!-'" ); 436 return E_INVALID_XML_SYNTAX; 437 } 438 if( FAILED( hr = AdvanceComment() ) ) 439 return hr; 440 return S_OK; 441 } 442 443 if( m_Ch != '[' ) 444 { 445 Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" ); 446 return E_INVALID_XML_SYNTAX; 447 } 448 if( FAILED( hr = AdvanceCharacter() ) ) 449 return hr; 450 if( m_Ch != 'C' ) 451 { 452 Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" ); 453 return E_INVALID_XML_SYNTAX; 454 } 455 if( FAILED( hr = AdvanceCharacter() ) ) 456 return hr; 457 if( m_Ch != 'D' ) 458 { 459 Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" ); 460 return E_INVALID_XML_SYNTAX; 461 } 462 if( FAILED( hr = AdvanceCharacter() ) ) 463 return hr; 464 if( m_Ch != 'A' ) 465 { 466 Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" ); 467 return E_INVALID_XML_SYNTAX; 468 } 469 if( FAILED( hr = AdvanceCharacter() ) ) 470 return hr; 471 if( m_Ch != 'T' ) 472 { 473 Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" ); 474 return E_INVALID_XML_SYNTAX; 475 } 476 if( FAILED( hr = AdvanceCharacter() ) ) 477 return hr; 478 if( m_Ch != 'A' ) 479 { 480 Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" ); 481 return E_INVALID_XML_SYNTAX; 482 } 483 if( FAILED( hr = AdvanceCharacter() ) ) 484 return hr; 485 if( m_Ch != '[' ) 486 { 487 Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" ); 488 return E_INVALID_XML_SYNTAX; 489 } 490 if( FAILED( hr = AdvanceCDATA() ) ) 491 return hr; 492 } 493 else if( m_Ch == '/' ) 494 { 495 WCHAR *pEntityRefVal = m_pWritePtr; 496 497 if( FAILED( hr = AdvanceName() ) ) 498 return hr; 499 500 if( FAILED( m_pISAXCallback->ElementEnd( pEntityRefVal, 501 (UINT) ( m_pWritePtr - pEntityRefVal ) ) ) ) 502 return E_ABORT; 503 504 if( FAILED( hr = ConsumeSpace() ) ) 505 return hr; 506 507 if( FAILED( hr = AdvanceCharacter() ) ) 508 return hr; 509 510 if( m_Ch != '>' ) 511 { 512 Error( E_INVALID_XML_SYNTAX, "Expecting '>' after name for closing entity reference" ); 513 return E_INVALID_XML_SYNTAX; 514 } 515 } 516 else if( m_Ch == '?' ) 517 { 518 // just skip any xml header tag since not really important after identifying character set 519 for( ;; ) 520 { 521 if( FAILED( hr = AdvanceCharacter() ) ) 522 return hr; 523 524 if ( m_Ch == '>' ) 525 return S_OK; 526 } 527 } 528 else 529 { 530 XMLAttribute Attributes[ XML_MAX_ATTRIBUTES_PER_ELEMENT ]; 531 UINT NumAttrs; 532 533 WCHAR *pEntityRefVal = m_pWritePtr; 534 UINT EntityRefLen; 535 536 NumAttrs = 0; 537 538 SkipNextAdvance(); 539 540 // Entity tag 541 if( FAILED( hr = AdvanceName() ) ) 542 return hr; 543 544 EntityRefLen = (UINT)( m_pWritePtr - pEntityRefVal ); 545 546 if( FAILED( hr = ConsumeSpace() ) ) 547 return hr; 548 549 if( FAILED( hr = AdvanceCharacter() ) ) 550 return hr; 551 552 // read attributes 553 while( ( m_Ch != '>' ) && ( m_Ch != '/' ) ) 554 { 555 SkipNextAdvance(); 556 557 if ( NumAttrs >= XML_MAX_ATTRIBUTES_PER_ELEMENT ) 558 { 559 Error( E_INVALID_XML_SYNTAX, "Elements may not have more than %d attributes", XML_MAX_ATTRIBUTES_PER_ELEMENT ); 560 return E_INVALID_XML_SYNTAX; 561 } 562 563 Attributes[ NumAttrs ].strName = m_pWritePtr; 564 565 // Attribute name 566 if( FAILED( hr = AdvanceName() ) ) 567 return hr; 568 569 Attributes[ NumAttrs ].NameLen = (UINT)( m_pWritePtr - Attributes[ NumAttrs ].strName ); 570 571 if( FAILED( hr = ConsumeSpace() ) ) 572 return hr; 573 574 if( FAILED( hr = AdvanceCharacter() ) ) 575 return hr; 576 577 if( m_Ch != '=' ) 578 { 579 Error( E_INVALID_XML_SYNTAX, "Expecting '=' character after attribute name" ); 580 return E_INVALID_XML_SYNTAX; 581 } 582 583 if( FAILED( hr = ConsumeSpace() ) ) 584 return hr; 585 586 Attributes[ NumAttrs ].strValue = m_pWritePtr; 587 588 if( FAILED( hr = AdvanceAttrVal() ) ) 589 return hr; 590 591 Attributes[ NumAttrs ].ValueLen = (UINT)( m_pWritePtr - 592 Attributes[ NumAttrs ].strValue ); 593 594 ++NumAttrs; 595 596 if( FAILED( hr = ConsumeSpace() ) ) 597 return hr; 598 599 if( FAILED( hr = AdvanceCharacter() ) ) 600 return hr; 601 } 602 603 if( m_Ch == '/' ) 604 { 605 if( FAILED( hr = AdvanceCharacter() ) ) 606 return hr; 607 if( m_Ch != '>' ) 608 { 609 Error( E_INVALID_XML_SYNTAX, "Expecting '>' after '/' in element tag" ); 610 return E_INVALID_XML_SYNTAX; 611 } 612 613 if( FAILED( m_pISAXCallback->ElementBegin( pEntityRefVal, EntityRefLen, 614 Attributes, NumAttrs ) ) ) 615 return E_ABORT; 616 617 if( FAILED( m_pISAXCallback->ElementEnd( pEntityRefVal, EntityRefLen ) ) ) 618 return E_ABORT; 619 } 620 else 621 { 622 if( FAILED( m_pISAXCallback->ElementBegin( pEntityRefVal, EntityRefLen, 623 Attributes, NumAttrs ) ) ) 624 return E_ABORT; 625 } 626 } 627 628 return S_OK; 629} 630 631 632//------------------------------------------------------------------------------------- 633// Name: XMLParser::AdvanceCDATA 634// Desc: Read a CDATA section 635//------------------------------------------------------------------------------------- 636HRESULT XMLParser::AdvanceCDATA() 637{ 638 HRESULT hr; 639 WORD wStage = 0; 640 641 if( FAILED( m_pISAXCallback->CDATABegin() ) ) 642 return E_ABORT; 643 644 for( ;; ) 645 { 646 if( FAILED( hr = AdvanceCharacter() ) ) 647 return hr; 648 649 *m_pWritePtr = m_Ch; 650 m_pWritePtr++; 651 652 if( ( m_Ch == ']' ) && ( wStage == 0 ) ) 653 wStage = 1; 654 else if( ( m_Ch == ']' ) && ( wStage == 1 ) ) 655 wStage = 2; 656 else if( ( m_Ch == '>' ) && ( wStage == 2 ) ) 657 { 658 m_pWritePtr -= 3; 659 break; 660 } 661 else 662 wStage = 0; 663 664 if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE ) 665 { 666 if( FAILED( m_pISAXCallback->CDATAData( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), TRUE ) ) ) 667 return E_ABORT; 668 m_pWritePtr = m_pWriteBuf; 669 } 670 } 671 672 if( FAILED( m_pISAXCallback->CDATAData( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), FALSE ) ) ) 673 return E_ABORT; 674 675 m_pWritePtr = m_pWriteBuf; 676 677 if( FAILED( m_pISAXCallback->CDATAEnd() ) ) 678 return E_ABORT; 679 680 return S_OK; 681} 682 683//------------------------------------------------------------------------------------- 684// Name: XMLParser::AdvanceComment 685// Desk: Skips over a comment 686//------------------------------------------------------------------------------------- 687HRESULT XMLParser::AdvanceComment() 688{ 689 HRESULT hr; 690 WORD wStage; 691 692 wStage = 0; 693 for( ;; ) 694 { 695 if( FAILED( hr = AdvanceCharacter() ) ) 696 return hr; 697 698 if (( m_Ch == '-' ) && ( wStage == 0 )) 699 wStage = 1; 700 else if (( m_Ch == '-' ) && ( wStage == 1 )) 701 wStage = 2; 702 else if (( m_Ch == '>' ) && ( wStage == 2 )) 703 break; 704 else 705 wStage = 0; 706 } 707 708 return S_OK; 709} 710 711 712//------------------------------------------------------------------------------------- 713// Name: XMLParser::RegisterSAXCallbackInterface 714// Desc: Registers callback interface 715//------------------------------------------------------------------------------------- 716VOID XMLParser::RegisterSAXCallbackInterface( ISAXCallback *pISAXCallback ) 717{ 718 m_pISAXCallback = pISAXCallback; 719} 720 721 722//------------------------------------------------------------------------------------- 723// Name: XMLParser::GetSAXCallbackInterface 724// Desc: Returns current callback interface 725//------------------------------------------------------------------------------------- 726ISAXCallback* XMLParser::GetSAXCallbackInterface() 727{ 728 return m_pISAXCallback; 729} 730 731 732//------------------------------------------------------------------------------------- 733// Name: XMLParser::MainParseLoop 734// Desc: Main Loop to Parse Data - source agnostic 735//------------------------------------------------------------------------------------- 736HRESULT XMLParser::MainParseLoop() 737{ 738 BOOL bWhiteSpaceOnly = TRUE; 739 HRESULT hr = S_OK; 740 741 if( FAILED( m_pISAXCallback->StartDocument() ) ) 742 return E_ABORT; 743 744 m_pWritePtr = m_pWriteBuf; 745 746 FillBuffer(); 747 748 if ( *((WCHAR *) m_pReadBuf ) == 0xFEFF ) 749 { 750 m_bUnicode = TRUE; 751 m_bReverseBytes = FALSE; 752 m_pReadPtr += 2; 753 } 754 else if ( *((WCHAR *) m_pReadBuf ) == 0xFFFE ) 755 { 756 m_bUnicode = TRUE; 757 m_bReverseBytes = TRUE; 758 m_pReadPtr += 2; 759 } 760 else if ( *((WCHAR *) m_pReadBuf ) == 0x003C ) 761 { 762 m_bUnicode = TRUE; 763 m_bReverseBytes = FALSE; 764 } 765 else if ( *((WCHAR *) m_pReadBuf ) == 0x3C00 ) 766 { 767 m_bUnicode = TRUE; 768 m_bReverseBytes = TRUE; 769 } 770 else if ( m_pReadBuf[ 0 ] == 0x3C ) 771 { 772 m_bUnicode = FALSE; 773 m_bReverseBytes = FALSE; 774 } 775 else 776 { 777 Error( E_INVALID_XML_SYNTAX, "Unrecognized encoding (parser does not support UTF-8 language encodings)" ); 778 return E_INVALID_XML_SYNTAX; 779 } 780 781 for( ;; ) 782 { 783 if( FAILED( AdvanceCharacter( TRUE ) ) ) 784 { 785 if ( ( (UINT) ( m_pWritePtr - m_pWriteBuf ) != 0 ) && ( !bWhiteSpaceOnly ) ) 786 { 787 if( FAILED( m_pISAXCallback->ElementContent( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), FALSE ) ) ) 788 return E_ABORT; 789 790 bWhiteSpaceOnly = TRUE; 791 } 792 793 if( FAILED( m_pISAXCallback->EndDocument() ) ) 794 return E_ABORT; 795 796 return S_OK; 797 } 798 799 if( m_Ch == '<' ) 800 { 801 if( ( (UINT) ( m_pWritePtr - m_pWriteBuf ) != 0 ) && ( !bWhiteSpaceOnly ) ) 802 { 803 if( FAILED( m_pISAXCallback->ElementContent( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), FALSE ) ) ) 804 return E_ABORT; 805 806 bWhiteSpaceOnly = TRUE; 807 } 808 809 SkipNextAdvance(); 810 811 m_pWritePtr = m_pWriteBuf; 812 813 if( FAILED( hr = AdvanceElement() ) ) 814 return hr; 815 816 m_pWritePtr = m_pWriteBuf; 817 } 818 else 819 { 820 if( m_Ch == '&' ) 821 { 822 SkipNextAdvance(); 823 if( FAILED( hr = ConvertEscape() ) ) 824 return hr; 825 } 826 827 if( bWhiteSpaceOnly && ( m_Ch != ' ' ) && ( m_Ch != '\n' ) && ( m_Ch != '\r' ) && 828 ( m_Ch != '\t' ) ) 829 { 830 bWhiteSpaceOnly = FALSE; 831 } 832 833 *m_pWritePtr = m_Ch; 834 m_pWritePtr++; 835 836 if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE ) 837 { 838 if( !bWhiteSpaceOnly ) 839 { 840 if( FAILED( m_pISAXCallback->ElementContent( m_pWriteBuf, 841 ( UINT ) ( m_pWritePtr - m_pWriteBuf ), 842 TRUE ) ) ) 843 { 844 return E_ABORT; 845 } 846 } 847 848 m_pWritePtr = m_pWriteBuf; 849 bWhiteSpaceOnly = TRUE; 850 } 851 } 852 } 853} 854 855 856//------------------------------------------------------------------------------------- 857// Name: XMLParser::ParseXMLFile 858// Desc: Builds element data 859//------------------------------------------------------------------------------------- 860HRESULT XMLParser::ParseXMLFile( CONST CHAR *strFilename ) 861{ 862 HRESULT hr; 863 864 if( m_pISAXCallback == NULL ) 865 return E_NOINTERFACE; 866 867 m_pISAXCallback->m_LineNum = 1; 868 m_pISAXCallback->m_LinePos = 0; 869 m_pISAXCallback->m_strFilename = strFilename; // save this off only while we parse the file 870 871 m_bSkipNextAdvance = FALSE; 872 m_pReadPtr = m_pReadBuf; 873 874 m_pReadBuf[ 0 ] = '\0'; 875 m_pReadBuf[ 1 ] = '\0'; 876 877 m_pInXMLBuffer = NULL; 878 m_uInXMLBufferCharsLeft = 0; 879 m_hFile = CreateFile( strFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); 880 881 if( m_hFile == INVALID_HANDLE_VALUE ) 882 { 883 Error( E_COULD_NOT_OPEN_FILE, "Error opening file" ); 884 hr = E_COULD_NOT_OPEN_FILE; 885 886 } 887 else 888 { 889 LARGE_INTEGER iFileSize; 890 GetFileSizeEx( m_hFile, &iFileSize ); 891 m_dwCharsTotal = (DWORD)iFileSize.QuadPart; 892 m_dwCharsConsumed = 0; 893 hr = MainParseLoop(); 894 } 895 896 // Close the file 897 if( m_hFile != INVALID_HANDLE_VALUE ) 898 CloseHandle( m_hFile ); 899 m_hFile = INVALID_HANDLE_VALUE; 900 901 // we no longer own strFilename, so un-set it 902 m_pISAXCallback->m_strFilename = NULL; 903 904 return hr; 905} 906 907//------------------------------------------------------------------------------------- 908// Name: XMLParser::ParseXMLFile 909// Desc: Builds element data 910//------------------------------------------------------------------------------------- 911HRESULT XMLParser::ParseXMLBuffer( CONST CHAR *strBuffer, UINT uBufferSize ) 912{ 913 HRESULT hr; 914 915 if( m_pISAXCallback == NULL ) 916 return E_NOINTERFACE; 917 918 m_pISAXCallback->m_LineNum = 1; 919 m_pISAXCallback->m_LinePos = 0; 920 m_pISAXCallback->m_strFilename = ""; // save this off only while we parse the file 921 922 m_bSkipNextAdvance = FALSE; 923 m_pReadPtr = m_pReadBuf; 924 925 m_pReadBuf[ 0 ] = '\0'; 926 m_pReadBuf[ 1 ] = '\0'; 927 928 m_hFile = NULL; 929 m_pInXMLBuffer = strBuffer; 930 m_uInXMLBufferCharsLeft = uBufferSize; 931 m_dwCharsTotal = uBufferSize; 932 m_dwCharsConsumed = 0; 933 934 hr = MainParseLoop(); 935 936 // we no longer own strFilename, so un-set it 937 m_pISAXCallback->m_strFilename = NULL; 938 939 return hr; 940} 941 942//------------------------------------------------------------------------------------- 943// XMLParser::Error() 944// Logs an error through the callback interface 945//------------------------------------------------------------------------------------- 946#ifdef _Printf_format_string_ // VC++ 2008 and later support this annotation 947VOID XMLParser::Error( HRESULT hErr, _In_z_ _Printf_format_string_ CONST CHAR* strFormat, ... ) 948#else 949VOID XMLParser::Error( HRESULT hErr, CONST CHAR* strFormat, ... ) 950#endif 951{ 952 CONST INT MAX_OUTPUT_STR = 160; 953 CHAR strBuffer[ MAX_OUTPUT_STR ]; 954 va_list pArglist; 955 va_start( pArglist, strFormat ); 956 957 vsprintf( strBuffer, strFormat, pArglist ); 958 959 m_pISAXCallback->Error( hErr, strBuffer ); 960 va_end( pArglist ); 961} 962 963} // namespace ATG