This code was not tested and breaks in Release builds, reverting to restore
functionality of the nightly. All in-game menus do not work and generating
a world crashes.
This reverts commit a9be52c41a.
969 lines
28 KiB
C++
969 lines
28 KiB
C++
// 4J-PB -
|
|
// 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).
|
|
// The ATG Framework offers a clean and consistent format for the samples. These classes define functions used by all the samples.
|
|
// 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.
|
|
// You are encouraged to incorporate this code into your titles.
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// AtgXmlParser.cpp
|
|
//
|
|
// Simple callback non-validating XML parser implementation.
|
|
//
|
|
// Xbox Advanced Technology Group.
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "AtgXmlParser.h"
|
|
|
|
namespace ATG
|
|
{
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::XMLParser
|
|
//-------------------------------------------------------------------------------------
|
|
XMLParser::XMLParser()
|
|
{
|
|
m_pWritePtr = m_pWriteBuf;
|
|
m_pReadPtr = m_pReadBuf;
|
|
m_pISAXCallback = NULL;
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::~XMLParser
|
|
//-------------------------------------------------------------------------------------
|
|
XMLParser::~XMLParser()
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::FillBuffer
|
|
// Desc: Reads a block from the current open file
|
|
//-------------------------------------------------------------------------------------
|
|
VOID XMLParser::FillBuffer()
|
|
{
|
|
DWORD NChars;
|
|
|
|
m_pReadPtr = m_pReadBuf;
|
|
|
|
if( m_hFile == NULL )
|
|
{
|
|
if( m_uInXMLBufferCharsLeft > XML_READ_BUFFER_SIZE )
|
|
NChars = XML_READ_BUFFER_SIZE;
|
|
else
|
|
NChars = m_uInXMLBufferCharsLeft;
|
|
|
|
CopyMemory( m_pReadBuf, m_pInXMLBuffer, NChars );
|
|
m_uInXMLBufferCharsLeft -= NChars;
|
|
m_pInXMLBuffer += NChars;
|
|
}
|
|
else
|
|
{
|
|
if( !ReadFile( m_hFile, m_pReadBuf, XML_READ_BUFFER_SIZE, &NChars, NULL ))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_dwCharsConsumed += NChars;
|
|
int64_t iProgress = m_dwCharsTotal ? (( (int64_t)m_dwCharsConsumed * 1000 ) / (int64_t)m_dwCharsTotal) : 0;
|
|
m_pISAXCallback->SetParseProgress( (DWORD)iProgress );
|
|
|
|
m_pReadBuf[ NChars ] = '\0';
|
|
m_pReadBuf[ NChars + 1] = '\0';
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::SkipNextAdvance
|
|
// Desc: Puts the last character read back on the input stream
|
|
//-------------------------------------------------------------------------------------
|
|
VOID XMLParser::SkipNextAdvance()
|
|
{
|
|
m_bSkipNextAdvance = TRUE;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::ConsumeSpace
|
|
// Desc: Skips spaces in the current stream
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::ConsumeSpace()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Skip spaces
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
while ( ( m_Ch == ' ' ) || ( m_Ch == '\t' ) ||
|
|
( m_Ch == '\n' ) || ( m_Ch == '\r' ) )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
}
|
|
SkipNextAdvance();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::ConvertEscape
|
|
// Desc: Copies and converts an escape sequence into m_pWriteBuf
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::ConvertEscape()
|
|
{
|
|
HRESULT hr;
|
|
WCHAR wVal = 0;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
// all escape sequences start with &, so ignore the first character
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if ( m_Ch == '#' ) // character as hex or decimal
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if ( m_Ch == 'x' ) // hex number
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
while ( m_Ch != ';' )
|
|
{
|
|
wVal *= 16;
|
|
|
|
if ( ( m_Ch >= '0' ) && ( m_Ch <= '9' ) )
|
|
{
|
|
wVal += m_Ch - '0';
|
|
}
|
|
else if ( ( m_Ch >= 'a' ) && ( m_Ch <= 'f' ) )
|
|
{
|
|
wVal += m_Ch - 'a' + 10;
|
|
}
|
|
else if ( ( m_Ch >= 'A' ) && ( m_Ch <= 'F' ) )
|
|
{
|
|
wVal += m_Ch - 'A' + 10;
|
|
}
|
|
else
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expected hex digit as part of &#x escape sequence" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
}
|
|
}
|
|
else // decimal number
|
|
{
|
|
while ( m_Ch != ';' )
|
|
{
|
|
wVal *= 10;
|
|
|
|
if ( ( m_Ch >= '0' ) && ( m_Ch <= '9' ) )
|
|
{
|
|
wVal += m_Ch - '0';
|
|
}
|
|
else
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expected decimal digit as part of &# escape sequence" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
// copy character into the buffer
|
|
m_Ch = wVal;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// must be an entity reference
|
|
|
|
WCHAR *pEntityRefVal = m_pWritePtr;
|
|
UINT EntityRefLen;
|
|
|
|
SkipNextAdvance();
|
|
if( FAILED( hr = AdvanceName() ) )
|
|
return hr;
|
|
|
|
EntityRefLen = (UINT)( m_pWritePtr - pEntityRefVal );
|
|
m_pWritePtr = pEntityRefVal;
|
|
|
|
if ( EntityRefLen == 0 )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting entity name after &" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
if( !wcsncmp( pEntityRefVal, L"lt", EntityRefLen ) )
|
|
wVal = '<';
|
|
else if( !wcsncmp( pEntityRefVal, L"gt", EntityRefLen ) )
|
|
wVal = '>';
|
|
else if( !wcsncmp( pEntityRefVal, L"amp", EntityRefLen ) )
|
|
wVal = '&';
|
|
else if( !wcsncmp( pEntityRefVal, L"apos", EntityRefLen ) )
|
|
wVal = '\'';
|
|
else if( !wcsncmp( pEntityRefVal, L"quot", EntityRefLen ) )
|
|
wVal = '"';
|
|
else
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Unrecognized entity name after & - (should be lt, gt, amp, apos, or quot)" );
|
|
return E_INVALID_XML_SYNTAX; // return false if unrecognized token sequence
|
|
}
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if( m_Ch != ';' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expected terminating ; for entity reference" );
|
|
return E_INVALID_XML_SYNTAX; // malformed reference - needs terminating ;
|
|
}
|
|
|
|
m_Ch = wVal;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::AdvanceAttrVal
|
|
// Desc: Copies an attribute value into m_pWrite buf, skipping surrounding quotes
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::AdvanceAttrVal()
|
|
{
|
|
HRESULT hr;
|
|
WCHAR wQuoteChar;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if( ( m_Ch != '"' ) && ( m_Ch != '\'' ) )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Attribute values must be enclosed in quotes" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
wQuoteChar = m_Ch;
|
|
|
|
for( ;; )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
else if( m_Ch == wQuoteChar )
|
|
break;
|
|
else if( m_Ch == '&' )
|
|
{
|
|
SkipNextAdvance();
|
|
if( FAILED( hr = ConvertEscape() ) )
|
|
return hr;
|
|
}
|
|
else if( m_Ch == '<' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Illegal character '<' in element tag" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
// copy character into the buffer
|
|
|
|
if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Total element tag size may not be more than %d characters", XML_WRITE_BUFFER_SIZE );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
*m_pWritePtr = m_Ch;
|
|
m_pWritePtr++;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::AdvanceName
|
|
// Desc: Copies a name into the m_pWriteBuf - returns TRUE on success, FALSE on failure
|
|
// Ignores leading whitespace. Currently does not support unicode names
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::AdvanceName()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if( ( ( m_Ch < 'A' ) || ( m_Ch > 'Z' ) ) &&
|
|
( ( m_Ch < 'a' ) || ( m_Ch > 'z' ) ) &&
|
|
( m_Ch != '_' ) && ( m_Ch != ':' ) )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Names must start with an alphabetic character or _ or :" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
while( ( ( m_Ch >= 'A' ) && ( m_Ch <= 'Z' ) ) ||
|
|
( ( m_Ch >= 'a' ) && ( m_Ch <= 'z' ) ) ||
|
|
( ( m_Ch >= '0' ) && ( m_Ch <= '9' ) ) ||
|
|
( m_Ch == '_' ) || ( m_Ch == ':' ) ||
|
|
( m_Ch == '-' ) || ( m_Ch == '.' ) )
|
|
{
|
|
|
|
if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Total element tag size may not be more than %d characters", XML_WRITE_BUFFER_SIZE );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
*m_pWritePtr = m_Ch;
|
|
m_pWritePtr++;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
}
|
|
|
|
SkipNextAdvance();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::AdvanceCharacter
|
|
// Desc: Copies the character at *m_pReadPtr to m_Ch
|
|
// handling difference in UTF16 / UTF8, and big/little endian
|
|
// and getting another chunk of the file if needed
|
|
// Returns S_OK if there are more characters, E_ABORT for no characters to read
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::AdvanceCharacter( BOOL bOkToFail )
|
|
{
|
|
if( m_bSkipNextAdvance )
|
|
{
|
|
m_bSkipNextAdvance = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
// If we hit EOF in the middle of a character,
|
|
// it's ok-- we'll just have a corrupt last character
|
|
// (the buffer is padded with double NULLs )
|
|
|
|
if ( ( m_pReadPtr[0] == '\0' ) && ( m_pReadPtr[1] == '\0' ) )
|
|
{
|
|
// Read more from the file
|
|
FillBuffer();
|
|
|
|
// We are at EOF if it is still NULL
|
|
if ( ( m_pReadPtr[0] == '\0' ) && ( m_pReadPtr[1] == '\0' ) )
|
|
{
|
|
if( !bOkToFail )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Unexpected EOF while parsing XML file" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( m_bUnicode == FALSE )
|
|
{
|
|
m_Ch = *((CHAR *)m_pReadPtr);
|
|
m_pReadPtr++;
|
|
}
|
|
else // if( m_bUnicode == TRUE )
|
|
{
|
|
m_Ch = *((WCHAR *)m_pReadPtr);
|
|
|
|
if( m_bReverseBytes )
|
|
{
|
|
m_Ch = ( m_Ch << 8 ) + ( m_Ch >> 8 );
|
|
}
|
|
|
|
m_pReadPtr += 2;
|
|
}
|
|
|
|
if( m_Ch == '\n' )
|
|
{
|
|
m_pISAXCallback->m_LineNum++;
|
|
m_pISAXCallback->m_LinePos = 0;
|
|
}
|
|
else if( m_Ch != '\r' )
|
|
m_pISAXCallback->m_LinePos++;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::AdvanceElement
|
|
// Desc: Builds <element> data, calls callback
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::AdvanceElement()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// write ptr at the beginning of the buffer
|
|
m_pWritePtr = m_pWriteBuf;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
// if first character wasn't '<', we wouldn't be here
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if( m_Ch == '!' )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if ( m_Ch == '-' )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != '-' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '-' after '<!-'" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceComment() ) )
|
|
return hr;
|
|
return S_OK;
|
|
}
|
|
|
|
if( m_Ch != '[' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != 'C' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != 'D' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != 'A' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != 'T' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != 'A' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != '[' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '<![CDATA['" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
if( FAILED( hr = AdvanceCDATA() ) )
|
|
return hr;
|
|
}
|
|
else if( m_Ch == '/' )
|
|
{
|
|
WCHAR *pEntityRefVal = m_pWritePtr;
|
|
|
|
if( FAILED( hr = AdvanceName() ) )
|
|
return hr;
|
|
|
|
if( FAILED( m_pISAXCallback->ElementEnd( pEntityRefVal,
|
|
(UINT) ( m_pWritePtr - pEntityRefVal ) ) ) )
|
|
return E_ABORT;
|
|
|
|
if( FAILED( hr = ConsumeSpace() ) )
|
|
return hr;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if( m_Ch != '>' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '>' after name for closing entity reference" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
}
|
|
else if( m_Ch == '?' )
|
|
{
|
|
// just skip any xml header tag since not really important after identifying character set
|
|
for( ;; )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if ( m_Ch == '>' )
|
|
return S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XMLAttribute Attributes[ XML_MAX_ATTRIBUTES_PER_ELEMENT ];
|
|
UINT NumAttrs;
|
|
|
|
WCHAR *pEntityRefVal = m_pWritePtr;
|
|
UINT EntityRefLen;
|
|
|
|
NumAttrs = 0;
|
|
|
|
SkipNextAdvance();
|
|
|
|
// Entity tag
|
|
if( FAILED( hr = AdvanceName() ) )
|
|
return hr;
|
|
|
|
EntityRefLen = (UINT)( m_pWritePtr - pEntityRefVal );
|
|
|
|
if( FAILED( hr = ConsumeSpace() ) )
|
|
return hr;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
// read attributes
|
|
while( ( m_Ch != '>' ) && ( m_Ch != '/' ) )
|
|
{
|
|
SkipNextAdvance();
|
|
|
|
if ( NumAttrs >= XML_MAX_ATTRIBUTES_PER_ELEMENT )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Elements may not have more than %d attributes", XML_MAX_ATTRIBUTES_PER_ELEMENT );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
Attributes[ NumAttrs ].strName = m_pWritePtr;
|
|
|
|
// Attribute name
|
|
if( FAILED( hr = AdvanceName() ) )
|
|
return hr;
|
|
|
|
Attributes[ NumAttrs ].NameLen = (UINT)( m_pWritePtr - Attributes[ NumAttrs ].strName );
|
|
|
|
if( FAILED( hr = ConsumeSpace() ) )
|
|
return hr;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if( m_Ch != '=' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '=' character after attribute name" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
if( FAILED( hr = ConsumeSpace() ) )
|
|
return hr;
|
|
|
|
Attributes[ NumAttrs ].strValue = m_pWritePtr;
|
|
|
|
if( FAILED( hr = AdvanceAttrVal() ) )
|
|
return hr;
|
|
|
|
Attributes[ NumAttrs ].ValueLen = (UINT)( m_pWritePtr -
|
|
Attributes[ NumAttrs ].strValue );
|
|
|
|
++NumAttrs;
|
|
|
|
if( FAILED( hr = ConsumeSpace() ) )
|
|
return hr;
|
|
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
}
|
|
|
|
if( m_Ch == '/' )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
if( m_Ch != '>' )
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Expecting '>' after '/' in element tag" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
if( FAILED( m_pISAXCallback->ElementBegin( pEntityRefVal, EntityRefLen,
|
|
Attributes, NumAttrs ) ) )
|
|
return E_ABORT;
|
|
|
|
if( FAILED( m_pISAXCallback->ElementEnd( pEntityRefVal, EntityRefLen ) ) )
|
|
return E_ABORT;
|
|
}
|
|
else
|
|
{
|
|
if( FAILED( m_pISAXCallback->ElementBegin( pEntityRefVal, EntityRefLen,
|
|
Attributes, NumAttrs ) ) )
|
|
return E_ABORT;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::AdvanceCDATA
|
|
// Desc: Read a CDATA section
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::AdvanceCDATA()
|
|
{
|
|
HRESULT hr;
|
|
WORD wStage = 0;
|
|
|
|
if( FAILED( m_pISAXCallback->CDATABegin() ) )
|
|
return E_ABORT;
|
|
|
|
for( ;; )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
*m_pWritePtr = m_Ch;
|
|
m_pWritePtr++;
|
|
|
|
if( ( m_Ch == ']' ) && ( wStage == 0 ) )
|
|
wStage = 1;
|
|
else if( ( m_Ch == ']' ) && ( wStage == 1 ) )
|
|
wStage = 2;
|
|
else if( ( m_Ch == '>' ) && ( wStage == 2 ) )
|
|
{
|
|
m_pWritePtr -= 3;
|
|
break;
|
|
}
|
|
else
|
|
wStage = 0;
|
|
|
|
if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE )
|
|
{
|
|
if( FAILED( m_pISAXCallback->CDATAData( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), TRUE ) ) )
|
|
return E_ABORT;
|
|
m_pWritePtr = m_pWriteBuf;
|
|
}
|
|
}
|
|
|
|
if( FAILED( m_pISAXCallback->CDATAData( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), FALSE ) ) )
|
|
return E_ABORT;
|
|
|
|
m_pWritePtr = m_pWriteBuf;
|
|
|
|
if( FAILED( m_pISAXCallback->CDATAEnd() ) )
|
|
return E_ABORT;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::AdvanceComment
|
|
// Desk: Skips over a comment
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::AdvanceComment()
|
|
{
|
|
HRESULT hr;
|
|
WORD wStage;
|
|
|
|
wStage = 0;
|
|
for( ;; )
|
|
{
|
|
if( FAILED( hr = AdvanceCharacter() ) )
|
|
return hr;
|
|
|
|
if (( m_Ch == '-' ) && ( wStage == 0 ))
|
|
wStage = 1;
|
|
else if (( m_Ch == '-' ) && ( wStage == 1 ))
|
|
wStage = 2;
|
|
else if (( m_Ch == '>' ) && ( wStage == 2 ))
|
|
break;
|
|
else
|
|
wStage = 0;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::RegisterSAXCallbackInterface
|
|
// Desc: Registers callback interface
|
|
//-------------------------------------------------------------------------------------
|
|
VOID XMLParser::RegisterSAXCallbackInterface( ISAXCallback *pISAXCallback )
|
|
{
|
|
m_pISAXCallback = pISAXCallback;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::GetSAXCallbackInterface
|
|
// Desc: Returns current callback interface
|
|
//-------------------------------------------------------------------------------------
|
|
ISAXCallback* XMLParser::GetSAXCallbackInterface()
|
|
{
|
|
return m_pISAXCallback;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::MainParseLoop
|
|
// Desc: Main Loop to Parse Data - source agnostic
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::MainParseLoop()
|
|
{
|
|
BOOL bWhiteSpaceOnly = TRUE;
|
|
HRESULT hr = S_OK;
|
|
|
|
if( FAILED( m_pISAXCallback->StartDocument() ) )
|
|
return E_ABORT;
|
|
|
|
m_pWritePtr = m_pWriteBuf;
|
|
|
|
FillBuffer();
|
|
|
|
if ( *((WCHAR *) m_pReadBuf ) == 0xFEFF )
|
|
{
|
|
m_bUnicode = TRUE;
|
|
m_bReverseBytes = FALSE;
|
|
m_pReadPtr += 2;
|
|
}
|
|
else if ( *((WCHAR *) m_pReadBuf ) == 0xFFFE )
|
|
{
|
|
m_bUnicode = TRUE;
|
|
m_bReverseBytes = TRUE;
|
|
m_pReadPtr += 2;
|
|
}
|
|
else if ( *((WCHAR *) m_pReadBuf ) == 0x003C )
|
|
{
|
|
m_bUnicode = TRUE;
|
|
m_bReverseBytes = FALSE;
|
|
}
|
|
else if ( *((WCHAR *) m_pReadBuf ) == 0x3C00 )
|
|
{
|
|
m_bUnicode = TRUE;
|
|
m_bReverseBytes = TRUE;
|
|
}
|
|
else if ( m_pReadBuf[ 0 ] == 0x3C )
|
|
{
|
|
m_bUnicode = FALSE;
|
|
m_bReverseBytes = FALSE;
|
|
}
|
|
else
|
|
{
|
|
Error( E_INVALID_XML_SYNTAX, "Unrecognized encoding (parser does not support UTF-8 language encodings)" );
|
|
return E_INVALID_XML_SYNTAX;
|
|
}
|
|
|
|
for( ;; )
|
|
{
|
|
if( FAILED( AdvanceCharacter( TRUE ) ) )
|
|
{
|
|
if ( ( (UINT) ( m_pWritePtr - m_pWriteBuf ) != 0 ) && ( !bWhiteSpaceOnly ) )
|
|
{
|
|
if( FAILED( m_pISAXCallback->ElementContent( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), FALSE ) ) )
|
|
return E_ABORT;
|
|
|
|
bWhiteSpaceOnly = TRUE;
|
|
}
|
|
|
|
if( FAILED( m_pISAXCallback->EndDocument() ) )
|
|
return E_ABORT;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
if( m_Ch == '<' )
|
|
{
|
|
if( ( (UINT) ( m_pWritePtr - m_pWriteBuf ) != 0 ) && ( !bWhiteSpaceOnly ) )
|
|
{
|
|
if( FAILED( m_pISAXCallback->ElementContent( m_pWriteBuf, (UINT)( m_pWritePtr - m_pWriteBuf ), FALSE ) ) )
|
|
return E_ABORT;
|
|
|
|
bWhiteSpaceOnly = TRUE;
|
|
}
|
|
|
|
SkipNextAdvance();
|
|
|
|
m_pWritePtr = m_pWriteBuf;
|
|
|
|
if( FAILED( hr = AdvanceElement() ) )
|
|
return hr;
|
|
|
|
m_pWritePtr = m_pWriteBuf;
|
|
}
|
|
else
|
|
{
|
|
if( m_Ch == '&' )
|
|
{
|
|
SkipNextAdvance();
|
|
if( FAILED( hr = ConvertEscape() ) )
|
|
return hr;
|
|
}
|
|
|
|
if( bWhiteSpaceOnly && ( m_Ch != ' ' ) && ( m_Ch != '\n' ) && ( m_Ch != '\r' ) &&
|
|
( m_Ch != '\t' ) )
|
|
{
|
|
bWhiteSpaceOnly = FALSE;
|
|
}
|
|
|
|
*m_pWritePtr = m_Ch;
|
|
m_pWritePtr++;
|
|
|
|
if( m_pWritePtr - m_pWriteBuf >= XML_WRITE_BUFFER_SIZE )
|
|
{
|
|
if( !bWhiteSpaceOnly )
|
|
{
|
|
if( FAILED( m_pISAXCallback->ElementContent( m_pWriteBuf,
|
|
( UINT ) ( m_pWritePtr - m_pWriteBuf ),
|
|
TRUE ) ) )
|
|
{
|
|
return E_ABORT;
|
|
}
|
|
}
|
|
|
|
m_pWritePtr = m_pWriteBuf;
|
|
bWhiteSpaceOnly = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::ParseXMLFile
|
|
// Desc: Builds element data
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::ParseXMLFile( CONST CHAR *strFilename )
|
|
{
|
|
HRESULT hr;
|
|
|
|
if( m_pISAXCallback == NULL )
|
|
return E_NOINTERFACE;
|
|
|
|
m_pISAXCallback->m_LineNum = 1;
|
|
m_pISAXCallback->m_LinePos = 0;
|
|
m_pISAXCallback->m_strFilename = strFilename; // save this off only while we parse the file
|
|
|
|
m_bSkipNextAdvance = FALSE;
|
|
m_pReadPtr = m_pReadBuf;
|
|
|
|
m_pReadBuf[ 0 ] = '\0';
|
|
m_pReadBuf[ 1 ] = '\0';
|
|
|
|
m_pInXMLBuffer = NULL;
|
|
m_uInXMLBufferCharsLeft = 0;
|
|
|
|
WCHAR wchFilename[ 64 ];
|
|
|
|
swprintf_s(wchFilename,64,L"%s",strFilename);
|
|
|
|
m_hFile = CreateFile( wchFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL );
|
|
|
|
if( m_hFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
Error( E_COULD_NOT_OPEN_FILE, "Error opening file" );
|
|
hr = E_COULD_NOT_OPEN_FILE;
|
|
|
|
}
|
|
else
|
|
{
|
|
LARGE_INTEGER iFileSize;
|
|
GetFileSizeEx( m_hFile, &iFileSize );
|
|
m_dwCharsTotal = (DWORD)iFileSize.QuadPart;
|
|
m_dwCharsConsumed = 0;
|
|
hr = MainParseLoop();
|
|
}
|
|
|
|
// Close the file
|
|
if( m_hFile != INVALID_HANDLE_VALUE )
|
|
CloseHandle( m_hFile );
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
|
|
// we no longer own strFilename, so un-set it
|
|
m_pISAXCallback->m_strFilename = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Name: XMLParser::ParseXMLFile
|
|
// Desc: Builds element data
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT XMLParser::ParseXMLBuffer( CONST CHAR *strBuffer, UINT uBufferSize )
|
|
{
|
|
HRESULT hr;
|
|
|
|
if( m_pISAXCallback == NULL )
|
|
return E_NOINTERFACE;
|
|
|
|
m_pISAXCallback->m_LineNum = 1;
|
|
m_pISAXCallback->m_LinePos = 0;
|
|
m_pISAXCallback->m_strFilename = ""; // save this off only while we parse the file
|
|
|
|
m_bSkipNextAdvance = FALSE;
|
|
m_pReadPtr = m_pReadBuf;
|
|
|
|
m_pReadBuf[ 0 ] = '\0';
|
|
m_pReadBuf[ 1 ] = '\0';
|
|
|
|
m_hFile = NULL;
|
|
m_pInXMLBuffer = strBuffer;
|
|
m_uInXMLBufferCharsLeft = uBufferSize;
|
|
m_dwCharsTotal = uBufferSize;
|
|
m_dwCharsConsumed = 0;
|
|
|
|
hr = MainParseLoop();
|
|
|
|
// we no longer own strFilename, so un-set it
|
|
m_pISAXCallback->m_strFilename = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// XMLParser::Error()
|
|
// Logs an error through the callback interface
|
|
//-------------------------------------------------------------------------------------
|
|
#ifdef _Printf_format_string_ // VC++ 2008 and later support this annotation
|
|
VOID XMLParser::Error( HRESULT hErr, _In_z_ _Printf_format_string_ CONST CHAR* strFormat, ... )
|
|
#else
|
|
VOID XMLParser::Error( HRESULT hErr, CONST CHAR* strFormat, ... )
|
|
#endif
|
|
{
|
|
CONST INT MAX_OUTPUT_STR = 160;
|
|
CHAR strBuffer[ MAX_OUTPUT_STR ];
|
|
va_list pArglist;
|
|
va_start( pArglist, strFormat );
|
|
|
|
vsprintf( strBuffer, strFormat, pArglist );
|
|
|
|
m_pISAXCallback->Error( hErr, strBuffer );
|
|
va_end( pArglist );
|
|
}
|
|
|
|
} // namespace ATG
|