2026-03-02 17:39:35 +07:00
// 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.
2026-03-01 12:16:08 +08:00
//-------------------------------------------------------------------------------------
// AtgXmlParser.cpp
2026-03-02 17:39:35 +07:00
//
2026-03-01 12:16:08 +08:00
// 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 ( )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
}
//-------------------------------------------------------------------------------------
// 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 )
{
2026-03-02 17:39:35 +07:00
if ( m_uInXMLBufferCharsLeft > XML_READ_BUFFER_SIZE )
2026-03-01 12:16:08 +08:00
NChars = XML_READ_BUFFER_SIZE ;
else
NChars = m_uInXMLBufferCharsLeft ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
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 ;
2026-03-02 17:39:35 +07:00
__int64 iProgress = m_dwCharsTotal ? ( ( ( __int64 ) m_dwCharsConsumed * 1000 ) / ( __int64 ) m_dwCharsTotal ) : 0 ;
2026-03-01 12:16:08 +08:00
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
2026-03-02 17:39:35 +07:00
// Desc: Skips spaces in the current stream
2026-03-01 12:16:08 +08:00
//-------------------------------------------------------------------------------------
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 ;
2026-03-02 17:39:35 +07:00
}
SkipNextAdvance ( ) ;
2026-03-01 12:16:08 +08:00
return S_OK ;
}
//-------------------------------------------------------------------------------------
// Name: XMLParser::ConvertEscape
2026-03-02 17:39:35 +07:00
// Desc: Copies and converts an escape sequence into m_pWriteBuf
2026-03-01 12:16:08 +08:00
//-------------------------------------------------------------------------------------
HRESULT XMLParser : : ConvertEscape ( )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
HRESULT hr ;
WCHAR wVal = 0 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
2026-03-02 17:39:35 +07:00
// all escape sequences start with &, so ignore the first character
2026-03-01 12:16:08 +08:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
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 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
while ( m_Ch ! = ' ; ' )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
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 ;
2026-03-02 17:39:35 +07:00
}
2026-03-01 12:16:08 +08:00
else
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Expected hex digit as part of &#x escape sequence " ) ;
return E_INVALID_XML_SYNTAX ;
2026-03-01 12:16:08 +08:00
}
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
}
}
else // decimal number
{
while ( m_Ch ! = ' ; ' )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
wVal * = 10 ;
if ( ( m_Ch > = ' 0 ' ) & & ( m_Ch < = ' 9 ' ) )
{
wVal + = m_Ch - ' 0 ' ;
}
else
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Expected decimal digit as part of &# escape sequence " ) ;
2026-03-01 12:16:08 +08:00
return E_INVALID_XML_SYNTAX ;
}
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
}
}
// copy character into the buffer
m_Ch = wVal ;
return S_OK ;
2026-03-02 17:39:35 +07:00
}
2026-03-01 12:16:08 +08:00
// must be an entity reference
WCHAR * pEntityRefVal = m_pWritePtr ;
UINT EntityRefLen ;
SkipNextAdvance ( ) ;
if ( FAILED ( hr = AdvanceName ( ) ) )
return hr ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
EntityRefLen = ( UINT ) ( m_pWritePtr - pEntityRefVal ) ;
m_pWritePtr = pEntityRefVal ;
if ( EntityRefLen = = 0 )
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Expecting entity name after & " ) ;
2026-03-01 12:16:08 +08:00
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
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Unrecognized entity name after & - (should be lt, gt, amp, apos, or quot) " ) ;
2026-03-01 12:16:08 +08:00
return E_INVALID_XML_SYNTAX ; // return false if unrecognized token sequence
}
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' ; ' )
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Expected terminating ; for entity reference " ) ;
2026-03-01 12:16:08 +08:00
return E_INVALID_XML_SYNTAX ; // malformed reference - needs terminating ;
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
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 ! = ' \' ' ) )
2026-03-02 17:39:35 +07:00
{
Error ( E_INVALID_XML_SYNTAX , " Attribute values must be enclosed in quotes " ) ;
2026-03-01 12:16:08 +08:00
return E_INVALID_XML_SYNTAX ;
}
wQuoteChar = m_Ch ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
for ( ; ; )
{
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
else if ( m_Ch = = wQuoteChar )
break ;
2026-03-01 12:16:08 +08:00
else if ( m_Ch = = ' & ' )
{
SkipNextAdvance ( ) ;
if ( FAILED ( hr = ConvertEscape ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
else if ( m_Ch = = ' < ' )
2026-03-01 12:16:08 +08:00
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Illegal character '<' in element tag " ) ;
return E_INVALID_XML_SYNTAX ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
// copy character into the buffer
2026-03-02 17:39:35 +07:00
if ( m_pWritePtr - m_pWriteBuf > = XML_WRITE_BUFFER_SIZE )
2026-03-01 12:16:08 +08:00
{
2026-03-02 17:39:35 +07:00
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 ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
* m_pWritePtr = m_Ch ;
2026-03-02 17:39:35 +07:00
m_pWritePtr + + ;
2026-03-01 12:16:08 +08:00
}
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 ( )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
HRESULT hr ;
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
if ( ( ( m_Ch < ' A ' ) | | ( m_Ch > ' Z ' ) ) & &
( ( m_Ch < ' a ' ) | | ( m_Ch > ' z ' ) ) & &
( m_Ch ! = ' _ ' ) & & ( m_Ch ! = ' : ' ) )
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Names must start with an alphabetic character or _ or : " ) ;
return E_INVALID_XML_SYNTAX ;
2026-03-01 12:16:08 +08:00
}
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 )
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Total element tag size may not be more than %d characters " , XML_WRITE_BUFFER_SIZE ) ;
2026-03-01 12:16:08 +08:00
return E_INVALID_XML_SYNTAX ;
2026-03-02 17:39:35 +07:00
}
2026-03-01 12:16:08 +08:00
* m_pWritePtr = m_Ch ;
m_pWritePtr + + ;
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
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 )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
if ( m_bSkipNextAdvance )
{
m_bSkipNextAdvance = FALSE ;
return S_OK ;
}
// If we hit EOF in the middle of a character,
2026-03-02 17:39:35 +07:00
// it's ok-- we'll just have a corrupt last character
2026-03-01 12:16:08 +08:00
// (the buffer is padded with double NULLs )
if ( ( m_pReadPtr [ 0 ] = = ' \0 ' ) & & ( m_pReadPtr [ 1 ] = = ' \0 ' ) )
{
// Read more from the file
2026-03-02 17:39:35 +07:00
FillBuffer ( ) ;
2026-03-01 12:16:08 +08:00
// We are at EOF if it is still NULL
if ( ( m_pReadPtr [ 0 ] = = ' \0 ' ) & & ( m_pReadPtr [ 1 ] = = ' \0 ' ) )
{
if ( ! bOkToFail )
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Unexpected EOF while parsing XML file " ) ;
2026-03-01 12:16:08 +08:00
return E_INVALID_XML_SYNTAX ;
}
else
{
return E_FAIL ;
}
}
2026-03-02 17:39:35 +07:00
}
2026-03-01 12:16:08 +08:00
if ( m_bUnicode = = FALSE )
{
m_Ch = * ( ( CHAR * ) m_pReadPtr ) ;
m_pReadPtr + + ;
}
else // if( m_bUnicode == TRUE )
{
m_Ch = * ( ( WCHAR * ) m_pReadPtr ) ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( m_bReverseBytes )
{
m_Ch = ( m_Ch < < 8 ) + ( m_Ch > > 8 ) ;
}
2026-03-02 17:39:35 +07:00
m_pReadPtr + = 2 ;
2026-03-01 12:16:08 +08:00
}
if ( m_Ch = = ' \n ' )
{
m_pISAXCallback - > m_LineNum + + ;
m_pISAXCallback - > m_LinePos = 0 ;
}
else if ( m_Ch ! = ' \r ' )
m_pISAXCallback - > m_LinePos + + ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
return S_OK ;
}
//-------------------------------------------------------------------------------------
// Name: XMLParser::AdvanceElement
2026-03-02 17:39:35 +07:00
// Desc: Builds <element> data, calls callback
2026-03-01 12:16:08 +08:00
//-------------------------------------------------------------------------------------
HRESULT XMLParser : : AdvanceElement ( )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
HRESULT hr ;
// write ptr at the beginning of the buffer
m_pWritePtr = m_pWriteBuf ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
// if first character wasn't '<', we wouldn't be here
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
if ( m_Ch = = ' ! ' )
{
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
2026-03-01 12:16:08 +08:00
if ( m_Ch = = ' - ' )
{
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' - ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '-' after '<!-' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceComment ( ) ) )
return hr ;
2026-03-01 12:16:08 +08:00
return S_OK ;
}
2026-03-02 17:39:35 +07:00
if ( m_Ch ! = ' [ ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '<![CDATA[' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' C ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '<![CDATA[' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' D ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '<![CDATA[' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' A ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '<![CDATA[' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' T ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '<![CDATA[' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' A ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '<![CDATA[' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
if ( m_Ch ! = ' [ ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '<![CDATA[' " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCDATA ( ) ) )
2026-03-01 12:16:08 +08:00
return hr ;
}
2026-03-02 17:39:35 +07:00
else if ( m_Ch = = ' / ' )
2026-03-01 12:16:08 +08:00
{
WCHAR * pEntityRefVal = m_pWritePtr ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceName ( ) ) )
2026-03-01 12:16:08 +08:00
return hr ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( m_pISAXCallback - > ElementEnd ( pEntityRefVal ,
2026-03-01 12:16:08 +08:00
( UINT ) ( m_pWritePtr - pEntityRefVal ) ) ) )
return E_ABORT ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = ConsumeSpace ( ) ) )
2026-03-01 12:16:08 +08:00
return hr ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
2026-03-01 12:16:08 +08:00
if ( m_Ch ! = ' > ' )
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '>' after name for closing entity reference " ) ;
return E_INVALID_XML_SYNTAX ;
}
}
2026-03-02 17:39:35 +07:00
else if ( m_Ch = = ' ? ' )
2026-03-01 12:16:08 +08:00
{
// just skip any xml header tag since not really important after identifying character set
for ( ; ; )
{
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
2026-03-01 12:16:08 +08:00
if ( m_Ch = = ' > ' )
return S_OK ;
}
}
else
{
2026-03-02 17:39:35 +07:00
XMLAttribute Attributes [ XML_MAX_ATTRIBUTES_PER_ELEMENT ] ;
2026-03-01 12:16:08 +08:00
UINT NumAttrs ;
WCHAR * pEntityRefVal = m_pWritePtr ;
UINT EntityRefLen ;
NumAttrs = 0 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
SkipNextAdvance ( ) ;
// Entity tag
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceName ( ) ) )
2026-03-01 12:16:08 +08:00
return hr ;
EntityRefLen = ( UINT ) ( m_pWritePtr - pEntityRefVal ) ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = ConsumeSpace ( ) ) )
2026-03-01 12:16:08 +08:00
return hr ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
// read attributes
while ( ( m_Ch ! = ' > ' ) & & ( m_Ch ! = ' / ' ) )
{
SkipNextAdvance ( ) ;
if ( NumAttrs > = XML_MAX_ATTRIBUTES_PER_ELEMENT )
{
2026-03-02 17:39:35 +07:00
Error ( E_INVALID_XML_SYNTAX , " Elements may not have more than %d attributes " , XML_MAX_ATTRIBUTES_PER_ELEMENT ) ;
return E_INVALID_XML_SYNTAX ;
2026-03-01 12:16:08 +08:00
}
Attributes [ NumAttrs ] . strName = m_pWritePtr ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
// Attribute name
if ( FAILED ( hr = AdvanceName ( ) ) )
return hr ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
Attributes [ NumAttrs ] . NameLen = ( UINT ) ( m_pWritePtr - Attributes [ NumAttrs ] . strName ) ;
if ( FAILED ( hr = ConsumeSpace ( ) ) )
return hr ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
2026-03-01 12:16:08 +08:00
2026-03-02 17:39:35 +07:00
if ( m_Ch ! = ' = ' )
2026-03-01 12:16:08 +08:00
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '=' character after attribute name " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = ConsumeSpace ( ) ) )
2026-03-01 12:16:08 +08:00
return hr ;
Attributes [ NumAttrs ] . strValue = m_pWritePtr ;
if ( FAILED ( hr = AdvanceAttrVal ( ) ) )
return hr ;
2026-03-02 17:39:35 +07:00
Attributes [ NumAttrs ] . ValueLen = ( UINT ) ( m_pWritePtr -
2026-03-01 12:16:08 +08:00
Attributes [ NumAttrs ] . strValue ) ;
+ + NumAttrs ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( FAILED ( hr = ConsumeSpace ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
}
if ( m_Ch = = ' / ' )
{
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
2026-03-02 17:39:35 +07:00
return hr ;
2026-03-01 12:16:08 +08:00
if ( m_Ch ! = ' > ' )
{
Error ( E_INVALID_XML_SYNTAX , " Expecting '>' after '/' in element tag " ) ;
return E_INVALID_XML_SYNTAX ;
}
2026-03-02 17:39:35 +07:00
if ( FAILED ( m_pISAXCallback - > ElementBegin ( pEntityRefVal , EntityRefLen ,
2026-03-01 12:16:08 +08:00
Attributes , NumAttrs ) ) )
return E_ABORT ;
if ( FAILED ( m_pISAXCallback - > ElementEnd ( pEntityRefVal , EntityRefLen ) ) )
return E_ABORT ;
}
else
{
2026-03-02 17:39:35 +07:00
if ( FAILED ( m_pISAXCallback - > ElementBegin ( pEntityRefVal , EntityRefLen ,
2026-03-01 12:16:08 +08:00
Attributes , NumAttrs ) ) )
return E_ABORT ;
}
}
return S_OK ;
}
//-------------------------------------------------------------------------------------
// Name: XMLParser::AdvanceCDATA
// Desc: Read a CDATA section
//-------------------------------------------------------------------------------------
HRESULT XMLParser : : AdvanceCDATA ( )
{
HRESULT hr ;
WORD wStage = 0 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( FAILED ( m_pISAXCallback - > CDATABegin ( ) ) )
return E_ABORT ;
for ( ; ; )
{
if ( FAILED ( hr = AdvanceCharacter ( ) ) )
return hr ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
* m_pWritePtr = m_Ch ;
m_pWritePtr + + ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
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 ;
2026-03-02 17:39:35 +07:00
}
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
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 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
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 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( ( m_Ch = = ' - ' ) & & ( wStage = = 0 ) )
wStage = 1 ;
else if ( ( m_Ch = = ' - ' ) & & ( wStage = = 1 ) )
wStage = 2 ;
2026-03-02 17:39:35 +07:00
else if ( ( m_Ch = = ' > ' ) & & ( wStage = = 2 ) )
break ;
2026-03-01 12:16:08 +08:00
else
2026-03-02 17:39:35 +07:00
wStage = 0 ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
return S_OK ;
}
//-------------------------------------------------------------------------------------
// Name: XMLParser::RegisterSAXCallbackInterface
2026-03-02 17:39:35 +07:00
// Desc: Registers callback interface
2026-03-01 12:16:08 +08:00
//-------------------------------------------------------------------------------------
VOID XMLParser : : RegisterSAXCallbackInterface ( ISAXCallback * pISAXCallback )
{
m_pISAXCallback = pISAXCallback ;
}
//-------------------------------------------------------------------------------------
// Name: XMLParser::GetSAXCallbackInterface
2026-03-02 17:39:35 +07:00
// Desc: Returns current callback interface
2026-03-01 12:16:08 +08:00
//-------------------------------------------------------------------------------------
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 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
m_pWritePtr = m_pWriteBuf ;
FillBuffer ( ) ;
if ( * ( ( WCHAR * ) m_pReadBuf ) = = 0xFEFF )
{
m_bUnicode = TRUE ;
m_bReverseBytes = FALSE ;
m_pReadPtr + = 2 ;
}
2026-03-02 17:39:35 +07:00
else if ( * ( ( WCHAR * ) m_pReadBuf ) = = 0xFFFE )
2026-03-01 12:16:08 +08:00
{
m_bUnicode = TRUE ;
m_bReverseBytes = TRUE ;
2026-03-02 17:39:35 +07:00
m_pReadPtr + = 2 ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
else if ( * ( ( WCHAR * ) m_pReadBuf ) = = 0x003C )
2026-03-01 12:16:08 +08:00
{
2026-03-02 17:39:35 +07:00
m_bUnicode = TRUE ;
2026-03-01 12:16:08 +08:00
m_bReverseBytes = FALSE ;
}
2026-03-02 17:39:35 +07:00
else if ( * ( ( WCHAR * ) m_pReadBuf ) = = 0x3C00 )
2026-03-01 12:16:08 +08:00
{
m_bUnicode = TRUE ;
2026-03-02 17:39:35 +07:00
m_bReverseBytes = TRUE ;
2026-03-01 12:16:08 +08:00
}
else if ( m_pReadBuf [ 0 ] = = 0x3C )
{
2026-03-02 17:39:35 +07:00
m_bUnicode = FALSE ;
m_bReverseBytes = FALSE ;
2026-03-01 12:16:08 +08:00
}
else
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
Error ( E_INVALID_XML_SYNTAX , " Unrecognized encoding (parser does not support UTF-8 language encodings) " ) ;
2026-03-02 17:39:35 +07:00
return E_INVALID_XML_SYNTAX ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
for ( ; ; )
{
if ( FAILED ( AdvanceCharacter ( TRUE ) ) )
{
if ( ( ( UINT ) ( m_pWritePtr - m_pWriteBuf ) ! = 0 ) & & ( ! bWhiteSpaceOnly ) )
2026-03-02 17:39:35 +07:00
{
if ( FAILED ( m_pISAXCallback - > ElementContent ( m_pWriteBuf , ( UINT ) ( m_pWritePtr - m_pWriteBuf ) , FALSE ) ) )
return E_ABORT ;
2026-03-01 12:16:08 +08:00
bWhiteSpaceOnly = TRUE ;
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( FAILED ( m_pISAXCallback - > EndDocument ( ) ) )
return E_ABORT ;
2026-03-02 17:39:35 +07:00
return S_OK ;
2026-03-01 12:16:08 +08:00
}
if ( m_Ch = = ' < ' )
{
if ( ( ( UINT ) ( m_pWritePtr - m_pWriteBuf ) ! = 0 ) & & ( ! bWhiteSpaceOnly ) )
2026-03-02 17:39:35 +07:00
{
if ( FAILED ( m_pISAXCallback - > ElementContent ( m_pWriteBuf , ( UINT ) ( m_pWritePtr - m_pWriteBuf ) , FALSE ) ) )
return E_ABORT ;
2026-03-01 12:16:08 +08:00
bWhiteSpaceOnly = TRUE ;
}
SkipNextAdvance ( ) ;
m_pWritePtr = m_pWriteBuf ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = AdvanceElement ( ) ) )
return hr ;
2026-03-01 12:16:08 +08:00
m_pWritePtr = m_pWriteBuf ;
}
2026-03-02 17:39:35 +07:00
else
2026-03-01 12:16:08 +08:00
{
if ( m_Ch = = ' & ' )
{
SkipNextAdvance ( ) ;
2026-03-02 17:39:35 +07:00
if ( FAILED ( hr = ConvertEscape ( ) ) )
return hr ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:39:35 +07:00
if ( bWhiteSpaceOnly & & ( m_Ch ! = ' ' ) & & ( m_Ch ! = ' \n ' ) & & ( m_Ch ! = ' \r ' ) & &
( m_Ch ! = ' \t ' ) )
2026-03-01 12:16:08 +08:00
{
bWhiteSpaceOnly = FALSE ;
}
* m_pWritePtr = m_Ch ;
m_pWritePtr + + ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( m_pWritePtr - m_pWriteBuf > = XML_WRITE_BUFFER_SIZE )
{
if ( ! bWhiteSpaceOnly )
2026-03-02 17:39:35 +07:00
{
if ( FAILED ( m_pISAXCallback - > ElementContent ( m_pWriteBuf ,
( UINT ) ( m_pWritePtr - m_pWriteBuf ) ,
2026-03-01 12:16:08 +08:00
TRUE ) ) )
{
2026-03-02 17:39:35 +07:00
return E_ABORT ;
2026-03-01 12:16:08 +08:00
}
}
m_pWritePtr = m_pWriteBuf ;
bWhiteSpaceOnly = TRUE ;
}
2026-03-02 17:39:35 +07:00
}
2026-03-01 12:16:08 +08:00
}
}
//-------------------------------------------------------------------------------------
// Name: XMLParser::ParseXMLFile
// Desc: Builds element data
//-------------------------------------------------------------------------------------
HRESULT XMLParser : : ParseXMLFile ( CONST CHAR * strFilename )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
HRESULT hr ;
if ( m_pISAXCallback = = NULL )
return E_NOINTERFACE ;
2026-03-02 17:39:35 +07:00
m_pISAXCallback - > m_LineNum = 1 ;
2026-03-01 12:16:08 +08:00
m_pISAXCallback - > m_LinePos = 0 ;
m_pISAXCallback - > m_strFilename = strFilename ; // save this off only while we parse the file
m_bSkipNextAdvance = FALSE ;
2026-03-02 17:39:35 +07:00
m_pReadPtr = m_pReadBuf ;
2026-03-01 12:16:08 +08:00
m_pReadBuf [ 0 ] = ' \0 ' ;
2026-03-02 17:39:35 +07:00
m_pReadBuf [ 1 ] = ' \0 ' ;
2026-03-01 12:16:08 +08:00
m_pInXMLBuffer = NULL ;
m_uInXMLBufferCharsLeft = 0 ;
2026-03-02 17:39:35 +07:00
m_hFile = CreateFile ( strFilename , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_FLAG_SEQUENTIAL_SCAN , NULL ) ;
2026-03-01 12:16:08 +08:00
if ( m_hFile = = INVALID_HANDLE_VALUE )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
Error ( E_COULD_NOT_OPEN_FILE , " Error opening file " ) ;
hr = E_COULD_NOT_OPEN_FILE ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
}
else
{
LARGE_INTEGER iFileSize ;
GetFileSizeEx ( m_hFile , & iFileSize ) ;
m_dwCharsTotal = ( DWORD ) iFileSize . QuadPart ;
m_dwCharsConsumed = 0 ;
hr = MainParseLoop ( ) ;
}
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
// 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
2026-03-02 17:39:35 +07:00
m_pISAXCallback - > m_strFilename = NULL ;
2026-03-01 12:16:08 +08:00
return hr ;
}
//-------------------------------------------------------------------------------------
// Name: XMLParser::ParseXMLFile
// Desc: Builds element data
//-------------------------------------------------------------------------------------
HRESULT XMLParser : : ParseXMLBuffer ( CONST CHAR * strBuffer , UINT uBufferSize )
2026-03-02 17:39:35 +07:00
{
2026-03-01 12:16:08 +08:00
HRESULT hr ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
if ( m_pISAXCallback = = NULL )
return E_NOINTERFACE ;
2026-03-02 17:39:35 +07:00
m_pISAXCallback - > m_LineNum = 1 ;
2026-03-01 12:16:08 +08:00
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 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
m_pReadBuf [ 0 ] = ' \0 ' ;
2026-03-02 17:39:35 +07:00
m_pReadBuf [ 1 ] = ' \0 ' ;
2026-03-01 12:16:08 +08:00
m_hFile = NULL ;
m_pInXMLBuffer = strBuffer ;
m_uInXMLBufferCharsLeft = uBufferSize ;
m_dwCharsTotal = uBufferSize ;
m_dwCharsConsumed = 0 ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
hr = MainParseLoop ( ) ;
// we no longer own strFilename, so un-set it
2026-03-02 17:39:35 +07:00
m_pISAXCallback - > m_strFilename = NULL ;
2026-03-01 12:16:08 +08:00
return hr ;
}
//-------------------------------------------------------------------------------------
2026-03-02 17:39:35 +07:00
// XMLParser::Error()
2026-03-01 12:16:08 +08:00
// 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 ) ;
2026-03-02 17:39:35 +07:00
2026-03-01 12:16:08 +08:00
m_pISAXCallback - > Error ( hErr , strBuffer ) ;
va_end ( pArglist ) ;
}
} // namespace ATG