| // Copyright 2014 PDFium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| #include "core/fxcrt/xml/cfx_saxreader.h" | |
| #include <algorithm> | |
| #include <utility> | |
| #include "core/fxcrt/xml/cfx_saxreaderhandler.h" | |
| #include "third_party/base/ptr_util.h" | |
| #include "third_party/base/stl_util.h" | |
| enum class CFX_SaxMode { | |
| Text = 0, | |
| NodeStart, | |
| DeclOrComment, | |
| DeclNode, | |
| Comment, | |
| CommentContent, | |
| TagName, | |
| TagAttributeName, | |
| TagAttributeEqual, | |
| TagAttributeValue, | |
| TagMaybeClose, | |
| TagClose, | |
| TagEnd, | |
| TargetData, | |
| }; | |
| class CFX_SAXCommentContext { | |
| public: | |
| CFX_SAXCommentContext() : m_iHeaderCount(0), m_iTailCount(0) {} | |
| int32_t m_iHeaderCount; | |
| int32_t m_iTailCount; | |
| }; | |
| namespace { | |
| const uint32_t kSaxFileBufSize = 32768; | |
| } // namespace | |
| CFX_SAXFile::CFX_SAXFile() | |
| : m_dwStart(0), | |
| m_dwEnd(0), | |
| m_dwCur(0), | |
| m_pBuf(nullptr), | |
| m_dwBufSize(0), | |
| m_dwBufIndex(0) {} | |
| CFX_SAXFile::~CFX_SAXFile() {} | |
| bool CFX_SAXFile::StartFile(const CFX_RetainPtr<IFX_SeekableReadStream>& pFile, | |
| uint32_t dwStart, | |
| uint32_t dwLen) { | |
| ASSERT(!m_pFile && pFile); | |
| uint32_t dwSize = pFile->GetSize(); | |
| if (dwStart >= dwSize) | |
| return false; | |
| if (dwLen == static_cast<uint32_t>(-1) || dwStart + dwLen > dwSize) | |
| dwLen = dwSize - dwStart; | |
| if (dwLen == 0) | |
| return false; | |
| m_dwBufSize = std::min(dwLen, kSaxFileBufSize); | |
| m_pBuf = FX_Alloc(uint8_t, m_dwBufSize); | |
| if (!pFile->ReadBlock(m_pBuf, dwStart, m_dwBufSize)) | |
| return false; | |
| m_dwStart = dwStart; | |
| m_dwEnd = dwStart + dwLen; | |
| m_dwCur = dwStart; | |
| m_pFile = pFile; | |
| m_dwBufIndex = 0; | |
| return true; | |
| } | |
| bool CFX_SAXFile::ReadNextBlock() { | |
| ASSERT(m_pFile); | |
| uint32_t dwSize = m_dwEnd - m_dwCur; | |
| if (dwSize == 0) { | |
| return false; | |
| } | |
| m_dwBufSize = std::min(dwSize, kSaxFileBufSize); | |
| if (!m_pFile->ReadBlock(m_pBuf, m_dwCur, m_dwBufSize)) { | |
| return false; | |
| } | |
| m_dwBufIndex = 0; | |
| return true; | |
| } | |
| void CFX_SAXFile::Reset() { | |
| if (m_pBuf) { | |
| FX_Free(m_pBuf); | |
| m_pBuf = nullptr; | |
| } | |
| m_pFile = nullptr; | |
| } | |
| CFX_SAXReader::CFX_SAXReader() | |
| : m_File(), | |
| m_pHandler(nullptr), | |
| m_iState(-1), | |
| m_dwItemID(0), | |
| m_dwParseMode(0) { | |
| m_Data.reserve(256); | |
| m_Name.reserve(256); | |
| } | |
| CFX_SAXReader::~CFX_SAXReader() { | |
| Reset(); | |
| } | |
| void CFX_SAXReader::Reset() { | |
| m_File.Reset(); | |
| m_iState = -1; | |
| m_Stack = std::stack<std::unique_ptr<CFX_SAXItem>>(); | |
| m_dwItemID = 0; | |
| m_SkipStack = std::stack<char>(); | |
| m_SkipChar = 0; | |
| m_pCommentContext.reset(); | |
| ClearData(); | |
| ClearName(); | |
| } | |
| void CFX_SAXReader::Push() { | |
| std::unique_ptr<CFX_SAXItem> pNew = | |
| pdfium::MakeUnique<CFX_SAXItem>(++m_dwItemID); | |
| if (!m_Stack.empty()) | |
| pNew->m_bSkip = m_Stack.top()->m_bSkip; | |
| m_Stack.push(std::move(pNew)); | |
| } | |
| void CFX_SAXReader::Pop() { | |
| if (!m_Stack.empty()) | |
| m_Stack.pop(); | |
| } | |
| CFX_SAXItem* CFX_SAXReader::GetCurrentItem() const { | |
| return m_Stack.empty() ? nullptr : m_Stack.top().get(); | |
| } | |
| void CFX_SAXReader::ClearData() { | |
| m_Data.clear(); | |
| m_iEntityStart = -1; | |
| } | |
| void CFX_SAXReader::ClearName() { | |
| m_Name.clear(); | |
| } | |
| void CFX_SAXReader::AppendToData(uint8_t ch) { | |
| m_Data.push_back(ch); | |
| } | |
| void CFX_SAXReader::AppendToName(uint8_t ch) { | |
| m_Name.push_back(ch); | |
| } | |
| void CFX_SAXReader::BackUpAndReplaceDataAt(int32_t index, uint8_t ch) { | |
| ASSERT(index > -1); | |
| m_Data.erase(m_Data.begin() + index, m_Data.end()); | |
| AppendToData(ch); | |
| } | |
| int32_t CFX_SAXReader::CurrentDataIndex() const { | |
| return pdfium::CollectionSize<int32_t>(m_Data) - 1; | |
| } | |
| bool CFX_SAXReader::IsEntityStart(uint8_t ch) const { | |
| return m_iEntityStart == -1 && ch == '&'; | |
| } | |
| bool CFX_SAXReader::IsEntityEnd(uint8_t ch) const { | |
| return m_iEntityStart != -1 && ch == ';'; | |
| } | |
| bool CFX_SAXReader::SkipSpace(uint8_t ch) { | |
| return (m_dwParseMode & CFX_SaxParseMode_NotSkipSpace) == 0 && ch < 0x21; | |
| } | |
| int32_t CFX_SAXReader::StartParse( | |
| const CFX_RetainPtr<IFX_SeekableReadStream>& pFile, | |
| uint32_t dwStart, | |
| uint32_t dwLen, | |
| uint32_t dwParseMode) { | |
| Reset(); | |
| if (!m_File.StartFile(pFile, dwStart, dwLen)) | |
| return -1; | |
| m_iState = 0; | |
| m_eMode = CFX_SaxMode::Text; | |
| m_ePrevMode = CFX_SaxMode::Text; | |
| m_bCharData = false; | |
| m_dwDataOffset = 0; | |
| m_dwParseMode = dwParseMode; | |
| m_Stack.emplace(new CFX_SAXItem(++m_dwItemID)); | |
| return 0; | |
| } | |
| int32_t CFX_SAXReader::ContinueParse(IFX_Pause* pPause) { | |
| if (m_iState < 0 || m_iState > 99) { | |
| return m_iState; | |
| } | |
| while (m_File.m_dwCur < m_File.m_dwEnd) { | |
| uint32_t& index = m_File.m_dwBufIndex; | |
| uint32_t size = m_File.m_dwBufSize; | |
| const uint8_t* pBuf = m_File.m_pBuf; | |
| while (index < size) { | |
| m_CurByte = pBuf[index]; | |
| ParseInternal(); | |
| index++; | |
| } | |
| m_File.m_dwCur += index; | |
| m_iState = (m_File.m_dwCur - m_File.m_dwStart) * 100 / | |
| (m_File.m_dwEnd - m_File.m_dwStart); | |
| if (m_File.m_dwCur >= m_File.m_dwEnd) { | |
| break; | |
| } | |
| if (!m_File.ReadNextBlock()) { | |
| m_iState = -2; | |
| break; | |
| } | |
| m_dwDataOffset = 0; | |
| if (pPause && pPause->NeedToPauseNow()) { | |
| break; | |
| } | |
| } | |
| return m_iState; | |
| } | |
| void CFX_SAXReader::ParseInternal() { | |
| switch (m_eMode) { | |
| case CFX_SaxMode::Text: | |
| ParseText(); | |
| break; | |
| case CFX_SaxMode::NodeStart: | |
| ParseNodeStart(); | |
| break; | |
| case CFX_SaxMode::DeclOrComment: | |
| ParseDeclOrComment(); | |
| break; | |
| case CFX_SaxMode::DeclNode: | |
| ParseDeclNode(); | |
| break; | |
| case CFX_SaxMode::Comment: | |
| ParseComment(); | |
| break; | |
| case CFX_SaxMode::CommentContent: | |
| ParseCommentContent(); | |
| break; | |
| case CFX_SaxMode::TagName: | |
| ParseTagName(); | |
| break; | |
| case CFX_SaxMode::TagAttributeName: | |
| ParseTagAttributeName(); | |
| break; | |
| case CFX_SaxMode::TagAttributeEqual: | |
| ParseTagAttributeEqual(); | |
| break; | |
| case CFX_SaxMode::TagAttributeValue: | |
| ParseTagAttributeValue(); | |
| break; | |
| case CFX_SaxMode::TagMaybeClose: | |
| ParseMaybeClose(); | |
| break; | |
| case CFX_SaxMode::TagClose: | |
| ParseTagClose(); | |
| break; | |
| case CFX_SaxMode::TagEnd: | |
| ParseTagEnd(); | |
| break; | |
| case CFX_SaxMode::TargetData: | |
| ParseTargetData(); | |
| break; | |
| } | |
| } | |
| void CFX_SAXReader::ParseChar(uint8_t ch) { | |
| AppendToData(ch); | |
| if (IsEntityStart(ch)) { | |
| m_iEntityStart = CurrentDataIndex(); | |
| return; | |
| } | |
| if (!IsEntityEnd(ch)) | |
| return; | |
| // No matter what, we're no longer in an entity. | |
| ASSERT(m_iEntityStart > -1); | |
| int32_t iSaveStart = m_iEntityStart; | |
| m_iEntityStart = -1; | |
| // NOTE: Relies on negative lengths being treated as empty strings. | |
| CFX_ByteString csEntity(m_Data.data() + iSaveStart + 1, | |
| CurrentDataIndex() - iSaveStart - 1); | |
| int32_t iLen = csEntity.GetLength(); | |
| if (iLen == 0) | |
| return; | |
| if (csEntity[0] == '#') { | |
| if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_sharp) == 0) { | |
| ch = 0; | |
| uint8_t w; | |
| if (iLen > 1 && csEntity[1] == 'x') { | |
| for (int32_t i = 2; i < iLen; i++) { | |
| w = csEntity[i]; | |
| if (w >= '0' && w <= '9') | |
| ch = (ch << 4) + w - '0'; | |
| else if (w >= 'A' && w <= 'F') | |
| ch = (ch << 4) + w - 55; | |
| else if (w >= 'a' && w <= 'f') | |
| ch = (ch << 4) + w - 87; | |
| else | |
| break; | |
| } | |
| } else { | |
| for (int32_t i = 1; i < iLen; i++) { | |
| w = csEntity[i]; | |
| if (w < '0' || w > '9') | |
| break; | |
| ch = ch * 10 + w - '0'; | |
| } | |
| } | |
| if (ch != 0) | |
| BackUpAndReplaceDataAt(iSaveStart, ch); | |
| } | |
| return; | |
| } | |
| if (csEntity == "amp") { | |
| if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_amp) == 0) | |
| BackUpAndReplaceDataAt(iSaveStart, '&'); | |
| return; | |
| } | |
| if (csEntity == "lt") { | |
| if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_lt) == 0) | |
| BackUpAndReplaceDataAt(iSaveStart, '<'); | |
| return; | |
| } | |
| if (csEntity == "gt") { | |
| if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_gt) == 0) | |
| BackUpAndReplaceDataAt(iSaveStart, '>'); | |
| return; | |
| } | |
| if (csEntity == "apos") { | |
| if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_apos) == 0) | |
| BackUpAndReplaceDataAt(iSaveStart, '\''); | |
| return; | |
| } | |
| if (csEntity == "quot") { | |
| if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_quot) == 0) | |
| BackUpAndReplaceDataAt(iSaveStart, '\"'); | |
| return; | |
| } | |
| } | |
| void CFX_SAXReader::ParseText() { | |
| if (m_CurByte == '<') { | |
| if (!m_Data.empty()) { | |
| NotifyData(); | |
| ClearData(); | |
| } | |
| Push(); | |
| m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; | |
| m_eMode = CFX_SaxMode::NodeStart; | |
| return; | |
| } | |
| if (m_Data.empty() && SkipSpace(m_CurByte)) | |
| return; | |
| ParseChar(m_CurByte); | |
| } | |
| void CFX_SAXReader::ParseNodeStart() { | |
| if (m_CurByte == '?') { | |
| GetCurrentItem()->m_eNode = CFX_SAXItem::Type::Instruction; | |
| m_eMode = CFX_SaxMode::TagName; | |
| return; | |
| } | |
| if (m_CurByte == '!') { | |
| m_eMode = CFX_SaxMode::DeclOrComment; | |
| return; | |
| } | |
| if (m_CurByte == '/') { | |
| m_eMode = CFX_SaxMode::TagEnd; | |
| return; | |
| } | |
| if (m_CurByte == '>') { | |
| Pop(); | |
| m_eMode = CFX_SaxMode::Text; | |
| return; | |
| } | |
| if (m_CurByte > 0x20) { | |
| m_dwDataOffset = m_File.m_dwBufIndex; | |
| GetCurrentItem()->m_eNode = CFX_SAXItem::Type::Tag; | |
| m_eMode = CFX_SaxMode::TagName; | |
| AppendToData(m_CurByte); | |
| } | |
| } | |
| void CFX_SAXReader::ParseDeclOrComment() { | |
| if (m_CurByte == '-') { | |
| m_eMode = CFX_SaxMode::Comment; | |
| GetCurrentItem()->m_eNode = CFX_SAXItem::Type::Comment; | |
| if (!m_pCommentContext) | |
| m_pCommentContext = pdfium::MakeUnique<CFX_SAXCommentContext>(); | |
| m_pCommentContext->m_iHeaderCount = 1; | |
| m_pCommentContext->m_iTailCount = 0; | |
| return; | |
| } | |
| m_eMode = CFX_SaxMode::DeclNode; | |
| m_dwDataOffset = m_File.m_dwBufIndex; | |
| m_SkipChar = '>'; | |
| m_SkipStack.push('>'); | |
| SkipNode(); | |
| } | |
| void CFX_SAXReader::ParseComment() { | |
| m_pCommentContext->m_iHeaderCount = 2; | |
| m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; | |
| m_eMode = CFX_SaxMode::CommentContent; | |
| } | |
| void CFX_SAXReader::ParseCommentContent() { | |
| if (m_CurByte == '-') { | |
| m_pCommentContext->m_iTailCount++; | |
| return; | |
| } | |
| if (m_CurByte == '>' && m_pCommentContext->m_iTailCount == 2) { | |
| NotifyTargetData(); | |
| ClearData(); | |
| Pop(); | |
| m_eMode = CFX_SaxMode::Text; | |
| return; | |
| } | |
| while (m_pCommentContext->m_iTailCount > 0) { | |
| AppendToData('-'); | |
| m_pCommentContext->m_iTailCount--; | |
| } | |
| AppendToData(m_CurByte); | |
| } | |
| void CFX_SAXReader::ParseDeclNode() { | |
| SkipNode(); | |
| } | |
| void CFX_SAXReader::ParseTagName() { | |
| if (m_CurByte < 0x21 || m_CurByte == '/' || m_CurByte == '>' || | |
| m_CurByte == '?') { | |
| NotifyEnter(); | |
| ClearData(); | |
| if (m_CurByte < 0x21) { | |
| ClearName(); | |
| m_eMode = CFX_SaxMode::TagAttributeName; | |
| } else if (m_CurByte == '/' || m_CurByte == '?') { | |
| m_ePrevMode = m_eMode; | |
| m_eMode = CFX_SaxMode::TagMaybeClose; | |
| } else { | |
| NotifyBreak(); | |
| m_eMode = CFX_SaxMode::Text; | |
| } | |
| } else { | |
| AppendToData(m_CurByte); | |
| } | |
| } | |
| void CFX_SAXReader::ParseTagAttributeName() { | |
| if (m_CurByte < 0x21 || m_CurByte == '=') { | |
| if (m_Name.empty() && m_CurByte < 0x21) | |
| return; | |
| m_SkipChar = 0; | |
| m_eMode = m_CurByte == '=' ? CFX_SaxMode::TagAttributeValue | |
| : CFX_SaxMode::TagAttributeEqual; | |
| ClearData(); | |
| return; | |
| } | |
| if (m_CurByte == '/' || m_CurByte == '>' || m_CurByte == '?') { | |
| if (m_CurByte == '/' || m_CurByte == '?') { | |
| m_ePrevMode = m_eMode; | |
| m_eMode = CFX_SaxMode::TagMaybeClose; | |
| } else { | |
| NotifyBreak(); | |
| m_eMode = CFX_SaxMode::Text; | |
| } | |
| return; | |
| } | |
| if (m_Name.empty()) | |
| m_dwDataOffset = m_File.m_dwBufIndex; | |
| AppendToName(m_CurByte); | |
| } | |
| void CFX_SAXReader::ParseTagAttributeEqual() { | |
| if (m_CurByte == '=') { | |
| m_SkipChar = 0; | |
| m_eMode = CFX_SaxMode::TagAttributeValue; | |
| return; | |
| } | |
| if (GetCurrentItem()->m_eNode == CFX_SAXItem::Type::Instruction) { | |
| AppendToName(0x20); | |
| m_eMode = CFX_SaxMode::TargetData; | |
| ParseTargetData(); | |
| } | |
| } | |
| void CFX_SAXReader::ParseTagAttributeValue() { | |
| if (m_SkipChar) { | |
| if (m_SkipChar == m_CurByte) { | |
| NotifyAttribute(); | |
| ClearData(); | |
| ClearName(); | |
| m_SkipChar = 0; | |
| m_eMode = CFX_SaxMode::TagAttributeName; | |
| return; | |
| } | |
| ParseChar(m_CurByte); | |
| return; | |
| } | |
| if (m_CurByte < 0x21) { | |
| return; | |
| } | |
| if (m_Data.empty()) { | |
| if (m_CurByte == '\'' || m_CurByte == '\"') | |
| m_SkipChar = m_CurByte; | |
| } | |
| } | |
| void CFX_SAXReader::ParseMaybeClose() { | |
| if (m_CurByte == '>') { | |
| if (GetCurrentItem()->m_eNode == CFX_SAXItem::Type::Instruction) { | |
| NotifyTargetData(); | |
| ClearData(); | |
| ClearName(); | |
| } | |
| ParseTagClose(); | |
| m_eMode = CFX_SaxMode::Text; | |
| } else if (m_ePrevMode == CFX_SaxMode::TagName) { | |
| AppendToData('/'); | |
| m_eMode = CFX_SaxMode::TagName; | |
| m_ePrevMode = CFX_SaxMode::Text; | |
| ParseTagName(); | |
| } else if (m_ePrevMode == CFX_SaxMode::TagAttributeName) { | |
| AppendToName('/'); | |
| m_eMode = CFX_SaxMode::TagAttributeName; | |
| m_ePrevMode = CFX_SaxMode::Text; | |
| ParseTagAttributeName(); | |
| } else if (m_ePrevMode == CFX_SaxMode::TargetData) { | |
| AppendToName('?'); | |
| m_eMode = CFX_SaxMode::TargetData; | |
| m_ePrevMode = CFX_SaxMode::Text; | |
| ParseTargetData(); | |
| } | |
| } | |
| void CFX_SAXReader::ParseTagClose() { | |
| m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; | |
| NotifyClose(); | |
| Pop(); | |
| } | |
| void CFX_SAXReader::ParseTagEnd() { | |
| if (m_CurByte < 0x21) { | |
| return; | |
| } | |
| if (m_CurByte == '>') { | |
| Pop(); | |
| m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; | |
| NotifyEnd(); | |
| ClearData(); | |
| Pop(); | |
| m_eMode = CFX_SaxMode::Text; | |
| } else { | |
| ParseChar(m_CurByte); | |
| } | |
| } | |
| void CFX_SAXReader::ParseTargetData() { | |
| if (m_CurByte == '?') { | |
| m_ePrevMode = m_eMode; | |
| m_eMode = CFX_SaxMode::TagMaybeClose; | |
| } else { | |
| AppendToName(m_CurByte); | |
| } | |
| } | |
| void CFX_SAXReader::SkipNode() { | |
| if (m_SkipChar == '\'' || m_SkipChar == '\"') { | |
| if (m_CurByte != m_SkipChar) | |
| return; | |
| ASSERT(!m_SkipStack.empty()); | |
| m_SkipStack.pop(); | |
| m_SkipChar = !m_SkipStack.empty() ? m_SkipStack.top() : 0; | |
| return; | |
| } | |
| switch (m_CurByte) { | |
| case '<': | |
| m_SkipChar = '>'; | |
| m_SkipStack.push('>'); | |
| break; | |
| case '[': | |
| m_SkipChar = ']'; | |
| m_SkipStack.push(']'); | |
| break; | |
| case '(': | |
| m_SkipChar = ')'; | |
| m_SkipStack.push(')'); | |
| break; | |
| case '\'': | |
| m_SkipChar = '\''; | |
| m_SkipStack.push('\''); | |
| break; | |
| case '\"': | |
| m_SkipChar = '\"'; | |
| m_SkipStack.push('\"'); | |
| break; | |
| default: | |
| if (m_CurByte == m_SkipChar) { | |
| m_SkipStack.pop(); | |
| m_SkipChar = !m_SkipStack.empty() ? m_SkipStack.top() : 0; | |
| if (m_SkipStack.empty() && m_CurByte == '>') { | |
| if (m_Data.size() >= 9 && memcmp(m_Data.data(), "[CDATA[", 7) == 0 && | |
| memcmp(m_Data.data() + m_Data.size() - 2, "]]", 2) == 0) { | |
| Pop(); | |
| m_Data.erase(m_Data.begin(), m_Data.begin() + 7); | |
| m_Data.erase(m_Data.end() - 2, m_Data.end()); | |
| m_bCharData = true; | |
| NotifyData(); | |
| m_bCharData = false; | |
| } else { | |
| Pop(); | |
| } | |
| ClearData(); | |
| m_eMode = CFX_SaxMode::Text; | |
| } | |
| } | |
| break; | |
| } | |
| if (!m_SkipStack.empty()) | |
| ParseChar(m_CurByte); | |
| } | |
| void CFX_SAXReader::NotifyData() { | |
| if (!m_pHandler) | |
| return; | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (!pItem) | |
| return; | |
| if (pItem->m_eNode == CFX_SAXItem::Type::Tag) | |
| m_pHandler->OnTagData( | |
| pItem->m_pNode, | |
| m_bCharData ? CFX_SAXItem::Type::CharData : CFX_SAXItem::Type::Text, | |
| CFX_ByteStringC(m_Data), m_File.m_dwCur + m_dwDataOffset); | |
| } | |
| void CFX_SAXReader::NotifyEnter() { | |
| if (!m_pHandler) | |
| return; | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (!pItem) | |
| return; | |
| if (pItem->m_eNode == CFX_SAXItem::Type::Tag || | |
| pItem->m_eNode == CFX_SAXItem::Type::Instruction) { | |
| pItem->m_pNode = m_pHandler->OnTagEnter(CFX_ByteStringC(m_Data), | |
| pItem->m_eNode, m_dwNodePos); | |
| } | |
| } | |
| void CFX_SAXReader::NotifyAttribute() { | |
| if (!m_pHandler) | |
| return; | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (!pItem) | |
| return; | |
| if (pItem->m_eNode == CFX_SAXItem::Type::Tag || | |
| pItem->m_eNode == CFX_SAXItem::Type::Instruction) { | |
| m_pHandler->OnTagAttribute(pItem->m_pNode, CFX_ByteStringC(m_Name), | |
| CFX_ByteStringC(m_Data)); | |
| } | |
| } | |
| void CFX_SAXReader::NotifyBreak() { | |
| if (!m_pHandler) | |
| return; | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (!pItem) | |
| return; | |
| if (pItem->m_eNode == CFX_SAXItem::Type::Tag) | |
| m_pHandler->OnTagBreak(pItem->m_pNode); | |
| } | |
| void CFX_SAXReader::NotifyClose() { | |
| if (!m_pHandler) | |
| return; | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (!pItem) | |
| return; | |
| if (pItem->m_eNode == CFX_SAXItem::Type::Tag || | |
| pItem->m_eNode == CFX_SAXItem::Type::Instruction) { | |
| m_pHandler->OnTagClose(pItem->m_pNode, m_dwNodePos); | |
| } | |
| } | |
| void CFX_SAXReader::NotifyEnd() { | |
| if (!m_pHandler) | |
| return; | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (!pItem) | |
| return; | |
| if (pItem->m_eNode == CFX_SAXItem::Type::Tag) | |
| m_pHandler->OnTagEnd(pItem->m_pNode, CFX_ByteStringC(m_Data), m_dwNodePos); | |
| } | |
| void CFX_SAXReader::NotifyTargetData() { | |
| if (!m_pHandler) | |
| return; | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (!pItem) | |
| return; | |
| if (pItem->m_eNode == CFX_SAXItem::Type::Instruction) { | |
| m_pHandler->OnTargetData(pItem->m_pNode, pItem->m_eNode, | |
| CFX_ByteStringC(m_Name), m_dwNodePos); | |
| } else if (pItem->m_eNode == CFX_SAXItem::Type::Comment) { | |
| m_pHandler->OnTargetData(pItem->m_pNode, pItem->m_eNode, | |
| CFX_ByteStringC(m_Data), m_dwNodePos); | |
| } | |
| } | |
| void CFX_SAXReader::SkipCurrentNode() { | |
| CFX_SAXItem* pItem = GetCurrentItem(); | |
| if (pItem) | |
| pItem->m_bSkip = true; | |
| } |