Home | History | Annotate | Download | only in xml
      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 <algorithm>
      8 
      9 #include "xfa/src/fgas/src/fgas_base.h"
     10 #include "fx_sax_imp.h"
     11 
     12 namespace {
     13 
     14 const FX_DWORD kSaxFileBufSize = 32768;
     15 
     16 }  // namespace
     17 
     18 IFX_SAXReader* FX_SAXReader_Create() {
     19   return new CFX_SAXReader;
     20 }
     21 CFX_SAXFile::CFX_SAXFile()
     22     : m_pFile(NULL),
     23       m_dwStart(0),
     24       m_dwEnd(0),
     25       m_dwCur(0),
     26       m_pBuf(NULL),
     27       m_dwBufSize(0),
     28       m_dwBufIndex(0) {}
     29 FX_BOOL CFX_SAXFile::StartFile(IFX_FileRead* pFile,
     30                                FX_DWORD dwStart,
     31                                FX_DWORD dwLen) {
     32   FXSYS_assert(m_pFile == NULL && pFile != NULL);
     33   FX_DWORD dwSize = pFile->GetSize();
     34   if (dwStart >= dwSize) {
     35     return FALSE;
     36   }
     37   if (dwLen == -1 || dwStart + dwLen > dwSize) {
     38     dwLen = dwSize - dwStart;
     39   }
     40   if (dwLen == 0) {
     41     return FALSE;
     42   }
     43   m_dwBufSize = std::min(dwLen, kSaxFileBufSize);
     44   m_pBuf = FX_Alloc(uint8_t, m_dwBufSize);
     45   if (!pFile->ReadBlock(m_pBuf, dwStart, m_dwBufSize)) {
     46     return FALSE;
     47   }
     48   m_dwStart = dwStart;
     49   m_dwEnd = dwStart + dwLen;
     50   m_dwCur = dwStart;
     51   m_pFile = pFile;
     52   m_dwBufIndex = 0;
     53   return TRUE;
     54 }
     55 FX_BOOL CFX_SAXFile::ReadNextBlock() {
     56   FXSYS_assert(m_pFile != NULL);
     57   FX_DWORD dwSize = m_dwEnd - m_dwCur;
     58   if (dwSize == 0) {
     59     return FALSE;
     60   }
     61   m_dwBufSize = std::min(dwSize, kSaxFileBufSize);
     62   if (!m_pFile->ReadBlock(m_pBuf, m_dwCur, m_dwBufSize)) {
     63     return FALSE;
     64   }
     65   m_dwBufIndex = 0;
     66   return TRUE;
     67 }
     68 void CFX_SAXFile::Reset() {
     69   if (m_pBuf) {
     70     FX_Free(m_pBuf);
     71     m_pBuf = NULL;
     72   }
     73   m_pFile = NULL;
     74 }
     75 CFX_SAXReader::CFX_SAXReader()
     76     : m_File(),
     77       m_pHandler(nullptr),
     78       m_iState(-1),
     79       m_pRoot(nullptr),
     80       m_pCurItem(nullptr),
     81       m_dwItemID(0),
     82       m_iDataSize(256),
     83       m_iNameSize(256),
     84       m_dwParseMode(0),
     85       m_pCommentContext(nullptr) {
     86   m_pszData = FX_Alloc(uint8_t, m_iDataSize);
     87   m_pszName = FX_Alloc(uint8_t, m_iNameSize);
     88 }
     89 CFX_SAXReader::~CFX_SAXReader() {
     90   Reset();
     91   if (m_pszData) {
     92     FX_Free(m_pszData);
     93     m_pszData = NULL;
     94   }
     95   if (m_pszName) {
     96     FX_Free(m_pszName);
     97     m_pszName = NULL;
     98   }
     99 }
    100 void CFX_SAXReader::Reset() {
    101   m_File.Reset();
    102   CFX_SAXItem* pItem = m_pRoot;
    103   while (pItem) {
    104     CFX_SAXItem* pNext = pItem->m_pNext;
    105     delete pItem;
    106     pItem = pNext;
    107   }
    108   m_pRoot = NULL;
    109   m_pCurItem = NULL;
    110   m_dwItemID = 0;
    111   m_SkipStack.RemoveAll();
    112   m_SkipChar = 0;
    113   m_iDataLength = 0;
    114   m_iEntityStart = -1;
    115   m_iNameLength = 0;
    116   m_iDataPos = 0;
    117   if (m_pCommentContext) {
    118     delete m_pCommentContext;
    119     m_pCommentContext = NULL;
    120   }
    121 }
    122 inline void CFX_SAXReader::Push() {
    123   CFX_SAXItem* pNew = new CFX_SAXItem;
    124   pNew->m_dwID = ++m_dwItemID;
    125   pNew->m_bSkip = m_pCurItem->m_bSkip;
    126   pNew->m_pPrev = m_pCurItem;
    127   m_pCurItem->m_pNext = pNew;
    128   m_pCurItem = pNew;
    129 }
    130 inline void CFX_SAXReader::Pop() {
    131   if (!m_pCurItem) {
    132     return;
    133   }
    134   CFX_SAXItem* pPrev = m_pCurItem->m_pPrev;
    135   pPrev->m_pNext = NULL;
    136   delete m_pCurItem;
    137   m_pCurItem = pPrev;
    138 }
    139 inline void CFX_SAXReader::AppendData(uint8_t ch) {
    140   ReallocDataBuffer();
    141   m_pszData[m_iDataPos++] = ch;
    142 }
    143 inline void CFX_SAXReader::AppendName(uint8_t ch) {
    144   ReallocNameBuffer();
    145   m_pszName[m_iDataPos++] = ch;
    146 }
    147 void CFX_SAXReader::ReallocDataBuffer() {
    148   if (m_iDataPos < m_iDataSize) {
    149     return;
    150   }
    151   if (m_iDataSize <= 1024 * 1024) {
    152     m_iDataSize *= 2;
    153   } else {
    154     m_iDataSize += 1024 * 1024;
    155   }
    156   m_pszData = (uint8_t*)FX_Realloc(uint8_t, m_pszData, m_iDataSize);
    157 }
    158 void CFX_SAXReader::ReallocNameBuffer() {
    159   if (m_iDataPos < m_iNameSize) {
    160     return;
    161   }
    162   if (m_iNameSize <= 1024 * 1024) {
    163     m_iNameSize *= 2;
    164   } else {
    165     m_iNameSize += 1024 * 1024;
    166   }
    167   m_pszName = (uint8_t*)FX_Realloc(uint8_t, m_pszName, m_iNameSize);
    168 }
    169 inline FX_BOOL CFX_SAXReader::SkipSpace(uint8_t ch) {
    170   return (m_dwParseMode & FX_SAXPARSEMODE_NotSkipSpace) == 0 && ch < 0x21;
    171 }
    172 int32_t CFX_SAXReader::StartParse(IFX_FileRead* pFile,
    173                                   FX_DWORD dwStart,
    174                                   FX_DWORD dwLen,
    175                                   FX_DWORD dwParseMode) {
    176   m_iState = -1;
    177   Reset();
    178   if (!m_File.StartFile(pFile, dwStart, dwLen)) {
    179     return -1;
    180   }
    181   m_iState = 0;
    182   m_eMode = FX_SAXMODE_Text;
    183   m_ePrevMode = FX_SAXMODE_Text;
    184   m_bCharData = FALSE;
    185   m_dwDataOffset = 0;
    186   m_pRoot = m_pCurItem = new CFX_SAXItem;
    187   m_pCurItem->m_dwID = ++m_dwItemID;
    188   m_dwParseMode = dwParseMode;
    189   return 0;
    190 }
    191 typedef void (CFX_SAXReader::*FX_SAXReader_LPFParse)();
    192 static const FX_SAXReader_LPFParse g_FX_SAXReader_LPFParse[FX_SAXMODE_MAX] = {
    193     &CFX_SAXReader::ParseText,
    194     &CFX_SAXReader::ParseNodeStart,
    195     &CFX_SAXReader::ParseDeclOrComment,
    196     &CFX_SAXReader::ParseDeclNode,
    197     &CFX_SAXReader::ParseComment,
    198     &CFX_SAXReader::ParseCommentContent,
    199     &CFX_SAXReader::ParseTagName,
    200     &CFX_SAXReader::ParseTagAttributeName,
    201     &CFX_SAXReader::ParseTagAttributeEqual,
    202     &CFX_SAXReader::ParseTagAttributeValue,
    203     &CFX_SAXReader::ParseMaybeClose,
    204     &CFX_SAXReader::ParseTagClose,
    205     &CFX_SAXReader::ParseTagEnd,
    206     &CFX_SAXReader::ParseTargetData,
    207 };
    208 int32_t CFX_SAXReader::ContinueParse(IFX_Pause* pPause) {
    209   if (m_iState < 0 || m_iState > 99) {
    210     return m_iState;
    211   }
    212   while (m_File.m_dwCur < m_File.m_dwEnd) {
    213     FX_DWORD& index = m_File.m_dwBufIndex;
    214     FX_DWORD size = m_File.m_dwBufSize;
    215     const uint8_t* pBuf = m_File.m_pBuf;
    216     while (index < size) {
    217       m_CurByte = pBuf[index];
    218       (this->*g_FX_SAXReader_LPFParse[m_eMode])();
    219       index++;
    220     }
    221     m_File.m_dwCur += index;
    222     m_iState = (m_File.m_dwCur - m_File.m_dwStart) * 100 /
    223                (m_File.m_dwEnd - m_File.m_dwStart);
    224     if (m_File.m_dwCur >= m_File.m_dwEnd) {
    225       break;
    226     }
    227     if (!m_File.ReadNextBlock()) {
    228       m_iState = -2;
    229       break;
    230     }
    231     m_dwDataOffset = 0;
    232     if (pPause && pPause->NeedToPauseNow()) {
    233       break;
    234     }
    235   }
    236   return m_iState;
    237 }
    238 void CFX_SAXReader::ParseChar(uint8_t ch) {
    239   ReallocDataBuffer();
    240   m_pszData[m_iDataPos] = ch;
    241   if (m_iEntityStart > -1 && ch == ';') {
    242     int32_t iSaveEntityStart = m_iEntityStart;
    243     CFX_ByteString csEntity(m_pszData + m_iEntityStart + 1,
    244                             m_iDataPos - m_iEntityStart - 1);
    245     int32_t iLen = csEntity.GetLength();
    246     if (iLen > 0) {
    247       if (csEntity[0] == '#') {
    248         if ((m_dwParseMode & FX_SAXPARSEMODE_NotConvert_sharp) == 0) {
    249           ch = 0;
    250           uint8_t w;
    251           if (iLen > 1 && csEntity[1] == 'x') {
    252             for (int32_t i = 2; i < iLen; i++) {
    253               w = csEntity[i];
    254               if (w >= '0' && w <= '9') {
    255                 ch = (ch << 4) + w - '0';
    256               } else if (w >= 'A' && w <= 'F') {
    257                 ch = (ch << 4) + w - 55;
    258               } else if (w >= 'a' && w <= 'f') {
    259                 ch = (ch << 4) + w - 87;
    260               } else {
    261                 break;
    262               }
    263             }
    264           } else {
    265             for (int32_t i = 1; i < iLen; i++) {
    266               w = csEntity[i];
    267               if (w < '0' || w > '9') {
    268                 break;
    269               }
    270               ch = ch * 10 + w - '0';
    271             }
    272           }
    273           if (ch != 0) {
    274             m_pszData[m_iEntityStart++] = ch;
    275           }
    276         }
    277       } else {
    278         if (csEntity.Compare("amp") == 0) {
    279           if ((m_dwParseMode & FX_SAXPARSEMODE_NotConvert_amp) == 0) {
    280             m_pszData[m_iEntityStart++] = '&';
    281           }
    282         } else if (csEntity.Compare("lt") == 0) {
    283           if ((m_dwParseMode & FX_SAXPARSEMODE_NotConvert_lt) == 0) {
    284             m_pszData[m_iEntityStart++] = '<';
    285           }
    286         } else if (csEntity.Compare("gt") == 0) {
    287           if ((m_dwParseMode & FX_SAXPARSEMODE_NotConvert_gt) == 0) {
    288             m_pszData[m_iEntityStart++] = '>';
    289           }
    290         } else if (csEntity.Compare("apos") == 0) {
    291           if ((m_dwParseMode & FX_SAXPARSEMODE_NotConvert_apos) == 0) {
    292             m_pszData[m_iEntityStart++] = '\'';
    293           }
    294         } else if (csEntity.Compare("quot") == 0) {
    295           if ((m_dwParseMode & FX_SAXPARSEMODE_NotConvert_quot) == 0) {
    296             m_pszData[m_iEntityStart++] = '\"';
    297           }
    298         }
    299       }
    300     }
    301     if (iSaveEntityStart != m_iEntityStart) {
    302       m_iDataPos = m_iEntityStart;
    303       m_iEntityStart = -1;
    304     } else {
    305       m_iDataPos++;
    306       m_iEntityStart = -1;
    307     }
    308   } else {
    309     if (m_iEntityStart < 0 && ch == '&') {
    310       m_iEntityStart = m_iDataPos;
    311     }
    312     m_iDataPos++;
    313   }
    314 }
    315 void CFX_SAXReader::ParseText() {
    316   if (m_CurByte == '<') {
    317     if (m_iDataPos > 0) {
    318       m_iDataLength = m_iDataPos;
    319       m_iDataPos = 0;
    320       if (m_pHandler) {
    321         NotifyData();
    322       }
    323     }
    324     Push();
    325     m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex;
    326     m_eMode = FX_SAXMODE_NodeStart;
    327     return;
    328   }
    329   if (m_iDataPos < 1 && SkipSpace(m_CurByte)) {
    330     return;
    331   }
    332   ParseChar(m_CurByte);
    333 }
    334 void CFX_SAXReader::ParseNodeStart() {
    335   if (m_CurByte == '?') {
    336     m_pCurItem->m_eNode = FX_SAXNODE_Instruction;
    337     m_eMode = FX_SAXMODE_TagName;
    338     return;
    339   }
    340   if (m_CurByte == '!') {
    341     m_eMode = FX_SAXMODE_DeclOrComment;
    342     return;
    343   }
    344   if (m_CurByte == '/') {
    345     m_eMode = FX_SAXMODE_TagEnd;
    346     return;
    347   }
    348   if (m_CurByte == '>') {
    349     Pop();
    350     m_eMode = FX_SAXMODE_Text;
    351     return;
    352   }
    353   if (m_CurByte > 0x20) {
    354     m_dwDataOffset = m_File.m_dwBufIndex;
    355     m_pCurItem->m_eNode = FX_SAXNODE_Tag;
    356     m_eMode = FX_SAXMODE_TagName;
    357     AppendData(m_CurByte);
    358   }
    359 }
    360 void CFX_SAXReader::ParseDeclOrComment() {
    361   if (m_CurByte == '-') {
    362     m_eMode = FX_SAXMODE_Comment;
    363     m_pCurItem->m_eNode = FX_SAXNODE_Comment;
    364     if (m_pCommentContext == NULL) {
    365       m_pCommentContext = new CFX_SAXCommentContext;
    366     }
    367     m_pCommentContext->m_iHeaderCount = 1;
    368     m_pCommentContext->m_iTailCount = 0;
    369   } else {
    370     m_eMode = FX_SAXMODE_DeclNode;
    371     m_dwDataOffset = m_File.m_dwBufIndex;
    372     m_SkipChar = '>';
    373     m_SkipStack.Add('>');
    374     SkipNode();
    375   }
    376 }
    377 void CFX_SAXReader::ParseComment() {
    378   m_pCommentContext->m_iHeaderCount = 2;
    379   m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex;
    380   m_eMode = FX_SAXMODE_CommentContent;
    381 }
    382 void CFX_SAXReader::ParseCommentContent() {
    383   if (m_CurByte == '-') {
    384     m_pCommentContext->m_iTailCount++;
    385   } else if (m_CurByte == '>' && m_pCommentContext->m_iTailCount == 2) {
    386     m_iDataLength = m_iDataPos;
    387     m_iDataPos = 0;
    388     if (m_pHandler) {
    389       NotifyTargetData();
    390     }
    391     Pop();
    392     m_eMode = FX_SAXMODE_Text;
    393   } else {
    394     while (m_pCommentContext->m_iTailCount > 0) {
    395       AppendData('-');
    396       m_pCommentContext->m_iTailCount--;
    397     }
    398     AppendData(m_CurByte);
    399   }
    400 }
    401 void CFX_SAXReader::ParseDeclNode() {
    402   SkipNode();
    403 }
    404 void CFX_SAXReader::ParseTagName() {
    405   if (m_CurByte < 0x21 || m_CurByte == '/' || m_CurByte == '>' ||
    406       m_CurByte == '?') {
    407     m_iDataLength = m_iDataPos;
    408     m_iDataPos = 0;
    409     if (m_pHandler) {
    410       NotifyEnter();
    411     }
    412     if (m_CurByte < 0x21) {
    413       m_eMode = FX_SAXMODE_TagAttributeName;
    414     } else if (m_CurByte == '/' || m_CurByte == '?') {
    415       m_ePrevMode = m_eMode;
    416       m_eMode = FX_SAXMODE_TagMaybeClose;
    417     } else {
    418       if (m_pHandler) {
    419         NotifyBreak();
    420       }
    421       m_eMode = FX_SAXMODE_Text;
    422     }
    423   } else {
    424     AppendData(m_CurByte);
    425   }
    426 }
    427 void CFX_SAXReader::ParseTagAttributeName() {
    428   if (m_CurByte < 0x21 || m_CurByte == '=') {
    429     if (m_iDataPos < 1 && m_CurByte < 0x21) {
    430       return;
    431     }
    432     m_iNameLength = m_iDataPos;
    433     m_iDataPos = 0;
    434     m_SkipChar = 0;
    435     m_eMode = m_CurByte == '=' ? FX_SAXMODE_TagAttributeValue
    436                                : FX_SAXMODE_TagAttributeEqual;
    437     return;
    438   }
    439   if (m_CurByte == '/' || m_CurByte == '>' || m_CurByte == '?') {
    440     if (m_CurByte == '/' || m_CurByte == '?') {
    441       m_ePrevMode = m_eMode;
    442       m_eMode = FX_SAXMODE_TagMaybeClose;
    443     } else {
    444       if (m_pHandler) {
    445         NotifyBreak();
    446       }
    447       m_eMode = FX_SAXMODE_Text;
    448     }
    449     return;
    450   }
    451   if (m_iDataPos < 1) {
    452     m_dwDataOffset = m_File.m_dwBufIndex;
    453   }
    454   AppendName(m_CurByte);
    455 }
    456 void CFX_SAXReader::ParseTagAttributeEqual() {
    457   if (m_CurByte == '=') {
    458     m_SkipChar = 0;
    459     m_eMode = FX_SAXMODE_TagAttributeValue;
    460     return;
    461   } else if (m_pCurItem->m_eNode == FX_SAXNODE_Instruction) {
    462     m_iDataPos = m_iNameLength;
    463     AppendName(0x20);
    464     m_eMode = FX_SAXMODE_TargetData;
    465     ParseTargetData();
    466   }
    467 }
    468 void CFX_SAXReader::ParseTagAttributeValue() {
    469   if (m_SkipChar) {
    470     if (m_SkipChar == m_CurByte) {
    471       {
    472         m_iDataLength = m_iDataPos;
    473         m_iDataPos = 0;
    474         if (m_pHandler) {
    475           NotifyAttribute();
    476         }
    477       }
    478       m_SkipChar = 0;
    479       m_eMode = FX_SAXMODE_TagAttributeName;
    480       return;
    481     }
    482     ParseChar(m_CurByte);
    483     return;
    484   }
    485   if (m_CurByte < 0x21) {
    486     return;
    487   }
    488   if (m_iDataPos < 1) {
    489     if (m_CurByte == '\'' || m_CurByte == '\"') {
    490       m_SkipChar = m_CurByte;
    491     }
    492   }
    493 }
    494 void CFX_SAXReader::ParseMaybeClose() {
    495   if (m_CurByte == '>') {
    496     if (m_pCurItem->m_eNode == FX_SAXNODE_Instruction) {
    497       m_iNameLength = m_iDataPos;
    498       m_iDataPos = 0;
    499       if (m_pHandler) {
    500         NotifyTargetData();
    501       }
    502     }
    503     ParseTagClose();
    504     m_eMode = FX_SAXMODE_Text;
    505   } else if (m_ePrevMode == FX_SAXMODE_TagName) {
    506     AppendData('/');
    507     m_eMode = FX_SAXMODE_TagName;
    508     m_ePrevMode = FX_SAXMODE_Text;
    509     ParseTagName();
    510   } else if (m_ePrevMode == FX_SAXMODE_TagAttributeName) {
    511     AppendName('/');
    512     m_eMode = FX_SAXMODE_TagAttributeName;
    513     m_ePrevMode = FX_SAXMODE_Text;
    514     ParseTagAttributeName();
    515   } else if (m_ePrevMode == FX_SAXMODE_TargetData) {
    516     AppendName('?');
    517     m_eMode = FX_SAXMODE_TargetData;
    518     m_ePrevMode = FX_SAXMODE_Text;
    519     ParseTargetData();
    520   }
    521 }
    522 void CFX_SAXReader::ParseTagClose() {
    523   m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex;
    524   if (m_pHandler) {
    525     NotifyClose();
    526   }
    527   Pop();
    528 }
    529 void CFX_SAXReader::ParseTagEnd() {
    530   if (m_CurByte < 0x21) {
    531     return;
    532   }
    533   if (m_CurByte == '>') {
    534     Pop();
    535     m_dwNodePos = m_File.m_dwCur + m_File.m_dwBufIndex;
    536     m_iDataLength = m_iDataPos;
    537     m_iDataPos = 0;
    538     if (m_pHandler) {
    539       NotifyEnd();
    540     }
    541     Pop();
    542     m_eMode = FX_SAXMODE_Text;
    543   } else {
    544     ParseChar(m_CurByte);
    545   }
    546 }
    547 void CFX_SAXReader::ParseTargetData() {
    548   if (m_CurByte == '?') {
    549     m_ePrevMode = m_eMode;
    550     m_eMode = FX_SAXMODE_TagMaybeClose;
    551   } else {
    552     AppendName(m_CurByte);
    553   }
    554 }
    555 void CFX_SAXReader::SkipNode() {
    556   int32_t iLen = m_SkipStack.GetSize();
    557   if (m_SkipChar == '\'' || m_SkipChar == '\"') {
    558     if (m_CurByte != m_SkipChar) {
    559       return;
    560     }
    561     iLen--;
    562     FXSYS_assert(iLen > -1);
    563     m_SkipStack.RemoveAt(iLen, 1);
    564     m_SkipChar = iLen ? m_SkipStack[iLen - 1] : 0;
    565     return;
    566   }
    567   switch (m_CurByte) {
    568     case '<':
    569       m_SkipChar = '>';
    570       m_SkipStack.Add('>');
    571       break;
    572     case '[':
    573       m_SkipChar = ']';
    574       m_SkipStack.Add(']');
    575       break;
    576     case '(':
    577       m_SkipChar = ')';
    578       m_SkipStack.Add(')');
    579       break;
    580     case '\'':
    581       m_SkipChar = '\'';
    582       m_SkipStack.Add('\'');
    583       break;
    584     case '\"':
    585       m_SkipChar = '\"';
    586       m_SkipStack.Add('\"');
    587       break;
    588     default:
    589       if (m_CurByte == m_SkipChar) {
    590         iLen--;
    591         m_SkipStack.RemoveAt(iLen, 1);
    592         m_SkipChar = iLen ? m_SkipStack[iLen - 1] : 0;
    593         if (iLen == 0 && m_CurByte == '>') {
    594           m_iDataLength = m_iDataPos;
    595           m_iDataPos = 0;
    596           if (m_iDataLength >= 9 &&
    597               FXSYS_memcmp(m_pszData, "[CDATA[", 7 * sizeof(uint8_t)) == 0 &&
    598               FXSYS_memcmp(m_pszData + m_iDataLength - 2, "]]",
    599                            2 * sizeof(uint8_t)) == 0) {
    600             Pop();
    601             m_iDataLength -= 9;
    602             m_dwDataOffset += 7;
    603             FXSYS_memmove(m_pszData, m_pszData + 7,
    604                           m_iDataLength * sizeof(uint8_t));
    605             m_bCharData = TRUE;
    606             if (m_pHandler) {
    607               NotifyData();
    608             }
    609             m_bCharData = FALSE;
    610           } else {
    611             Pop();
    612           }
    613           m_eMode = FX_SAXMODE_Text;
    614         }
    615       }
    616       break;
    617   }
    618   if (iLen > 0) {
    619     ParseChar(m_CurByte);
    620   }
    621 }
    622 void CFX_SAXReader::NotifyData() {
    623   FXSYS_assert(m_pHandler != NULL);
    624   if (m_pCurItem->m_eNode == FX_SAXNODE_Tag)
    625     m_pHandler->OnTagData(m_pCurItem->m_pNode,
    626                           m_bCharData ? FX_SAXNODE_CharData : FX_SAXNODE_Text,
    627                           CFX_ByteStringC(m_pszData, m_iDataLength),
    628                           m_File.m_dwCur + m_dwDataOffset);
    629 }
    630 void CFX_SAXReader::NotifyEnter() {
    631   FXSYS_assert(m_pHandler != NULL);
    632   if (m_pCurItem->m_eNode == FX_SAXNODE_Tag ||
    633       m_pCurItem->m_eNode == FX_SAXNODE_Instruction) {
    634     m_pCurItem->m_pNode =
    635         m_pHandler->OnTagEnter(CFX_ByteStringC(m_pszData, m_iDataLength),
    636                                m_pCurItem->m_eNode, m_dwNodePos);
    637   }
    638 }
    639 void CFX_SAXReader::NotifyAttribute() {
    640   FXSYS_assert(m_pHandler != NULL);
    641   if (m_pCurItem->m_eNode == FX_SAXNODE_Tag ||
    642       m_pCurItem->m_eNode == FX_SAXNODE_Instruction) {
    643     m_pHandler->OnTagAttribute(m_pCurItem->m_pNode,
    644                                CFX_ByteStringC(m_pszName, m_iNameLength),
    645                                CFX_ByteStringC(m_pszData, m_iDataLength));
    646   }
    647 }
    648 void CFX_SAXReader::NotifyBreak() {
    649   FXSYS_assert(m_pHandler != NULL);
    650   if (m_pCurItem->m_eNode == FX_SAXNODE_Tag) {
    651     m_pHandler->OnTagBreak(m_pCurItem->m_pNode);
    652   }
    653 }
    654 void CFX_SAXReader::NotifyClose() {
    655   FXSYS_assert(m_pHandler != NULL);
    656   if (m_pCurItem->m_eNode == FX_SAXNODE_Tag ||
    657       m_pCurItem->m_eNode == FX_SAXNODE_Instruction) {
    658     m_pHandler->OnTagClose(m_pCurItem->m_pNode, m_dwNodePos);
    659   }
    660 }
    661 void CFX_SAXReader::NotifyEnd() {
    662   FXSYS_assert(m_pHandler != NULL);
    663   if (m_pCurItem->m_eNode == FX_SAXNODE_Tag) {
    664     m_pHandler->OnTagEnd(m_pCurItem->m_pNode,
    665                          CFX_ByteStringC(m_pszData, m_iDataLength),
    666                          m_dwNodePos);
    667   }
    668 }
    669 void CFX_SAXReader::NotifyTargetData() {
    670   FXSYS_assert(m_pHandler != NULL);
    671   if (m_pCurItem->m_eNode == FX_SAXNODE_Instruction) {
    672     m_pHandler->OnTargetData(m_pCurItem->m_pNode, m_pCurItem->m_eNode,
    673                              CFX_ByteStringC(m_pszName, m_iNameLength),
    674                              m_dwNodePos);
    675   } else if (m_pCurItem->m_eNode == FX_SAXNODE_Comment) {
    676     m_pHandler->OnTargetData(m_pCurItem->m_pNode, m_pCurItem->m_eNode,
    677                              CFX_ByteStringC(m_pszData, m_iDataLength),
    678                              m_dwNodePos);
    679   }
    680 }
    681 void CFX_SAXReader::SkipCurrentNode() {
    682   if (!m_pCurItem) {
    683     return;
    684   }
    685   m_pCurItem->m_bSkip = TRUE;
    686 }
    687 void CFX_SAXReader::SetHandler(IFX_SAXReaderHandler* pHandler) {
    688   m_pHandler = pHandler;
    689 }
    690