1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "core/fxcrt/xml/cfx_saxreader.h" 8 9 #include <algorithm> 10 #include <utility> 11 12 #include "core/fxcrt/fx_stream.h" 13 #include "core/fxcrt/xml/cfx_saxreaderhandler.h" 14 #include "third_party/base/ptr_util.h" 15 #include "third_party/base/stl_util.h" 16 17 enum class CFX_SaxMode { 18 Text = 0, 19 NodeStart, 20 DeclOrComment, 21 DeclNode, 22 Comment, 23 CommentContent, 24 TagName, 25 TagAttributeName, 26 TagAttributeEqual, 27 TagAttributeValue, 28 TagMaybeClose, 29 TagClose, 30 TagEnd, 31 TargetData, 32 }; 33 34 class CFX_SAXCommentContext { 35 public: 36 CFX_SAXCommentContext() : m_iHeaderCount(0), m_iTailCount(0) {} 37 int32_t m_iHeaderCount; 38 int32_t m_iTailCount; 39 }; 40 41 namespace { 42 43 const uint32_t kSaxFileBufSize = 32768; 44 45 } // namespace 46 47 CFX_SAXFile::CFX_SAXFile() 48 : m_dwStart(0), 49 m_dwEnd(0), 50 m_dwCur(0), 51 m_pBuf(nullptr), 52 m_dwBufSize(0), 53 m_dwBufIndex(0) {} 54 55 CFX_SAXFile::~CFX_SAXFile() {} 56 57 bool CFX_SAXFile::StartFile(const RetainPtr<IFX_SeekableReadStream>& pFile, 58 uint32_t dwStart, 59 uint32_t dwLen) { 60 ASSERT(!m_pFile && pFile); 61 uint32_t dwSize = pFile->GetSize(); 62 if (dwStart >= dwSize) 63 return false; 64 65 if (dwLen == static_cast<uint32_t>(-1) || dwStart + dwLen > dwSize) 66 dwLen = dwSize - dwStart; 67 68 if (dwLen == 0) 69 return false; 70 71 m_dwBufSize = std::min(dwLen, kSaxFileBufSize); 72 m_pBuf = FX_Alloc(uint8_t, m_dwBufSize); 73 if (!pFile->ReadBlock(m_pBuf, dwStart, m_dwBufSize)) 74 return false; 75 76 m_dwStart = dwStart; 77 m_dwEnd = dwStart + dwLen; 78 m_dwCur = dwStart; 79 m_pFile = pFile; 80 m_dwBufIndex = 0; 81 return true; 82 } 83 84 bool CFX_SAXFile::ReadNextBlock() { 85 ASSERT(m_pFile); 86 uint32_t dwSize = m_dwEnd - m_dwCur; 87 if (dwSize == 0) { 88 return false; 89 } 90 m_dwBufSize = std::min(dwSize, kSaxFileBufSize); 91 if (!m_pFile->ReadBlock(m_pBuf, m_dwCur, m_dwBufSize)) { 92 return false; 93 } 94 m_dwBufIndex = 0; 95 return true; 96 } 97 98 void CFX_SAXFile::Reset() { 99 if (m_pBuf) { 100 FX_Free(m_pBuf); 101 m_pBuf = nullptr; 102 } 103 m_pFile = nullptr; 104 } 105 106 CFX_SAXReader::CFX_SAXReader() 107 : m_File(), 108 m_pHandler(nullptr), 109 m_iState(-1), 110 m_dwItemID(0), 111 m_dwParseMode(0) { 112 m_Data.reserve(256); 113 m_Name.reserve(256); 114 } 115 116 CFX_SAXReader::~CFX_SAXReader() { 117 Reset(); 118 } 119 120 void CFX_SAXReader::Reset() { 121 m_File.Reset(); 122 m_iState = -1; 123 m_Stack = std::stack<std::unique_ptr<CFX_SAXItem>>(); 124 m_dwItemID = 0; 125 m_SkipStack = std::stack<char>(); 126 m_SkipChar = 0; 127 m_pCommentContext.reset(); 128 ClearData(); 129 ClearName(); 130 } 131 132 void CFX_SAXReader::Push() { 133 std::unique_ptr<CFX_SAXItem> pNew = 134 pdfium::MakeUnique<CFX_SAXItem>(++m_dwItemID); 135 if (!m_Stack.empty()) 136 pNew->m_bSkip = m_Stack.top()->m_bSkip; 137 m_Stack.push(std::move(pNew)); 138 } 139 140 void CFX_SAXReader::Pop() { 141 if (!m_Stack.empty()) 142 m_Stack.pop(); 143 } 144 145 CFX_SAXItem* CFX_SAXReader::GetCurrentItem() const { 146 return m_Stack.empty() ? nullptr : m_Stack.top().get(); 147 } 148 149 void CFX_SAXReader::ClearData() { 150 m_Data.clear(); 151 m_iEntityStart = -1; 152 } 153 154 void CFX_SAXReader::ClearName() { 155 m_Name.clear(); 156 } 157 158 void CFX_SAXReader::AppendToData(uint8_t ch) { 159 m_Data.push_back(ch); 160 } 161 162 void CFX_SAXReader::AppendToName(uint8_t ch) { 163 m_Name.push_back(ch); 164 } 165 166 void CFX_SAXReader::BackUpAndReplaceDataAt(int32_t index, uint8_t ch) { 167 ASSERT(index > -1); 168 m_Data.erase(m_Data.begin() + index, m_Data.end()); 169 AppendToData(ch); 170 } 171 172 int32_t CFX_SAXReader::CurrentDataIndex() const { 173 return pdfium::CollectionSize<int32_t>(m_Data) - 1; 174 } 175 176 bool CFX_SAXReader::IsEntityStart(uint8_t ch) const { 177 return m_iEntityStart == -1 && ch == '&'; 178 } 179 180 bool CFX_SAXReader::IsEntityEnd(uint8_t ch) const { 181 return m_iEntityStart != -1 && ch == ';'; 182 } 183 184 bool CFX_SAXReader::SkipSpace(uint8_t ch) { 185 return (m_dwParseMode & CFX_SaxParseMode_NotSkipSpace) == 0 && ch < 0x21; 186 } 187 188 int32_t CFX_SAXReader::StartParse( 189 const RetainPtr<IFX_SeekableReadStream>& pFile, 190 uint32_t dwStart, 191 uint32_t dwLen, 192 uint32_t dwParseMode) { 193 Reset(); 194 if (!m_File.StartFile(pFile, dwStart, dwLen)) 195 return -1; 196 197 m_iState = 0; 198 m_eMode = CFX_SaxMode::Text; 199 m_ePrevMode = CFX_SaxMode::Text; 200 m_bCharData = false; 201 m_dwDataOffset = 0; 202 m_dwParseMode = dwParseMode; 203 m_Stack.push(pdfium::MakeUnique<CFX_SAXItem>(++m_dwItemID)); 204 return 0; 205 } 206 207 int32_t CFX_SAXReader::ContinueParse() { 208 if (m_iState < 0 || m_iState > 99) 209 return m_iState; 210 211 while (m_File.m_dwCur < m_File.m_dwEnd) { 212 uint32_t& index = m_File.m_dwBufIndex; 213 uint32_t size = m_File.m_dwBufSize; 214 const uint8_t* pBuf = m_File.m_pBuf; 215 while (index < size) { 216 m_CurByte = pBuf[index]; 217 ParseInternal(); 218 index++; 219 } 220 m_File.m_dwCur += index; 221 m_iState = (m_File.m_dwCur - m_File.m_dwStart) * 100 / 222 (m_File.m_dwEnd - m_File.m_dwStart); 223 if (m_File.m_dwCur >= m_File.m_dwEnd) 224 break; 225 if (!m_File.ReadNextBlock()) { 226 m_iState = -2; 227 break; 228 } 229 m_dwDataOffset = 0; 230 } 231 return m_iState; 232 } 233 234 void CFX_SAXReader::ParseInternal() { 235 switch (m_eMode) { 236 case CFX_SaxMode::Text: 237 ParseText(); 238 break; 239 case CFX_SaxMode::NodeStart: 240 ParseNodeStart(); 241 break; 242 case CFX_SaxMode::DeclOrComment: 243 ParseDeclOrComment(); 244 break; 245 case CFX_SaxMode::DeclNode: 246 ParseDeclNode(); 247 break; 248 case CFX_SaxMode::Comment: 249 ParseComment(); 250 break; 251 case CFX_SaxMode::CommentContent: 252 ParseCommentContent(); 253 break; 254 case CFX_SaxMode::TagName: 255 ParseTagName(); 256 break; 257 case CFX_SaxMode::TagAttributeName: 258 ParseTagAttributeName(); 259 break; 260 case CFX_SaxMode::TagAttributeEqual: 261 ParseTagAttributeEqual(); 262 break; 263 case CFX_SaxMode::TagAttributeValue: 264 ParseTagAttributeValue(); 265 break; 266 case CFX_SaxMode::TagMaybeClose: 267 ParseMaybeClose(); 268 break; 269 case CFX_SaxMode::TagClose: 270 ParseTagClose(); 271 break; 272 case CFX_SaxMode::TagEnd: 273 ParseTagEnd(); 274 break; 275 case CFX_SaxMode::TargetData: 276 ParseTargetData(); 277 break; 278 } 279 } 280 281 void CFX_SAXReader::ParseChar(uint8_t ch) { 282 AppendToData(ch); 283 if (IsEntityStart(ch)) { 284 m_iEntityStart = CurrentDataIndex(); 285 return; 286 } 287 if (!IsEntityEnd(ch)) 288 return; 289 290 // No matter what, we're no longer in an entity. 291 ASSERT(m_iEntityStart > -1); 292 int32_t iSaveStart = m_iEntityStart; 293 m_iEntityStart = -1; 294 295 // NOTE: Relies on negative lengths being treated as empty strings. 296 ByteString csEntity(m_Data.data() + iSaveStart + 1, 297 CurrentDataIndex() - iSaveStart - 1); 298 int32_t iLen = csEntity.GetLength(); 299 if (iLen == 0) 300 return; 301 302 if (csEntity[0] == '#') { 303 if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_sharp) == 0) { 304 ch = 0; 305 uint8_t w; 306 if (iLen > 1 && csEntity[1] == 'x') { 307 for (int32_t i = 2; i < iLen; i++) { 308 w = csEntity[i]; 309 if (w >= '0' && w <= '9') 310 ch = (ch << 4) + w - '0'; 311 else if (w >= 'A' && w <= 'F') 312 ch = (ch << 4) + w - 55; 313 else if (w >= 'a' && w <= 'f') 314 ch = (ch << 4) + w - 87; 315 else 316 break; 317 } 318 } else { 319 for (int32_t i = 1; i < iLen; i++) { 320 w = csEntity[i]; 321 if (w < '0' || w > '9') 322 break; 323 ch = ch * 10 + w - '0'; 324 } 325 } 326 if (ch != 0) 327 BackUpAndReplaceDataAt(iSaveStart, ch); 328 } 329 return; 330 } 331 if (csEntity == "amp") { 332 if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_amp) == 0) 333 BackUpAndReplaceDataAt(iSaveStart, '&'); 334 return; 335 } 336 if (csEntity == "lt") { 337 if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_lt) == 0) 338 BackUpAndReplaceDataAt(iSaveStart, '<'); 339 return; 340 } 341 if (csEntity == "gt") { 342 if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_gt) == 0) 343 BackUpAndReplaceDataAt(iSaveStart, '>'); 344 return; 345 } 346 if (csEntity == "apos") { 347 if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_apos) == 0) 348 BackUpAndReplaceDataAt(iSaveStart, '\''); 349 return; 350 } 351 if (csEntity == "quot") { 352 if ((m_dwParseMode & CFX_SaxParseMode_NotConvert_quot) == 0) 353 BackUpAndReplaceDataAt(iSaveStart, '\"'); 354 return; 355 } 356 } 357 358 void CFX_SAXReader::ParseText() { 359 if (m_CurByte == '<') { 360 if (!m_Data.empty()) { 361 NotifyData(); 362 ClearData(); 363 } 364 Push(); 365 m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; 366 m_eMode = CFX_SaxMode::NodeStart; 367 return; 368 } 369 if (m_Data.empty() && SkipSpace(m_CurByte)) 370 return; 371 372 ParseChar(m_CurByte); 373 } 374 375 void CFX_SAXReader::ParseNodeStart() { 376 if (m_CurByte == '?') { 377 GetCurrentItem()->m_eNode = CFX_SAXItem::Type::Instruction; 378 m_eMode = CFX_SaxMode::TagName; 379 return; 380 } 381 if (m_CurByte == '!') { 382 m_eMode = CFX_SaxMode::DeclOrComment; 383 return; 384 } 385 if (m_CurByte == '/') { 386 m_eMode = CFX_SaxMode::TagEnd; 387 return; 388 } 389 if (m_CurByte == '>') { 390 Pop(); 391 m_eMode = CFX_SaxMode::Text; 392 return; 393 } 394 if (m_CurByte > 0x20) { 395 m_dwDataOffset = m_File.m_dwBufIndex; 396 GetCurrentItem()->m_eNode = CFX_SAXItem::Type::Tag; 397 m_eMode = CFX_SaxMode::TagName; 398 AppendToData(m_CurByte); 399 } 400 } 401 402 void CFX_SAXReader::ParseDeclOrComment() { 403 if (m_CurByte == '-') { 404 m_eMode = CFX_SaxMode::Comment; 405 GetCurrentItem()->m_eNode = CFX_SAXItem::Type::Comment; 406 if (!m_pCommentContext) 407 m_pCommentContext = pdfium::MakeUnique<CFX_SAXCommentContext>(); 408 m_pCommentContext->m_iHeaderCount = 1; 409 m_pCommentContext->m_iTailCount = 0; 410 return; 411 } 412 m_eMode = CFX_SaxMode::DeclNode; 413 m_dwDataOffset = m_File.m_dwBufIndex; 414 m_SkipChar = '>'; 415 m_SkipStack.push('>'); 416 SkipNode(); 417 } 418 419 void CFX_SAXReader::ParseComment() { 420 m_pCommentContext->m_iHeaderCount = 2; 421 m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; 422 m_eMode = CFX_SaxMode::CommentContent; 423 } 424 425 void CFX_SAXReader::ParseCommentContent() { 426 if (m_CurByte == '-') { 427 m_pCommentContext->m_iTailCount++; 428 return; 429 } 430 if (m_CurByte == '>' && m_pCommentContext->m_iTailCount == 2) { 431 NotifyTargetData(); 432 ClearData(); 433 Pop(); 434 m_eMode = CFX_SaxMode::Text; 435 return; 436 } 437 while (m_pCommentContext->m_iTailCount > 0) { 438 AppendToData('-'); 439 m_pCommentContext->m_iTailCount--; 440 } 441 AppendToData(m_CurByte); 442 } 443 444 void CFX_SAXReader::ParseDeclNode() { 445 SkipNode(); 446 } 447 448 void CFX_SAXReader::ParseTagName() { 449 if (m_CurByte < 0x21 || m_CurByte == '/' || m_CurByte == '>' || 450 m_CurByte == '?') { 451 NotifyEnter(); 452 ClearData(); 453 if (m_CurByte < 0x21) { 454 ClearName(); 455 m_eMode = CFX_SaxMode::TagAttributeName; 456 } else if (m_CurByte == '/' || m_CurByte == '?') { 457 m_ePrevMode = m_eMode; 458 m_eMode = CFX_SaxMode::TagMaybeClose; 459 } else { 460 NotifyBreak(); 461 m_eMode = CFX_SaxMode::Text; 462 } 463 } else { 464 AppendToData(m_CurByte); 465 } 466 } 467 468 void CFX_SAXReader::ParseTagAttributeName() { 469 if (m_CurByte < 0x21 || m_CurByte == '=') { 470 if (m_Name.empty() && m_CurByte < 0x21) 471 return; 472 473 m_SkipChar = 0; 474 m_eMode = m_CurByte == '=' ? CFX_SaxMode::TagAttributeValue 475 : CFX_SaxMode::TagAttributeEqual; 476 ClearData(); 477 return; 478 } 479 if (m_CurByte == '/' || m_CurByte == '>' || m_CurByte == '?') { 480 if (m_CurByte == '/' || m_CurByte == '?') { 481 m_ePrevMode = m_eMode; 482 m_eMode = CFX_SaxMode::TagMaybeClose; 483 } else { 484 NotifyBreak(); 485 m_eMode = CFX_SaxMode::Text; 486 } 487 return; 488 } 489 if (m_Name.empty()) 490 m_dwDataOffset = m_File.m_dwBufIndex; 491 AppendToName(m_CurByte); 492 } 493 494 void CFX_SAXReader::ParseTagAttributeEqual() { 495 if (m_CurByte == '=') { 496 m_SkipChar = 0; 497 m_eMode = CFX_SaxMode::TagAttributeValue; 498 return; 499 } 500 if (GetCurrentItem()->m_eNode == CFX_SAXItem::Type::Instruction) { 501 AppendToName(0x20); 502 m_eMode = CFX_SaxMode::TargetData; 503 ParseTargetData(); 504 } 505 } 506 507 void CFX_SAXReader::ParseTagAttributeValue() { 508 if (m_SkipChar) { 509 if (m_SkipChar == m_CurByte) { 510 NotifyAttribute(); 511 ClearData(); 512 ClearName(); 513 m_SkipChar = 0; 514 m_eMode = CFX_SaxMode::TagAttributeName; 515 return; 516 } 517 ParseChar(m_CurByte); 518 return; 519 } 520 if (m_CurByte < 0x21) { 521 return; 522 } 523 if (m_Data.empty()) { 524 if (m_CurByte == '\'' || m_CurByte == '\"') 525 m_SkipChar = m_CurByte; 526 } 527 } 528 529 void CFX_SAXReader::ParseMaybeClose() { 530 if (m_CurByte == '>') { 531 if (GetCurrentItem()->m_eNode == CFX_SAXItem::Type::Instruction) { 532 NotifyTargetData(); 533 ClearData(); 534 ClearName(); 535 } 536 ParseTagClose(); 537 m_eMode = CFX_SaxMode::Text; 538 } else if (m_ePrevMode == CFX_SaxMode::TagName) { 539 AppendToData('/'); 540 m_eMode = CFX_SaxMode::TagName; 541 m_ePrevMode = CFX_SaxMode::Text; 542 ParseTagName(); 543 } else if (m_ePrevMode == CFX_SaxMode::TagAttributeName) { 544 AppendToName('/'); 545 m_eMode = CFX_SaxMode::TagAttributeName; 546 m_ePrevMode = CFX_SaxMode::Text; 547 ParseTagAttributeName(); 548 } else if (m_ePrevMode == CFX_SaxMode::TargetData) { 549 AppendToName('?'); 550 m_eMode = CFX_SaxMode::TargetData; 551 m_ePrevMode = CFX_SaxMode::Text; 552 ParseTargetData(); 553 } 554 } 555 void CFX_SAXReader::ParseTagClose() { 556 m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; 557 NotifyClose(); 558 Pop(); 559 } 560 void CFX_SAXReader::ParseTagEnd() { 561 if (m_CurByte < 0x21) { 562 return; 563 } 564 if (m_CurByte == '>') { 565 Pop(); 566 m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex; 567 NotifyEnd(); 568 ClearData(); 569 Pop(); 570 m_eMode = CFX_SaxMode::Text; 571 } else { 572 ParseChar(m_CurByte); 573 } 574 } 575 void CFX_SAXReader::ParseTargetData() { 576 if (m_CurByte == '?') { 577 m_ePrevMode = m_eMode; 578 m_eMode = CFX_SaxMode::TagMaybeClose; 579 } else { 580 AppendToName(m_CurByte); 581 } 582 } 583 void CFX_SAXReader::SkipNode() { 584 if (m_SkipChar == '\'' || m_SkipChar == '\"') { 585 if (m_CurByte != m_SkipChar) 586 return; 587 588 ASSERT(!m_SkipStack.empty()); 589 m_SkipStack.pop(); 590 m_SkipChar = !m_SkipStack.empty() ? m_SkipStack.top() : 0; 591 return; 592 } 593 switch (m_CurByte) { 594 case '<': 595 m_SkipChar = '>'; 596 m_SkipStack.push('>'); 597 break; 598 case '[': 599 m_SkipChar = ']'; 600 m_SkipStack.push(']'); 601 break; 602 case '(': 603 m_SkipChar = ')'; 604 m_SkipStack.push(')'); 605 break; 606 case '\'': 607 m_SkipChar = '\''; 608 m_SkipStack.push('\''); 609 break; 610 case '\"': 611 m_SkipChar = '\"'; 612 m_SkipStack.push('\"'); 613 break; 614 default: 615 if (m_CurByte == m_SkipChar) { 616 m_SkipStack.pop(); 617 m_SkipChar = !m_SkipStack.empty() ? m_SkipStack.top() : 0; 618 if (m_SkipStack.empty() && m_CurByte == '>') { 619 if (m_Data.size() >= 9 && memcmp(m_Data.data(), "[CDATA[", 7) == 0 && 620 memcmp(m_Data.data() + m_Data.size() - 2, "]]", 2) == 0) { 621 Pop(); 622 m_Data.erase(m_Data.begin(), m_Data.begin() + 7); 623 m_Data.erase(m_Data.end() - 2, m_Data.end()); 624 m_bCharData = true; 625 NotifyData(); 626 m_bCharData = false; 627 } else { 628 Pop(); 629 } 630 ClearData(); 631 m_eMode = CFX_SaxMode::Text; 632 } 633 } 634 break; 635 } 636 if (!m_SkipStack.empty()) 637 ParseChar(m_CurByte); 638 } 639 640 void CFX_SAXReader::NotifyData() { 641 if (!m_pHandler) 642 return; 643 644 CFX_SAXItem* pItem = GetCurrentItem(); 645 if (!pItem) 646 return; 647 648 if (pItem->m_eNode == CFX_SAXItem::Type::Tag) 649 m_pHandler->OnTagData( 650 pItem->m_pNode, 651 m_bCharData ? CFX_SAXItem::Type::CharData : CFX_SAXItem::Type::Text, 652 ByteStringView(m_Data), m_File.m_dwCur + m_dwDataOffset); 653 } 654 655 void CFX_SAXReader::NotifyEnter() { 656 if (!m_pHandler) 657 return; 658 659 CFX_SAXItem* pItem = GetCurrentItem(); 660 if (!pItem) 661 return; 662 663 if (pItem->m_eNode == CFX_SAXItem::Type::Tag || 664 pItem->m_eNode == CFX_SAXItem::Type::Instruction) { 665 pItem->m_pNode = m_pHandler->OnTagEnter(ByteStringView(m_Data), 666 pItem->m_eNode, m_dwNodePos); 667 } 668 } 669 670 void CFX_SAXReader::NotifyAttribute() { 671 if (!m_pHandler) 672 return; 673 674 CFX_SAXItem* pItem = GetCurrentItem(); 675 if (!pItem) 676 return; 677 678 if (pItem->m_eNode == CFX_SAXItem::Type::Tag || 679 pItem->m_eNode == CFX_SAXItem::Type::Instruction) { 680 m_pHandler->OnTagAttribute(pItem->m_pNode, ByteStringView(m_Name), 681 ByteStringView(m_Data)); 682 } 683 } 684 685 void CFX_SAXReader::NotifyBreak() { 686 if (!m_pHandler) 687 return; 688 689 CFX_SAXItem* pItem = GetCurrentItem(); 690 if (!pItem) 691 return; 692 693 if (pItem->m_eNode == CFX_SAXItem::Type::Tag) 694 m_pHandler->OnTagBreak(pItem->m_pNode); 695 } 696 697 void CFX_SAXReader::NotifyClose() { 698 if (!m_pHandler) 699 return; 700 701 CFX_SAXItem* pItem = GetCurrentItem(); 702 if (!pItem) 703 return; 704 705 if (pItem->m_eNode == CFX_SAXItem::Type::Tag || 706 pItem->m_eNode == CFX_SAXItem::Type::Instruction) { 707 m_pHandler->OnTagClose(pItem->m_pNode, m_dwNodePos); 708 } 709 } 710 711 void CFX_SAXReader::NotifyEnd() { 712 if (!m_pHandler) 713 return; 714 715 CFX_SAXItem* pItem = GetCurrentItem(); 716 if (!pItem) 717 return; 718 719 if (pItem->m_eNode == CFX_SAXItem::Type::Tag) 720 m_pHandler->OnTagEnd(pItem->m_pNode, ByteStringView(m_Data), m_dwNodePos); 721 } 722 723 void CFX_SAXReader::NotifyTargetData() { 724 if (!m_pHandler) 725 return; 726 727 CFX_SAXItem* pItem = GetCurrentItem(); 728 if (!pItem) 729 return; 730 731 if (pItem->m_eNode == CFX_SAXItem::Type::Instruction) { 732 m_pHandler->OnTargetData(pItem->m_pNode, pItem->m_eNode, 733 ByteStringView(m_Name), m_dwNodePos); 734 } else if (pItem->m_eNode == CFX_SAXItem::Type::Comment) { 735 m_pHandler->OnTargetData(pItem->m_pNode, pItem->m_eNode, 736 ByteStringView(m_Data), m_dwNodePos); 737 } 738 } 739 740 void CFX_SAXReader::SkipCurrentNode() { 741 CFX_SAXItem* pItem = GetCurrentItem(); 742 if (pItem) 743 pItem->m_bSkip = true; 744 } 745