/* * This is a part of the BugTrap package. * Copyright (c) 2005-2009 IntelleSoft. * All rights reserved. * * Description: XML parser. * Author: Maksim Pyatkovskiy. * * This source code is only intended as a supplement to the * BugTrap package reference and related electronic documentation * provided with the product. See these sources for detailed * information regarding the BugTrap package. */ #include "StdAfx.h" #include "XmlReader.h" #include "BugTrapUtils.h" #include "FileStream.h" #ifdef _DEBUG #define new DEBUG_NEW #endif static const TCHAR g_pszXmlInternalError [] = _T("Internal error"); static const TCHAR g_pszXmlInputError [] = _T("Input error"); static const TCHAR g_pszXmlErrorOutOfMemory [] = _T("Out of memory"); static const TCHAR g_pszXmlErrorInvalidClosingElement [] = _T("Invalid closing element"); static const TCHAR g_pszXmlErrorUnexpectedChars [] = _T("Unexpected characters"); static const TCHAR g_pszXmlErrorUnexpectedToken [] = _T("Unexpected token"); static const TCHAR g_pszXmlErrorUnexpectedElement [] = _T("Unexpected element"); static const TCHAR g_pszXmlErrorUnexpectedEndOfElement [] = _T("Unexpected end of element"); static const TCHAR g_pszXmlErrorUnexpectedEndOfStream [] = _T("Unexpected end of stream"); static const TCHAR g_pszXmlErrorInvalidNumber [] = _T("Invalid number"); static const TCHAR g_pszXmlErrorUnuspportedUrlScheme [] = _T("Unuspported URL scheme"); static const TCHAR g_pszXmlErrorInvalidUrl [] = _T("Invalid URL"); static const TCHAR g_pszXmlErrorInvalidEntity [] = _T("Invalid entity"); static const TCHAR g_pszXmlErrorCantOpenExternalResource [] = _T("Can't open external resource"); /// Map of standard entities and their values. CHash CXmlReader::m_mapStdEntities; /// XML search table. CXmlReader::CXmlSearchParams CXmlReader::CXmlParser::m_arrInitialXmlSearchParams[] = { #define XML_TEXT_PARAM_POS 0 CXmlSearchParams(_T(""), &CXmlReader::CXmlParser::XmlTextHandler), #define XML_ELEMENT_PARAM_POS 1 CXmlSearchParams(_T("<"), &CXmlReader::CXmlParser::XmlElementHandler), #define XML_PROCINSTR_PARAM_POS 2 CXmlSearchParams(_T(""), &CXmlReader::CXmlParser::DtdCondtionEndHandler), #define DTD_COND_PARAM_POS 5 CXmlSearchParams(_T("')); } } void CXmlReader::Close(void) { ReleaseInputStream(); m_pszErrorMessage = NULL; m_mapXmlEntities.DeleteAll(); m_mapDtdEntities.DeleteAll(); m_arrOpenElements.DeleteAll(); } /** * @param pszUrl - URL. * @return true if XML document has been located successfully. */ bool CXmlReader::Open(PCTSTR pszUrl) { CInputStream* pInputStream = m_XmlParser.CreateInputStream(pszUrl); if (pInputStream == NULL) { m_pszErrorMessage = m_XmlParser.GetErrorMessage(); return false; } SetInputStream(pInputStream); m_bReleaseInputStream = true; m_pszErrorMessage = NULL; return true; } /** * @param pInputStream - input stream. */ void CXmlReader::SetInputStream(CInputStream* pInputStream) { Close(); if (pInputStream != NULL) { m_DecStream.SetInputStream(pInputStream); m_DecStream.CheckEncoding(TXTENC_UTF8); m_XmlInputStream.SetInputStream(&m_DecStream); } } /** * @param pInputStream - input stream. */ void CXmlReader::CXmlInputStream::SetInputStream(CCharInputStream* pInputStream) { m_pInputStream = pInputStream; m_nBackBufferReadPos = 0; m_nBackBufferWritePos = 0; } /** * @param rXmlNode - info about current node is stored in this variable. * @param rSearchTable - search table. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ProcessNode(CXmlNode& rXmlNode, CXmlSearchTable& rSearchTable, PVOID pParam) { if (rSearchTable.m_pfnPrefetchedHandler != NULL) { rXmlNode.Reset(); FNodeHandler pfnHandler = rSearchTable.m_pfnPrefetchedHandler; rSearchTable.m_pfnPrefetchedHandler = NULL; return (this->*pfnHandler)(rXmlNode, pParam); } CXmlSearchParams* arrSearchParams = rSearchTable.m_arrSearchParams; size_t nNumParams = rSearchTable.m_nNumParams; for (size_t nParamNum = 0; nParamNum < nNumParams; ++nParamNum) arrSearchParams[nParamNum].m_bActive = true; size_t nSequencePos = 0, nDefaultParamNum = MAXSIZE_T, nDefaultSequenceLength = 0, nLongestParamNum = MAXSIZE_T, nLongestSequenceLength = 0; for (;;) { TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, false); if (nCharSize == MAXSIZE_T) return XMLR_ERROR; else if (nCharSize == 0) { if (nSequencePos == 0 && IsEndOfDocument()) return XMLR_EOF; m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; return XMLR_ERROR; } bool bNotEmptyCriteria = false; for (size_t nParamNum = 0; nParamNum < nNumParams; ++nParamNum) { CXmlSearchParams* pSearchParams = arrSearchParams + nParamNum; if (pSearchParams->m_bActive) { if (pSearchParams->m_pszSequence[nSequencePos] == *arrChar) { _ASSERTE(nCharSize == 1); bNotEmptyCriteria = true; nLongestParamNum = nParamNum; nLongestSequenceLength = nSequencePos; } else { pSearchParams->m_bActive = false; if (pSearchParams->m_pszSequence[nSequencePos] == _T('\0')) { nDefaultParamNum = nParamNum; nDefaultSequenceLength = nSequencePos; } } } } if (! bNotEmptyCriteria) { if (nLongestParamNum != MAXSIZE_T) { size_t nRestoreLength = 1 + nLongestSequenceLength - nDefaultSequenceLength; CXmlSearchParams* pSearchParams = arrSearchParams + nLongestParamNum; PrepareBackBuffer(nRestoreLength + nCharSize); UnsafePutCharBack(arrChar, nCharSize); UnsafePutCharsBack(pSearchParams->m_pszSequence + nDefaultSequenceLength, nRestoreLength); } else PutCharBack(arrChar, nCharSize); if (nDefaultParamNum != MAXSIZE_T) { CXmlSearchParams* pSearchParams = arrSearchParams + nDefaultParamNum; FNodeHandler pfnHandler = pSearchParams->m_pfnHandler; _ASSERTE(pfnHandler != NULL); DWORD dwAdjacentMode = pSearchParams->m_dwAdjacentMode; if (rSearchTable.m_dwAdjacentMode == AM_NONE) { rXmlNode.Reset(); rSearchTable.m_dwAdjacentMode = dwAdjacentMode; return (this->*pfnHandler)(rXmlNode, pParam); } else { if ((rSearchTable.m_dwAdjacentMode & dwAdjacentMode) != 0) { return (this->*pfnHandler)(rXmlNode, pParam); } else { rSearchTable.m_pfnPrefetchedHandler = pfnHandler; rSearchTable.m_dwAdjacentMode = dwAdjacentMode; return XMLR_EOS; } } } } else { ++nSequencePos; continue; } m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } } /** * @param arrChar - character data. * @return number of characters in one symbol. */ size_t CXmlReader::CXmlParser::ReadNonSpaceChar(TCHAR arrChar[2]) { for (;;) { size_t nCharSize = ReadChar(arrChar, true); if (nCharSize > 0 && nCharSize != MAXSIZE_T) { _ASSERTE(nCharSize < 2); WORD arrCharType[2]; #ifdef _UNICODE GetStringTypeW(CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #else GetStringTypeA(LOCALE_USER_DEFAULT, CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #endif if (*arrCharType & C1_SPACE) continue; } return nCharSize; } } /** * @param bRequired - true if space characters are required. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::SkipSpaces(bool bRequired) { bool bEmpty = true; for (;;) { TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; _ASSERTE(nCharSize < 2); WORD arrCharType[2]; #ifdef _UNICODE GetStringTypeW(CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #else GetStringTypeA(LOCALE_USER_DEFAULT, CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #endif if ((*arrCharType & C1_SPACE) == 0) { if (bEmpty && bRequired) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } else { PutCharBack(arrChar, nCharSize); return XMLR_CONTINUE; } } bEmpty = false; } } /** * @param chValue - output character value. * @return true if buffer is not empty. */ bool CXmlReader::CXmlInputStream::ReadCharFromBackBuffer(TCHAR& chValue) { if (IsBackBufferEmpty()) return false; chValue = m_pBackBuffer[m_nBackBufferReadPos]; m_nBackBufferReadPos = (m_nBackBufferReadPos + 1) % m_nBackBufferSize; return true; } /** * @param arrChar - character data. * @return number of characters in one symbol. */ size_t CXmlReader::CXmlInputStream::ReadChar(TCHAR arrChar[2]) { size_t nCharSize; if (ReadCharFromBackBuffer(arrChar[0])) { #ifdef _UNICODE if (IsUnicodeLeadChar((const BYTE*)arrChar)) #else if (IsDBCSLeadByte(*arrChar)) #endif { if (! ReadCharFromBackBuffer(arrChar[1])) { _ASSERT(FALSE); nCharSize = MAXSIZE_T; } else nCharSize = 2; } else nCharSize = 1; } else { _ASSERTE(m_pInputStream != NULL); nCharSize = m_pInputStream->ReadChar(arrChar); } return nCharSize; } /** * @param arrChar - character data. * @param bRequired - true if character is required. * @return number of characters in one symbol. */ size_t CXmlReader::CXmlParser::ReadChar(TCHAR arrChar[2], bool bRequired) { size_t nCharSize = ReadChar(arrChar); if (nCharSize == MAXSIZE_T) { m_pszErrorMessage = g_pszXmlInputError; } else if (nCharSize == 0 && bRequired) { m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; nCharSize = MAXSIZE_T; } return nCharSize; } /** * Specifies number of characters to reserve space for. * @param nNumChars - number of characters to reserve space for. */ void CXmlReader::CXmlInputStream::PrepareBackBuffer(size_t nNumChars) { size_t nCharsUsed = GetBackBufferLength(); if (nCharsUsed + nNumChars >= m_nBackBufferSize) { size_t nNewBufferSize = (m_nBackBufferSize + nNumChars) * 2; PTCHAR pBackBuffer = new TCHAR[nNewBufferSize]; if (pBackBuffer == NULL) RaiseException(STATUS_NO_MEMORY, 0, 0, NULL); CopyMemory(pBackBuffer, m_pBackBuffer + m_nBackBufferReadPos, nCharsUsed * sizeof(TCHAR)); delete[] m_pBackBuffer; m_pBackBuffer = pBackBuffer; m_nBackBufferSize = nNewBufferSize; m_nBackBufferReadPos = 0; m_nBackBufferWritePos = nCharsUsed; } } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::XmlTextHandler(CXmlNode& rXmlNode, PVOID /*pParam*/) { _ASSERTE( rXmlNode.m_eNodeType == CXmlNode::XNT_UNDEFINED || rXmlNode.m_eNodeType == CXmlNode::XNT_TEXT); if (m_eParserState == PS_XML_DOCUMENT) rXmlNode.m_eNodeType = CXmlNode::XNT_TEXT; return ReadText(rXmlNode.m_strNodeValue, _T("<"), false); } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::InvalidTokenHandler(CXmlNode& /*rXmlNode*/, PVOID /*pParam*/) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::DtdTextHandler(CXmlNode& rXmlNode, PVOID /*pParam*/) { _ASSERTE(rXmlNode.m_eNodeType == CXmlNode::XNT_UNDEFINED); return ReadText(rXmlNode.m_strNodeValue, _T("<]"), false); } /** * @return entity character. */ TCHAR CXmlReader::CXmlParser::GetEntityChar(void) const { switch (m_eParserState) { case PS_XML_DOCUMENT: return _T('&'); case PS_DTD_DOCUMENT: case PS_EMBEDDED_DTD: return _T('%'); default: return _T('\0'); } } /** * @return entities map. */ const CHash* CXmlReader::CXmlParser::GetEntities(void) const { switch (m_eParserState) { case PS_XML_DOCUMENT: return &m_rReader.m_mapXmlEntities; case PS_DTD_DOCUMENT: case PS_EMBEDDED_DTD: return &m_rReader.m_mapDtdEntities; default: return NULL; } } /** * @return entities map. */ CHash* CXmlReader::CXmlParser::GetEntities(void) { switch (m_eParserState) { case PS_XML_DOCUMENT: return &m_rReader.m_mapXmlEntities; case PS_DTD_DOCUMENT: case PS_EMBEDDED_DTD: return &m_rReader.m_mapDtdEntities; default: return NULL; } } /** * @param pOutputStream - output stream. * @param pszTerminators - list of text terminators. * @param bInAttribute - true when reading attribute value. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadTextEx(CStrStream* pOutputStream, PCTSTR pszTerminators, bool bInAttribute) { bool bEndOfDocument, bIgnoreText; if (! bInAttribute) { if (m_eParserState == PS_XML_UNDEFINED) m_eParserState = PS_XML_PROLOGUE; else if (m_eParserState == PS_DTD_UNDEFINED) m_eParserState = PS_DTD_DOCUMENT; bEndOfDocument = IsEndOfDocument(); bIgnoreText = m_eParserState != PS_XML_DOCUMENT; } else { bEndOfDocument = false; bIgnoreText = false; } TCHAR chLastLn = _T('\0'); TCHAR chEntity = GetEntityChar(); size_t nSkipChars = 0; XML_RESULT eResult; for (;;) { TCHAR arrChar[2]; WORD arrCharType[2]; size_t nCharSize = ReadChar(arrChar, false); if (nCharSize == 0) { if (! bEndOfDocument) { m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; return XMLR_ERROR; } return XMLR_EOF; } if (nCharSize == MAXSIZE_T) return XMLR_ERROR; if (nSkipChars == 0) { if (_tcschr(pszTerminators, *arrChar)) { PutCharBack(arrChar, nCharSize); return ((m_rReader.m_dwContentFilter & XCF_CDATA) != 0 ? XMLR_CONTINUE : XMLR_EOS); } else if (*arrChar == chEntity) { eResult = ReadEntity(nSkipChars); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; continue; } } else --nSkipChars; #ifdef _UNICODE GetStringTypeW(CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #else GetStringTypeA(LOCALE_USER_DEFAULT, CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #endif if (*arrCharType & C1_SPACE) { if (pOutputStream != NULL && ! bIgnoreText) { if (*arrChar == _T('\r') || *arrChar == _T('\n')) { _ASSERTE(nCharSize == 1); bool bSkipNextChar = chLastLn && *arrChar != chLastLn; chLastLn = *arrChar; if (bSkipNextChar) continue; else *arrChar = _T('\n'); } else chLastLn = _T('\0'); PutCharToStream(*pOutputStream, arrChar, nCharSize); } } else { if (bIgnoreText) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } if (pOutputStream != NULL) { chLastLn = _T('\0'); PutCharToStream(*pOutputStream, arrChar, nCharSize); } } } } /** * @param nValueLength - value length. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadNumericEntity(size_t& nValueLength) { nValueLength = 0; TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; XML_RESULT eResult; DWORD dwUnicodeChar = 0; if (*arrChar == _T('x') || *arrChar == _T('X')) { eResult = ReadHexNumber(dwUnicodeChar); } else { PutCharBack(arrChar, nCharSize); eResult = ReadDecNumber(dwUnicodeChar); } if (eResult != XMLR_CONTINUE) return XMLR_ERROR; nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T(';')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } if (dwUnicodeChar == 0) { m_pszErrorMessage = g_pszXmlErrorInvalidNumber; return XMLR_ERROR; } WCHAR arrCharW[2]; if (dwUnicodeChar >= 0x10000) { dwUnicodeChar -= 0x10000; arrCharW[0] = (WCHAR)(HIGH_SURROGATE_START + ((dwUnicodeChar >> 10) & (HIGH_SURROGATE_END - HIGH_SURROGATE_START))); arrCharW[1] = (WCHAR)(LOW_SURROGATE_START + (dwUnicodeChar & (LOW_SURROGATE_END - LOW_SURROGATE_START))); nCharSize = 2; } else { arrCharW[0] = (WCHAR)dwUnicodeChar; nCharSize = 1; } #ifdef _UNICODE PutCharBack(arrCharW, nCharSize); #else CHAR arrCharA[2]; nCharSize = WideCharToMultiByte(CP_ACP, 0, arrCharW, (int)nCharSize, arrCharA, countof(arrCharA), NULL, NULL); PutCharBack(arrCharA, nCharSize); #endif nValueLength += nCharSize; return XMLR_CONTINUE; } /** * @param nValueLength - value length. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadNamedEntity(size_t& nValueLength) { nValueLength = 0; CStrStream strEntityName(32); XML_RESULT eResult = ReadName(strEntityName); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T(';')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } TCHAR chValue; CHash* pMapEntities = GetEntities(); _ASSERTE(pMapEntities != NULL); const CStrStream* pstrEntityValue = pMapEntities != NULL ? pMapEntities->Lookup(strEntityName) : NULL; if (pstrEntityValue != NULL) { PutCharsBack(*pstrEntityValue); } else if (m_mapStdEntities.Lookup(strEntityName, chValue)) { PutCharBack(chValue); nValueLength = 1; } else { m_pszErrorMessage = g_pszXmlErrorInvalidEntity; return XMLR_ERROR; } return XMLR_CONTINUE; } /** * @param nValueLength - value length. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadEntity(size_t& nValueLength) { nValueLength = 0; TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar == _T('#')) { return ReadNumericEntity(nValueLength); } else { PutCharBack(arrChar, nCharSize); return ReadNamedEntity(nValueLength); } } /** * @param dwNumber - numeric value. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadDecNumber(DWORD& dwNumber) { dwNumber = 0; for (;;) { TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar >= _T('0') && *arrChar <= _T('9')) { dwNumber *= 10; dwNumber += *arrChar - _T('0'); } else { PutCharBack(arrChar, nCharSize); return XMLR_CONTINUE; } } } /** * @param dwNumber - numeric value. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadHexNumber(DWORD& dwNumber) { dwNumber = 0; for (;;) { TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar >= _T('0') && *arrChar <= _T('9')) { dwNumber *= 16; dwNumber += *arrChar - _T('0'); } else if (*arrChar >= _T('A') && *arrChar <= _T('Z')) { dwNumber *= 16; dwNumber += *arrChar - _T('A') + 10; } else if (*arrChar >= _T('a') && *arrChar <= _T('z')) { dwNumber *= 16; dwNumber += *arrChar - _T('a') + 10; } else { PutCharBack(arrChar, nCharSize); return XMLR_CONTINUE; } } } /** * @param pOutputStream - pointer to the output stream or @a NULL. * @param pszTerminator - terminator sequence. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadUntilEx(CStrStream* pOutputStream, PCTSTR pszTerminator) { PCTSTR pszTemp = pszTerminator; while (*pszTemp) { TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; _ASSERTE(nCharSize <= 2); if (arrChar[0] == pszTemp[0] && (nCharSize == 1 || arrChar[1] == pszTemp[1])) { pszTemp += nCharSize; continue; } if (pOutputStream != NULL) { size_t nNumChars = pszTemp - pszTerminator; PutCharsToStream(*pOutputStream, pszTerminator, nNumChars); PutCharToStream(*pOutputStream, arrChar, nCharSize); } pszTemp = pszTerminator; } return XMLR_CONTINUE; } /** * @param pOutputStream - output stream. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadNameEx(CStrStream* pOutputStream) { size_t nCharPos = 0; for (;;) { TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; _ASSERTE(nCharSize <= 2); WORD arrCharType[2]; #ifdef _UNICODE GetStringTypeW(CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #else GetStringTypeA(LOCALE_USER_DEFAULT, CT_CTYPE1, arrChar, (int)nCharSize, arrCharType); #endif if (nCharPos == 0 ? (*arrCharType & C1_ALPHA) || *arrChar == _T('_') || *arrChar == _T(':') : (*arrCharType & (C1_ALPHA | C1_DIGIT)) || *arrChar == _T('.') || *arrChar == _T('-') || *arrChar == _T('_') || *arrChar == _T(':') ) { if (pOutputStream != NULL) PutCharToStream(*pOutputStream, arrChar, nCharSize); } else if (nCharPos > 0) { PutCharBack(arrChar, nCharSize); return XMLR_CONTINUE; } else { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } ++nCharPos; } } /** * @param pszName - attribute name. * @return attribute value. */ PCTSTR CXmlReader::CAttributesList::CaselessGetAt(PCTSTR pszName) const { POSITION posAttr = GetStartPosition(); while (posAttr != NULL) { if (_tcsicmp(GetNameAt(posAttr), pszName) == 0) return GetValueAt(posAttr); posAttr = GetNextPosition(posAttr); } return NULL; } /** * @param rXmlNode - info about current node is stored in this variable. * @param eTagType - type of tag. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::TagHandler(CXmlNode& rXmlNode, TAG_TYPE eTagType) { _ASSERTE(rXmlNode.m_eNodeType == CXmlNode::XNT_UNDEFINED); XML_RESULT eResult; TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar == _T('/')) { if (m_eParserState != PS_XML_DOCUMENT) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } if (eTagType != TT_ELEMENT) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } rXmlNode.m_eNodeType = CXmlNode::XNT_ELEMENT_END; } else { switch (eTagType) { case TT_ELEMENT: if (m_eParserState != PS_XML_UNDEFINED && m_eParserState != PS_XML_PROLOGUE && m_eParserState != PS_XML_DOCUMENT) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } rXmlNode.m_eNodeType = CXmlNode::XNT_ELEMENT_BEGIN; break; case TT_PROCINSTR: if (m_eParserState != PS_XML_UNDEFINED && m_eParserState != PS_XML_PROLOGUE && m_eParserState != PS_XML_DOCUMENT && m_eParserState != PS_XML_EPILOGUE && m_eParserState != PS_DTD_UNDEFINED && m_eParserState != PS_DTD_DOCUMENT && m_eParserState != PS_EMBEDDED_DTD) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } rXmlNode.m_eNodeType = CXmlNode::XNT_PROCINSTR; break; default: _ASSERT(FALSE); m_pszErrorMessage = g_pszXmlInternalError; return XMLR_ERROR; } PutCharBack(arrChar, nCharSize); } eResult = ReadName(rXmlNode.m_strNodeName); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; for (;;) { nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; CArray& arrOpenElements = m_rReader.m_arrOpenElements; switch (eTagType) { case TT_ELEMENT: if (*arrChar == _T('/')) { if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } rXmlNode.m_eNodeType = CXmlNode::XNT_ELEMENT; nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('>')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } if (arrOpenElements.IsEmpty()) m_eParserState = PS_XML_EPILOGUE; else m_eParserState = PS_XML_DOCUMENT; return XMLR_EOS; } else if (*arrChar == _T('>')) { if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { size_t nLastElement = arrOpenElements.GetCount() - 1; if (nLastElement == MAXSIZE_T || _tcscmp(arrOpenElements.GetAt(nLastElement), rXmlNode.m_strNodeName) != 0) { m_pszErrorMessage = g_pszXmlErrorInvalidClosingElement; return XMLR_ERROR; } arrOpenElements.DeleteItem(nLastElement); _ASSERTE(m_eParserState == PS_XML_DOCUMENT); if (nLastElement == 0) m_eParserState = PS_XML_EPILOGUE; } else { arrOpenElements.AddItem(rXmlNode.m_strNodeName); m_eParserState = PS_XML_DOCUMENT; } return XMLR_EOS; } break; case TT_PROCINSTR: if (*arrChar == _T('?')) { nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('>')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } if (_tcsicmp(rXmlNode.m_strNodeName, _T("xml")) == 0) { if (m_eParserState == PS_XML_UNDEFINED) { m_eParserState = PS_XML_PROLOGUE; } else if (m_eParserState == PS_DTD_UNDEFINED) { m_eParserState = PS_DTD_DOCUMENT; } else { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } CAttributesList& rAttributes = rXmlNode.m_mapAttributes; PCTSTR pszEncoding = rAttributes.CaselessGetAt(_T("encoding")); CBaseDecoder* pDecoder = pszEncoding != NULL ? CBaseDecoder::GetDecoder(pszEncoding) : &CUTF8Decoder::GetInstance(); m_rXmlInputStream.SetDecoder(pDecoder); } if ((m_rReader.m_dwContentFilter & XCF_PROCINSTR) != 0) { rXmlNode.Reset(); return XMLR_CONTINUE; } else return XMLR_EOS; } break; default: _ASSERT(FALSE); m_pszErrorMessage = g_pszXmlInternalError; return XMLR_ERROR; } if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } PutCharBack(arrChar, nCharSize); CStrStream strAtrrName(32); eResult = ReadName(strAtrrName); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('=')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } CAttributesList::CAttributesListBase& rAttributes = rXmlNode.m_mapAttributes; CStrStream& rAttrValue = rAttributes.GetAt(strAtrrName); eResult = ReadString(rAttrValue); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; } } /** * @param pOutputStream - output stream. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadStringEx(CStrStream* pOutputStream) { TCHAR arrChar[2]; size_t nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; TCHAR szQuote[2] = { *arrChar, _T('\0') }; if (*szQuote != _T('\"') && *szQuote != _T('\'')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } XML_RESULT eResult = ReadTextEx(pOutputStream, szQuote, true); if (eResult == XMLR_EOF) { m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; return XMLR_ERROR; } if (eResult != XMLR_CONTINUE) return XMLR_ERROR; nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; _ASSERTE(*arrChar == *szQuote); if (*arrChar != *szQuote) { m_pszErrorMessage = g_pszXmlInternalError; return XMLR_ERROR; } return XMLR_CONTINUE; } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::CommentHandler(CXmlNode& rXmlNode, PVOID /*pParam*/) { if (m_eParserState == PS_XML_UNDEFINED) m_eParserState = PS_XML_PROLOGUE; else if (m_eParserState == PS_DTD_UNDEFINED) m_eParserState = PS_DTD_DOCUMENT; _ASSERTE(rXmlNode.m_eNodeType == CXmlNode::XNT_UNDEFINED); CStrStream* pOutputStream; bool bSkipComments = (m_rReader.m_dwContentFilter & XCF_COMMENT) != 0; if (! bSkipComments) { rXmlNode.m_eNodeType = CXmlNode::XNT_COMMENT; pOutputStream = &rXmlNode.m_strNodeValue; } else pOutputStream = NULL; XML_RESULT eResult = ReadUntilEx(pOutputStream, _T("--")); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; TCHAR arrChar[2]; size_t nCharSize = ReadChar(arrChar, true); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('>')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } return (bSkipComments ? XMLR_CONTINUE : XMLR_EOS); } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::XmlCDataHandler(CXmlNode& rXmlNode, PVOID /*pParam*/) { if (m_eParserState != PS_XML_DOCUMENT) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } XML_RESULT eResult; if ((m_rReader.m_dwContentFilter & XCF_CDATA) != 0) { _ASSERTE( rXmlNode.m_eNodeType == CXmlNode::XNT_UNDEFINED || rXmlNode.m_eNodeType == CXmlNode::XNT_TEXT); rXmlNode.m_eNodeType = CXmlNode::XNT_TEXT; eResult = ReadUntil(rXmlNode.m_strNodeValue, _T("]]>")); return (eResult == XMLR_CONTINUE ? XMLR_CONTINUE : XMLR_ERROR); } else { _ASSERTE(rXmlNode.m_eNodeType == CXmlNode::XNT_UNDEFINED); rXmlNode.m_eNodeType = CXmlNode::XNT_CDATA; eResult = ReadUntil(rXmlNode.m_strNodeValue, _T("]]>")); return (eResult == XMLR_CONTINUE ? XMLR_EOS : XMLR_ERROR); } } /** * @param pszUrl - URL. * @return input stream object or NULL pointer. */ CInputStream* CXmlReader::CXmlParser::CreateInputStream(PCTSTR pszUrl) { TCHAR szPath[MAX_PATH]; if (PathIsURL(pszUrl)) { if (UrlIsFileUrl(pszUrl)) { DWORD dwPathLength = countof(szPath); if (SUCCEEDED(PathCreateFromUrl(pszUrl, szPath, &dwPathLength, 0))) { pszUrl = szPath; } else { m_pszErrorMessage = g_pszXmlErrorInvalidUrl; return NULL; } } else { // at this moment only file URLs are supported m_pszErrorMessage = g_pszXmlErrorUnuspportedUrlScheme; return NULL; } } TCHAR szFileName[MAX_PATH]; if (PathIsRelative(pszUrl) && m_rXmlInputStream.GetName(szFileName, countof(szFileName))) { PathRemoveFileSpec(szFileName); PathAppend(szFileName, pszUrl); pszUrl = szFileName; } CFileStream* pFileStream = new CFileStream(); if (pFileStream == NULL) { m_pszErrorMessage = g_pszXmlErrorOutOfMemory; return NULL; } if (! pFileStream->Open(pszUrl, OPEN_EXISTING, GENERIC_READ, FILE_SHARE_READ)) { m_pszErrorMessage = g_pszXmlErrorCantOpenExternalResource; delete pFileStream; return NULL; } return pFileStream; } /** * @param rExternalName - eternal ID. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadExternalName(CStrStream& rExternalName) { CStrStream strNameType(16); XML_RESULT eResult = ReadName(strNameType); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; if (_tcscmp(strNameType, _T("PUBLIC")) == 0) { eResult = SkipString(); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; } else if (_tcscmp(strNameType, _T("SYSTEM")) != 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } return ReadString(rExternalName); } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::DocTypeHandler(CXmlNode& /*rXmlNode*/, PVOID /*pParam*/) { if (m_eParserState != PS_XML_UNDEFINED && m_eParserState != PS_XML_PROLOGUE) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } m_eParserState = PS_XML_PROLOGUE; XML_RESULT eResult = SkipSpaces(true); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; eResult = SkipName(); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; TCHAR arrChar[2]; size_t nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('>') && *arrChar != _T('[')) { PutCharBack(arrChar, nCharSize); CStrStream strDtdName(MAX_PATH); eResult = ReadExternalName(strDtdName); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; CInputStream* pInputStream = CreateInputStream(strDtdName); if (pInputStream == NULL) return XMLR_ERROR; CDecInputStream decInputStream(pInputStream); CXmlInputStream xmlInputSteam(&decInputStream); xmlInputSteam.CheckEncoding(TXTENC_UTF8); CXmlParser xmlParser(CXmlParser::PT_DTD_DOCUMENT, m_rReader, xmlInputSteam); eResult = xmlParser.ReadDtdNodes(); decInputStream.SetInputStream(NULL); xmlInputSteam.SetInputStream(NULL); delete pInputStream; pInputStream = NULL; _ASSERTE(eResult != XMLR_CONTINUE && eResult != XMLR_EOS); if (eResult == XMLR_CONTINUE || eResult == XMLR_EOS) { m_pszErrorMessage = g_pszXmlInternalError; return XMLR_ERROR; } if (eResult != XMLR_EOF) { m_pszErrorMessage = xmlParser.m_pszErrorMessage; return XMLR_ERROR; } nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; } if (*arrChar == _T('[')) { eResult = ReadDtdNodes(); _ASSERTE(eResult != XMLR_CONTINUE && eResult != XMLR_EOS); if (eResult == XMLR_CONTINUE || eResult == XMLR_EOS) { m_pszErrorMessage = g_pszXmlInternalError; return XMLR_ERROR; } if (eResult != XMLR_EOF) return XMLR_ERROR; nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; } if (*arrChar != _T('>')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } m_eParserState = PS_XML_DOCUMENT; return XMLR_CONTINUE; } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::DtdEntityHandler(CXmlNode& /*rXmlNode*/, PVOID pParam) { if (m_eParserState == PS_DTD_UNDEFINED) { m_eParserState = PS_DTD_DOCUMENT; } else if (m_eParserState != PS_DTD_DOCUMENT && m_eParserState != PS_EMBEDDED_DTD) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } bool bProcessingEnabled = pParam != NULL; XML_RESULT eResult = SkipSpaces(true); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; TCHAR arrChar[2]; size_t nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; bool bDtdEntity; if (*arrChar == _T('%')) { bDtdEntity = true; eResult = SkipSpaces(true); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; } else { bDtdEntity = false; PutCharBack(arrChar, nCharSize); } CStrStream strEntityName(32); eResult = ReadName(strEntityName); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; PutCharBack(arrChar, nCharSize); if (*arrChar == _T('\"') || *arrChar == _T('\'')) { // internal entity CStrStream strEntityValue(128); eResult = ReadString(strEntityValue); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; if (bProcessingEnabled) { CHash& rMapEntities = bDtdEntity ? m_rReader.m_mapDtdEntities : m_rReader.m_mapXmlEntities; rMapEntities.SetAt(strEntityName, strEntityValue); } nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('>')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } return XMLR_CONTINUE; } else { // external entity CStrStream strEntityPath(MAX_PATH); eResult = ReadExternalName(strEntityPath); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('>')) { PutCharBack(arrChar, nCharSize); CStrStream strNData(16); eResult = ReadName(strNData); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; if (_tcscmp(strNData, _T("NDATA")) != 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } eResult = SkipName(); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('>')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } } else if (bProcessingEnabled) { CInputStream* pInputStream = CreateInputStream(strEntityName); if (pInputStream == NULL) return XMLR_ERROR; CDecInputStream decInputStream(pInputStream); decInputStream.CheckEncoding(TXTENC_UTF8); CStrStream strEntityValue(128); for (;;) { TCHAR arrChar[2]; size_t nCharSize = decInputStream.ReadChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) break; PutCharToStream(strEntityValue, arrChar, nCharSize); } decInputStream.SetInputStream(NULL); delete pInputStream; pInputStream = NULL; CHash& rMapEntities = bDtdEntity ? m_rReader.m_mapDtdEntities : m_rReader.m_mapXmlEntities; rMapEntities.SetAt(strEntityName, strEntityValue); } return XMLR_CONTINUE; } } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::DtdCondtionHandler(CXmlNode& /*rXmlNode*/, PVOID pParam) { if (m_eParserState == PS_DTD_UNDEFINED) { m_eParserState = PS_DTD_DOCUMENT; } else if (m_eParserState != PS_DTD_DOCUMENT && m_eParserState != PS_EMBEDDED_DTD) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } TCHAR arrChar[2]; size_t nCharSize; CStrStream strCondition(16); XML_RESULT eResult; for (;;) { nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('%')) { PutCharBack(arrChar, nCharSize); eResult = ReadName(strCondition); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; break; } else { size_t nValueLength; eResult = ReadEntity(nValueLength); if (eResult != XMLR_CONTINUE) return XMLR_ERROR; } } bool bProcessingEnabled = pParam != NULL; if (_tcscmp(strCondition, _T("IGNORE")) == 0) { bProcessingEnabled = false; } else if (_tcscmp(strCondition, _T("INCLUDE")) != 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } nCharSize = ReadNonSpaceChar(arrChar); if (nCharSize == 0 || nCharSize == MAXSIZE_T) return XMLR_ERROR; if (*arrChar != _T('[')) { m_pszErrorMessage = g_pszXmlErrorUnexpectedChars; return XMLR_ERROR; } ++m_nNumEntries; eResult = ReadDtdNodes(bProcessingEnabled); _ASSERTE(eResult != XMLR_CONTINUE && eResult != XMLR_EOS); if (eResult == XMLR_CONTINUE || eResult == XMLR_EOS) { m_pszErrorMessage = g_pszXmlInternalError; return XMLR_ERROR; } if (eResult != XMLR_EOF) return XMLR_ERROR; --m_nNumEntries; return XMLR_CONTINUE; } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::DtdCondtionEndHandler(CXmlNode& /*rXmlNode*/, PVOID /*pParam*/) { if (m_eParserState != PS_DTD_DOCUMENT && m_eParserState != PS_EMBEDDED_DTD && m_nNumEntries == 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } return XMLR_EOF; } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::DtdEndHandler(CXmlNode& /*rXmlNode*/, PVOID /*pParam*/) { if (m_eParserState != PS_EMBEDDED_DTD && m_nNumEntries != 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } return XMLR_EOF; } /** * @param rXmlNode - info about current node is stored in this variable. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::DtdDeclarationHandler(CXmlNode& /*rXmlNode*/, PVOID /*pParam*/) { if (m_eParserState == PS_DTD_UNDEFINED) { m_eParserState = PS_DTD_DOCUMENT; } else if (m_eParserState != PS_DTD_DOCUMENT && m_eParserState != PS_EMBEDDED_DTD) { m_pszErrorMessage = g_pszXmlErrorUnexpectedToken; return XMLR_ERROR; } XML_RESULT eResult = SkipUntil(_T(">")); return (eResult == XMLR_CONTINUE ? XMLR_EOS : XMLR_ERROR); } /** * @param rXmlNode - info about current node is stored in this variable. * @param rSearchTable - search table. * @param pParam - custom defined parameter. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadNextNode(CXmlNode& rXmlNode, CXmlSearchTable& rSearchTable, PVOID pParam) { for (;;) { XML_RESULT eResult = ProcessNode(rXmlNode, rSearchTable, pParam); switch (eResult) { case XMLR_CONTINUE: continue; case XMLR_EOS: if (rXmlNode.m_eNodeType == CXmlNode::XNT_UNDEFINED) continue; if (rXmlNode.m_eNodeType == CXmlNode::XNT_TEXT) { if (m_eParserState != PS_XML_DOCUMENT) { _ASSERT(FALSE); rXmlNode.Reset(); continue; } if ((m_rReader.m_dwContentFilter & XCF_WHITESPACES) != 0) { rXmlNode.m_strNodeValue.Trim(); if (rXmlNode.m_strNodeValue.IsEmpty()) { rXmlNode.Reset(); continue; } } } break; case XMLR_EOF: rXmlNode.Reset(); break; } return eResult; } } /** * @param bProcessingEnabled - true if DTD processing should be enabled. * @return XML result code. */ CXmlReader::XML_RESULT CXmlReader::CXmlParser::ReadDtdNodes(bool bProcessingEnabled) { _ASSERTE( m_eParserState == PS_DTD_UNDEFINED || m_eParserState == PS_DTD_DOCUMENT || m_eParserState == PS_EMBEDDED_DTD || m_eParserState == PS_XML_PROLOGUE); if (m_eParserState == PS_XML_PROLOGUE) m_eParserState = PS_EMBEDDED_DTD; XML_RESULT eResult; CXmlNode xmlNode; do eResult = ReadNextDtdNode(xmlNode, bProcessingEnabled); while (eResult == XMLR_EOS); return eResult; } /** * @param rXmlNode - current node data is stored in this variable. * @param dwGotoFlags - go-to flags. * @return XML result code. */ int CXmlReader::GotoNextElement(CXmlNode& rXmlNode, DWORD dwGotoFlags) { for (;;) { size_t iResult = ReadNext(rXmlNode); if (iResult == 0) { if (dwGotoFlags & XGF_ALLOW_ELEMENT_END) return XMLR_EOF; m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; return XMLR_ERROR; } else if (iResult == MAXSIZE_T) { return XMLR_ERROR; } if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT || rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_BEGIN) { return XMLR_EOS; } else if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { if (dwGotoFlags & XGF_ALLOW_ELEMENT_END) return XMLR_EOS; m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfElement; return XMLR_ERROR; } } } /** * @param rXmlNode - current node data is stored in this variable. * @param dwGotoFlags - go-to flags. */ int CXmlReader::GotoNextElementEnd(CXmlNode& rXmlNode, DWORD dwGotoFlags) { size_t iNestedCount = 0; for (;;) { int iResult = ReadNext(rXmlNode); if (iResult == 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; return XMLR_ERROR; } else if (iResult == MAXSIZE_T) { return XMLR_ERROR; } else if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_BEGIN) { if (iNestedCount > 0 && (dwGotoFlags & XGF_ALLOW_NESTED_ELEMENTS) == 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedElement; return XMLR_ERROR; } ++iNestedCount; } else if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { if (iNestedCount > 0) --iNestedCount; else return XMLR_EOS; } } } /** * @param pszName - element name. * @param rXmlNode - current node data is stored in this variable. * @param dwGotoFlags - go-to flags. * @return XML result code. */ int CXmlReader::GotoNextElement(PCTSTR pszName, CXmlNode& rXmlNode, DWORD dwGotoFlags) { int iResult = GotoNextElement(rXmlNode, dwGotoFlags); if (iResult <= 0) return iResult; if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { _ASSERTE(dwGotoFlags & XGF_ALLOW_ELEMENT_END); return XMLR_EOS; } if (_tcscmp(rXmlNode.m_strNodeName, pszName) != 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedElement; return XMLR_ERROR; } return XMLR_EOS; } /** * @param pszName - element name. * @param rXmlNode - current node data is stored in this variable. * @param dwGotoFlags - go-to flags. * @return XML result code. */ int CXmlReader::GotoElement(PCTSTR pszName, CXmlNode& rXmlNode, DWORD dwGotoFlags) { CXmlNode XmlNode; size_t iNestedCount = 0; for (;;) { int iResult = ReadNext(XmlNode); if (iResult == 0) { if (dwGotoFlags & XGF_ALLOW_ELEMENT_END) return XMLR_EOF; m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; return XMLR_ERROR; } else if (iResult == MAXSIZE_T) { return XMLR_ERROR; } else if (XmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT) { if (iNestedCount == 0 && _tcscmp(rXmlNode.m_strNodeName, pszName) == 0) return XMLR_EOS; } else if (XmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_BEGIN) { if (iNestedCount == 0 && _tcscmp(rXmlNode.m_strNodeName, pszName) == 0) return XMLR_EOS; if (iNestedCount > 0 && (dwGotoFlags & XGF_ALLOW_NESTED_ELEMENTS) == 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedElement; return XMLR_ERROR; } ++iNestedCount; } else if (XmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { if (iNestedCount > 0) { --iNestedCount; } else { if (dwGotoFlags & XGF_ALLOW_ELEMENT_END) return XMLR_EOS; m_pszErrorMessage = g_pszXmlErrorInvalidClosingElement; return XMLR_ERROR; } } } } /** * @param rXmlNode - current node data is stored in this variable. * @param dwGotoFlags - go-to flags. * @return XML result code. */ int CXmlReader::GotoText(CXmlNode& rXmlNode, DWORD dwGotoFlags) { for (;;) { int iResult = ReadNext(rXmlNode); if (iResult == 0) { m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfStream; return XMLR_ERROR; } else if (iResult == MAXSIZE_T) { return XMLR_ERROR; } else if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT || rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_BEGIN) { m_pszErrorMessage = g_pszXmlErrorUnexpectedElement; return XMLR_ERROR; } else if (rXmlNode.m_eNodeType == CXmlNode::XNT_ELEMENT_END) { if (dwGotoFlags & XGF_ALLOW_ELEMENT_END) return XMLR_EOS; m_pszErrorMessage = g_pszXmlErrorUnexpectedEndOfElement; return XMLR_ERROR; } else if (rXmlNode.m_eNodeType == CXmlNode::XNT_TEXT) { return XMLR_EOS; } } }