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/foxitlib.h"
10#include "fde_xml.h"
11#ifdef __cplusplus
12extern "C" {
13#endif
14#define FDE_XMLVALIDCHARRANGENUM 5
15static FX_WCHAR g_XMLValidCharRange[FDE_XMLVALIDCHARRANGENUM][2] = {
16    {0x09, 0x09},
17    {0x0A, 0x0A},
18    {0x0D, 0x0D},
19    {0x20, 0xD7FF},
20    {0xE000, 0xFFFD}};
21FX_BOOL FDE_IsXMLValidChar(FX_WCHAR ch) {
22  int32_t iStart = 0, iEnd = FDE_XMLVALIDCHARRANGENUM - 1, iMid;
23  while (iStart <= iEnd) {
24    iMid = (iStart + iEnd) / 2;
25    if (ch < g_XMLValidCharRange[iMid][0]) {
26      iEnd = iMid - 1;
27    } else if (ch > g_XMLValidCharRange[iMid][1]) {
28      iStart = iMid + 1;
29    } else {
30      return TRUE;
31    }
32  }
33  return FALSE;
34}
35FX_BOOL FDE_IsXMLWhiteSpace(FX_WCHAR ch) {
36  return ch == L' ' || ch == 0x0A || ch == 0x0D || ch == 0x09;
37}
38typedef struct _FDE_XMLNAMECHAR {
39  FX_WCHAR wStart;
40  FX_WCHAR wEnd;
41  FX_BOOL bStartChar;
42} FDE_XMLNAMECHAR;
43#define FDE_XMLNAMECHARSNUM 20
44static FDE_XMLNAMECHAR g_XMLNameChars[FDE_XMLNAMECHARSNUM] = {
45    {L'-', L'.', FALSE},    {L'0', L'9', FALSE},     {L':', L':', FALSE},
46    {L'A', L'Z', TRUE},     {L'_', L'_', TRUE},      {L'a', L'z', TRUE},
47    {0xB7, 0xB7, FALSE},    {0xC0, 0xD6, TRUE},      {0xD8, 0xF6, TRUE},
48    {0xF8, 0x02FF, TRUE},   {0x0300, 0x036F, FALSE}, {0x0370, 0x037D, TRUE},
49    {0x037F, 0x1FFF, TRUE}, {0x200C, 0x200D, TRUE},  {0x203F, 0x2040, FALSE},
50    {0x2070, 0x218F, TRUE}, {0x2C00, 0x2FEF, TRUE},  {0x3001, 0xD7FF, TRUE},
51    {0xF900, 0xFDCF, TRUE}, {0xFDF0, 0xFFFD, TRUE},
52};
53FX_BOOL FDE_IsXMLNameChar(FX_WCHAR ch, FX_BOOL bFirstChar) {
54  int32_t iStart = 0, iEnd = FDE_XMLNAMECHARSNUM - 1, iMid;
55  while (iStart <= iEnd) {
56    iMid = (iStart + iEnd) / 2;
57    if (ch < g_XMLNameChars[iMid].wStart) {
58      iEnd = iMid - 1;
59    } else if (ch > g_XMLNameChars[iMid].wEnd) {
60      iStart = iMid + 1;
61    } else {
62      if (bFirstChar) {
63        return g_XMLNameChars[iMid].bStartChar;
64      }
65      return TRUE;
66    }
67  }
68  return FALSE;
69}
70#ifdef __cplusplus
71}
72#endif
73CFDE_XMLNode::CFDE_XMLNode()
74    : m_pParent(NULL), m_pChild(NULL), m_pPrior(NULL), m_pNext(NULL) {}
75CFDE_XMLNode::~CFDE_XMLNode() {
76  DeleteChildren();
77}
78void CFDE_XMLNode::DeleteChildren() {
79  CFDE_XMLNode *pChild = m_pChild, *pTemp;
80  while (pChild != NULL) {
81    pTemp = pChild->m_pNext;
82    pChild->Release();
83    pChild = pTemp;
84  }
85  m_pChild = NULL;
86}
87int32_t CFDE_XMLNode::CountChildNodes() const {
88  int32_t iCount = 0;
89  CFDE_XMLNode* pChild = m_pChild;
90  while (pChild != NULL) {
91    iCount++;
92    pChild = pChild->m_pNext;
93  }
94  return iCount;
95}
96CFDE_XMLNode* CFDE_XMLNode::GetChildNode(int32_t index) const {
97  CFDE_XMLNode* pChild = m_pChild;
98  while (pChild != NULL) {
99    if (index == 0) {
100      return pChild;
101    }
102    index--;
103    pChild = pChild->m_pNext;
104  }
105  return NULL;
106}
107int32_t CFDE_XMLNode::GetChildNodeIndex(CFDE_XMLNode* pNode) const {
108  int32_t index = 0;
109  CFDE_XMLNode* pChild = m_pChild;
110  while (pChild != NULL) {
111    if (pChild == pNode) {
112      return index;
113    }
114    index++;
115    pChild = pChild->m_pNext;
116  }
117  return -1;
118}
119CFDE_XMLNode* CFDE_XMLNode::GetPath(const FX_WCHAR* pPath,
120                                    int32_t iLength,
121                                    FX_BOOL bQualifiedName) const {
122  FXSYS_assert(pPath != NULL);
123  if (iLength < 0) {
124    iLength = FXSYS_wcslen(pPath);
125  }
126  if (iLength == 0) {
127    return NULL;
128  }
129  CFX_WideString csPath;
130  const FX_WCHAR* pStart = pPath;
131  const FX_WCHAR* pEnd = pPath + iLength;
132  FX_WCHAR ch;
133  while (pStart < pEnd) {
134    ch = *pStart++;
135    if (ch == L'/') {
136      break;
137    } else {
138      csPath += ch;
139    }
140  }
141  iLength -= pStart - pPath;
142  CFDE_XMLNode* pFind = NULL;
143  if (csPath.GetLength() < 1) {
144    pFind = GetNodeItem(IFDE_XMLNode::Root);
145  } else if (csPath.Compare(L"..") == 0) {
146    pFind = m_pParent;
147  } else if (csPath.Compare(L".") == 0) {
148    pFind = (CFDE_XMLNode*)this;
149  } else {
150    CFX_WideString wsTag;
151    CFDE_XMLNode* pNode = m_pChild;
152    while (pNode != NULL) {
153      if (pNode->GetType() == FDE_XMLNODE_Element) {
154        if (bQualifiedName) {
155          ((CFDE_XMLElement*)pNode)->GetTagName(wsTag);
156        } else {
157          ((CFDE_XMLElement*)pNode)->GetLocalTagName(wsTag);
158        }
159        if (wsTag.Compare(csPath) == 0) {
160          if (iLength < 1) {
161            pFind = pNode;
162          } else {
163            pFind = pNode->GetPath(pStart, iLength, bQualifiedName);
164          }
165          if (pFind != NULL) {
166            return pFind;
167          }
168        }
169      }
170      pNode = pNode->m_pNext;
171    }
172  }
173  if (pFind == NULL || iLength < 1) {
174    return pFind;
175  }
176  return pFind->GetPath(pStart, iLength, bQualifiedName);
177}
178int32_t CFDE_XMLNode::InsertChildNode(CFDE_XMLNode* pNode, int32_t index) {
179  FXSYS_assert(pNode != NULL);
180  pNode->m_pParent = this;
181  if (m_pChild == NULL) {
182    m_pChild = pNode;
183    pNode->m_pPrior = NULL;
184    pNode->m_pNext = NULL;
185    return 0;
186  } else if (index == 0) {
187    pNode->m_pNext = m_pChild;
188    pNode->m_pPrior = NULL;
189    m_pChild->m_pPrior = pNode;
190    m_pChild = pNode;
191    return 0;
192  }
193  int32_t iCount = 0;
194  CFDE_XMLNode* pFind = m_pChild;
195  while (++iCount != index && pFind->m_pNext != NULL) {
196    pFind = pFind->m_pNext;
197  }
198  pNode->m_pPrior = pFind;
199  pNode->m_pNext = pFind->m_pNext;
200  if (pFind->m_pNext != NULL) {
201    pFind->m_pNext->m_pPrior = pNode;
202  }
203  pFind->m_pNext = pNode;
204  return iCount;
205}
206void CFDE_XMLNode::RemoveChildNode(CFDE_XMLNode* pNode) {
207  FXSYS_assert(m_pChild != NULL && pNode != NULL);
208  if (m_pChild == pNode) {
209    m_pChild = pNode->m_pNext;
210  } else {
211    pNode->m_pPrior->m_pNext = pNode->m_pNext;
212  }
213  if (pNode->m_pNext != NULL) {
214    pNode->m_pNext->m_pPrior = pNode->m_pPrior;
215  }
216  pNode->m_pParent = NULL;
217  pNode->m_pNext = NULL;
218  pNode->m_pPrior = NULL;
219}
220CFDE_XMLNode* CFDE_XMLNode::GetNodeItem(IFDE_XMLNode::NodeItem eItem) const {
221  switch (eItem) {
222    case IFDE_XMLNode::Root: {
223      CFDE_XMLNode* pParent = (CFDE_XMLNode*)this;
224      while (pParent->m_pParent != NULL) {
225        pParent = pParent->m_pParent;
226      }
227      return pParent;
228    }
229    case IFDE_XMLNode::Parent:
230      return m_pParent;
231    case IFDE_XMLNode::FirstSibling: {
232      CFDE_XMLNode* pItem = (CFDE_XMLNode*)this;
233      while (pItem->m_pPrior != NULL) {
234        pItem = pItem->m_pPrior;
235      }
236      return pItem == (CFDE_XMLNode*)this ? NULL : pItem;
237    }
238    case IFDE_XMLNode::PriorSibling:
239      return m_pPrior;
240    case IFDE_XMLNode::NextSibling:
241      return m_pNext;
242    case IFDE_XMLNode::LastSibling: {
243      CFDE_XMLNode* pItem = (CFDE_XMLNode*)this;
244      while (pItem->m_pNext != NULL) {
245        pItem = pItem->m_pNext;
246      }
247      return pItem == (CFDE_XMLNode*)this ? NULL : pItem;
248    }
249    case IFDE_XMLNode::FirstNeighbor: {
250      CFDE_XMLNode* pParent = (CFDE_XMLNode*)this;
251      while (pParent->m_pParent != NULL) {
252        pParent = pParent->m_pParent;
253      }
254      return pParent == (CFDE_XMLNode*)this ? NULL : pParent;
255    }
256    case IFDE_XMLNode::PriorNeighbor: {
257      if (m_pPrior == NULL) {
258        return m_pParent;
259      }
260      CFDE_XMLNode* pItem = m_pPrior;
261      while (CFDE_XMLNode* pTemp = pItem->m_pChild) {
262        pItem = pTemp;
263        while ((pTemp = pItem->m_pNext) != NULL) {
264          pItem = pTemp;
265        }
266      }
267      return pItem;
268    }
269    case IFDE_XMLNode::NextNeighbor: {
270      if (m_pChild != NULL) {
271        return m_pChild;
272      }
273      if (m_pNext != NULL) {
274        return m_pNext;
275      }
276      CFDE_XMLNode* pItem = m_pParent;
277      while (pItem != NULL) {
278        if (pItem->m_pNext != NULL) {
279          return pItem->m_pNext;
280        }
281        pItem = pItem->m_pParent;
282      }
283      return NULL;
284    }
285    case IFDE_XMLNode::LastNeighbor: {
286      CFDE_XMLNode* pItem = (CFDE_XMLNode*)this;
287      while (pItem->m_pParent != NULL) {
288        pItem = pItem->m_pParent;
289      }
290      while (TRUE) {
291        while (pItem->m_pNext != NULL) {
292          pItem = pItem->m_pNext;
293        }
294        if (pItem->m_pChild == NULL) {
295          break;
296        }
297        pItem = pItem->m_pChild;
298      }
299      return pItem == (CFDE_XMLNode*)this ? NULL : pItem;
300    }
301    case IFDE_XMLNode::FirstChild:
302      return m_pChild;
303    case IFDE_XMLNode::LastChild: {
304      if (m_pChild == NULL) {
305        return NULL;
306      }
307      CFDE_XMLNode* pChild = m_pChild;
308      while (pChild->m_pNext != NULL) {
309        pChild = pChild->m_pNext;
310      }
311      return pChild;
312    }
313    default:
314      break;
315  }
316  return NULL;
317}
318int32_t CFDE_XMLNode::GetNodeLevel() const {
319  int32_t iLevel = 0;
320  CFDE_XMLNode* pItem = (CFDE_XMLNode*)this;
321  while ((pItem = pItem->m_pParent) != NULL) {
322    iLevel++;
323  }
324  return iLevel;
325}
326FX_BOOL CFDE_XMLNode::InsertNodeItem(IFDE_XMLNode::NodeItem eItem,
327                                     CFDE_XMLNode* pNode) {
328  FXSYS_assert(pNode != NULL);
329  switch (eItem) {
330    case IFDE_XMLNode::NextSibling: {
331      pNode->m_pParent = m_pParent;
332      pNode->m_pNext = m_pNext;
333      pNode->m_pPrior = this;
334      if (m_pNext) {
335        m_pNext->m_pPrior = pNode;
336      }
337      m_pNext = pNode;
338      return TRUE;
339    }
340    case IFDE_XMLNode::PriorSibling: {
341      pNode->m_pParent = m_pParent;
342      pNode->m_pNext = this;
343      pNode->m_pPrior = m_pPrior;
344      if (m_pPrior) {
345        m_pPrior->m_pNext = pNode;
346      } else if (m_pParent) {
347        m_pParent->m_pChild = pNode;
348      }
349      m_pPrior = pNode;
350      return TRUE;
351    }
352    default:
353      return FALSE;
354  }
355  return FALSE;
356}
357CFDE_XMLNode* CFDE_XMLNode::RemoveNodeItem(IFDE_XMLNode::NodeItem eItem) {
358  CFDE_XMLNode* pNode = NULL;
359  switch (eItem) {
360    case IFDE_XMLNode::NextSibling:
361      if (m_pNext) {
362        pNode = m_pNext;
363        m_pNext = pNode->m_pNext;
364        if (m_pNext) {
365          m_pNext->m_pPrior = this;
366        }
367        pNode->m_pParent = NULL;
368        pNode->m_pNext = NULL;
369        pNode->m_pPrior = NULL;
370      }
371      break;
372    default:
373      break;
374  }
375  return pNode;
376}
377CFDE_XMLNode* CFDE_XMLNode::Clone(FX_BOOL bRecursive) {
378  return NULL;
379}
380void CFDE_XMLNode::SaveXMLNode(IFX_Stream* pXMLStream) {
381  CFDE_XMLNode* pNode = (CFDE_XMLNode*)this;
382  FXSYS_assert(pXMLStream != NULL && pNode != NULL);
383  switch (pNode->GetType()) {
384    case FDE_XMLNODE_Instruction: {
385      CFX_WideString ws;
386      CFDE_XMLInstruction* pInstruction = (CFDE_XMLInstruction*)pNode;
387      if (pInstruction->m_wsTarget.CompareNoCase(L"xml") == 0) {
388        ws = L"<?xml version=\"1.0\" encoding=\"";
389        FX_WORD wCodePage = pXMLStream->GetCodePage();
390        if (wCodePage == FX_CODEPAGE_UTF16LE) {
391          ws += L"UTF-16";
392        } else if (wCodePage == FX_CODEPAGE_UTF16BE) {
393          ws += L"UTF-16be";
394        } else {
395          ws += L"UTF-8";
396        }
397        ws += L"\"?>";
398        pXMLStream->WriteString(ws, ws.GetLength());
399      } else {
400        ws.Format(L"<?%s", (const FX_WCHAR*)pInstruction->m_wsTarget);
401        pXMLStream->WriteString(ws, ws.GetLength());
402        CFX_WideStringArray& attributes = pInstruction->m_Attributes;
403        int32_t i, iCount = attributes.GetSize();
404        CFX_WideString wsValue;
405        for (i = 0; i < iCount; i += 2) {
406          ws = L" ";
407          ws += attributes[i];
408          ws += L"=\"";
409          wsValue = attributes[i + 1];
410          wsValue.Replace(L"&", L"&amp;");
411          wsValue.Replace(L"<", L"&lt;");
412          wsValue.Replace(L">", L"&gt;");
413          wsValue.Replace(L"\'", L"&apos;");
414          wsValue.Replace(L"\"", L"&quot;");
415          ws += wsValue;
416          ws += L"\"";
417          pXMLStream->WriteString(ws, ws.GetLength());
418        }
419        CFX_WideStringArray& targetdata = pInstruction->m_TargetData;
420        iCount = targetdata.GetSize();
421        for (i = 0; i < iCount; i++) {
422          ws = L" \"";
423          ws += targetdata[i];
424          ws += L"\"";
425          pXMLStream->WriteString(ws, ws.GetLength());
426        }
427        ws = L"?>";
428        pXMLStream->WriteString(ws, ws.GetLength());
429      }
430    } break;
431    case FDE_XMLNODE_Element: {
432      CFX_WideString ws;
433      ws = L"<";
434      ws += ((CFDE_XMLElement*)pNode)->m_wsTag;
435      pXMLStream->WriteString(ws, ws.GetLength());
436      CFX_WideStringArray& attributes = ((CFDE_XMLElement*)pNode)->m_Attributes;
437      int32_t iCount = attributes.GetSize();
438      CFX_WideString wsValue;
439      for (int32_t i = 0; i < iCount; i += 2) {
440        ws = L" ";
441        ws += attributes[i];
442        ws += L"=\"";
443        wsValue = attributes[i + 1];
444        wsValue.Replace(L"&", L"&amp;");
445        wsValue.Replace(L"<", L"&lt;");
446        wsValue.Replace(L">", L"&gt;");
447        wsValue.Replace(L"\'", L"&apos;");
448        wsValue.Replace(L"\"", L"&quot;");
449        ws += wsValue;
450        ws += L"\"";
451        pXMLStream->WriteString(ws, ws.GetLength());
452      }
453      if (pNode->m_pChild == NULL) {
454        ws = L"\n/>";
455        pXMLStream->WriteString(ws, ws.GetLength());
456      } else {
457        ws = L"\n>";
458        pXMLStream->WriteString(ws, ws.GetLength());
459        CFDE_XMLNode* pChild = pNode->m_pChild;
460        while (pChild != NULL) {
461          pChild->SaveXMLNode(pXMLStream);
462          pChild = pChild->m_pNext;
463        }
464        ws = L"</";
465        ws += ((CFDE_XMLElement*)pNode)->m_wsTag;
466        ws += L"\n>";
467        pXMLStream->WriteString(ws, ws.GetLength());
468      }
469    } break;
470    case FDE_XMLNODE_Text: {
471      CFX_WideString ws = ((CFDE_XMLText*)pNode)->m_wsText;
472      ws.Replace(L"&", L"&amp;");
473      ws.Replace(L"<", L"&lt;");
474      ws.Replace(L">", L"&gt;");
475      ws.Replace(L"\'", L"&apos;");
476      ws.Replace(L"\"", L"&quot;");
477      pXMLStream->WriteString(ws, ws.GetLength());
478    } break;
479    case FDE_XMLNODE_CharData: {
480      CFX_WideString ws = L"<![CDATA[";
481      ws += ((CFDE_XMLCharData*)pNode)->m_wsCharData;
482      ws += L"]]>";
483      pXMLStream->WriteString(ws, ws.GetLength());
484    } break;
485    case FDE_XMLNODE_Unknown:
486      break;
487    default:
488      break;
489  }
490}
491void CFDE_XMLNode::CloneChildren(CFDE_XMLNode* pClone) {
492  if (!m_pChild) {
493    return;
494  }
495  CFDE_XMLNode* pNext = m_pChild;
496  CFDE_XMLNode* pCloneNext = pNext->Clone(TRUE);
497  pClone->InsertChildNode(pCloneNext);
498  pNext = pNext->m_pNext;
499  while (pNext) {
500    CFDE_XMLNode* pChild = pNext->Clone(TRUE);
501    pCloneNext->InsertNodeItem(IFDE_XMLNode::NextSibling, pChild);
502    pCloneNext = pChild;
503    pNext = pNext->m_pNext;
504  }
505}
506IFDE_XMLInstruction* IFDE_XMLInstruction::Create(
507    const CFX_WideString& wsTarget) {
508  return (IFDE_XMLInstruction*)new CFDE_XMLInstruction(wsTarget);
509}
510CFDE_XMLInstruction::CFDE_XMLInstruction(const CFX_WideString& wsTarget)
511    : m_wsTarget(wsTarget) {
512  FXSYS_assert(m_wsTarget.GetLength() > 0);
513}
514CFDE_XMLNode* CFDE_XMLInstruction::Clone(FX_BOOL bRecursive) {
515  CFDE_XMLInstruction* pClone = new CFDE_XMLInstruction(m_wsTarget);
516  if (!pClone) {
517    return pClone;
518  }
519  pClone->m_Attributes.Copy(m_Attributes);
520  pClone->m_TargetData.Copy(m_TargetData);
521  if (bRecursive) {
522    CloneChildren(pClone);
523  }
524  return pClone;
525}
526int32_t CFDE_XMLInstruction::CountAttributes() const {
527  return m_Attributes.GetSize() / 2;
528}
529FX_BOOL CFDE_XMLInstruction::GetAttribute(int32_t index,
530                                          CFX_WideString& wsAttriName,
531                                          CFX_WideString& wsAttriValue) const {
532  int32_t iCount = m_Attributes.GetSize();
533  FXSYS_assert(index > -1 && index < iCount / 2);
534  for (int32_t i = 0; i < iCount; i += 2) {
535    if (index == 0) {
536      wsAttriName = m_Attributes[i];
537      wsAttriValue = m_Attributes[i + 1];
538      return TRUE;
539    }
540    index--;
541  }
542  return FALSE;
543}
544FX_BOOL CFDE_XMLInstruction::HasAttribute(const FX_WCHAR* pwsAttriName) const {
545  int32_t iCount = m_Attributes.GetSize();
546  for (int32_t i = 0; i < iCount; i += 2) {
547    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
548      return TRUE;
549    }
550  }
551  return FALSE;
552}
553void CFDE_XMLInstruction::GetString(const FX_WCHAR* pwsAttriName,
554                                    CFX_WideString& wsAttriValue,
555                                    const FX_WCHAR* pwsDefValue) const {
556  int32_t iCount = m_Attributes.GetSize();
557  for (int32_t i = 0; i < iCount; i += 2) {
558    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
559      wsAttriValue = m_Attributes[i + 1];
560      return;
561    }
562  }
563  wsAttriValue = pwsDefValue;
564}
565void CFDE_XMLInstruction::SetString(const CFX_WideString& wsAttriName,
566                                    const CFX_WideString& wsAttriValue) {
567  FXSYS_assert(wsAttriName.GetLength() > 0);
568  int32_t iCount = m_Attributes.GetSize();
569  for (int32_t i = 0; i < iCount; i += 2) {
570    if (m_Attributes[i].Compare(wsAttriName) == 0) {
571      m_Attributes[i] = wsAttriName;
572      m_Attributes[i + 1] = wsAttriValue;
573      return;
574    }
575  }
576  m_Attributes.Add(wsAttriName);
577  m_Attributes.Add(wsAttriValue);
578}
579int32_t CFDE_XMLInstruction::GetInteger(const FX_WCHAR* pwsAttriName,
580                                        int32_t iDefValue) const {
581  int32_t iCount = m_Attributes.GetSize();
582  for (int32_t i = 0; i < iCount; i += 2) {
583    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
584      return FXSYS_wtoi((const FX_WCHAR*)m_Attributes[i + 1]);
585    }
586  }
587  return iDefValue;
588}
589void CFDE_XMLInstruction::SetInteger(const FX_WCHAR* pwsAttriName,
590                                     int32_t iAttriValue) {
591  CFX_WideString wsValue;
592  wsValue.Format(L"%d", iAttriValue);
593  SetString(pwsAttriName, wsValue);
594}
595FX_FLOAT CFDE_XMLInstruction::GetFloat(const FX_WCHAR* pwsAttriName,
596                                       FX_FLOAT fDefValue) const {
597  int32_t iCount = m_Attributes.GetSize();
598  for (int32_t i = 0; i < iCount; i += 2) {
599    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
600      return FX_wcstof((const FX_WCHAR*)m_Attributes[i + 1]);
601    }
602  }
603  return fDefValue;
604}
605void CFDE_XMLInstruction::SetFloat(const FX_WCHAR* pwsAttriName,
606                                   FX_FLOAT fAttriValue) {
607  CFX_WideString wsValue;
608  wsValue.Format(L"%f", fAttriValue);
609  SetString(pwsAttriName, wsValue);
610}
611void CFDE_XMLInstruction::RemoveAttribute(const FX_WCHAR* pwsAttriName) {
612  int32_t iCount = m_Attributes.GetSize();
613  for (int32_t i = 0; i < iCount; i += 2) {
614    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
615      m_Attributes.RemoveAt(i + 1);
616      m_Attributes.RemoveAt(i);
617      return;
618    }
619  }
620}
621int32_t CFDE_XMLInstruction::CountData() const {
622  return m_TargetData.GetSize();
623}
624FX_BOOL CFDE_XMLInstruction::GetData(int32_t index,
625                                     CFX_WideString& wsData) const {
626  if (index < 0 || index >= m_TargetData.GetSize()) {
627    return FALSE;
628  }
629  wsData = m_TargetData[index];
630  return TRUE;
631}
632void CFDE_XMLInstruction::AppendData(const CFX_WideString& wsData) {
633  m_TargetData.Add(wsData);
634}
635void CFDE_XMLInstruction::RemoveData(int32_t index) {
636  m_TargetData.RemoveAt(index);
637}
638IFDE_XMLElement* IFDE_XMLElement::Create(const CFX_WideString& wsTag) {
639  return (IFDE_XMLElement*)new CFDE_XMLElement(wsTag);
640}
641CFDE_XMLElement::CFDE_XMLElement(const CFX_WideString& wsTag)
642    : CFDE_XMLNode(), m_wsTag(wsTag), m_Attributes() {
643  FXSYS_assert(m_wsTag.GetLength() > 0);
644}
645CFDE_XMLElement::~CFDE_XMLElement() {
646  m_Attributes.RemoveAll();
647}
648CFDE_XMLNode* CFDE_XMLElement::Clone(FX_BOOL bRecursive) {
649  CFDE_XMLElement* pClone = new CFDE_XMLElement(m_wsTag);
650  if (!pClone) {
651    return NULL;
652  }
653  pClone->m_Attributes.Copy(m_Attributes);
654  if (bRecursive) {
655    CloneChildren(pClone);
656  } else {
657    CFX_WideString wsText;
658    CFDE_XMLNode* pChild = m_pChild;
659    while (pChild != NULL) {
660      switch (pChild->GetType()) {
661        case FDE_XMLNODE_Text:
662          wsText += ((CFDE_XMLText*)pChild)->m_wsText;
663          break;
664        default:
665          break;
666      }
667      pChild = pChild->m_pNext;
668    }
669    pClone->SetTextData(wsText);
670  }
671  return pClone;
672}
673void CFDE_XMLElement::GetTagName(CFX_WideString& wsTag) const {
674  wsTag = m_wsTag;
675}
676void CFDE_XMLElement::GetLocalTagName(CFX_WideString& wsTag) const {
677  FX_STRSIZE iFind = m_wsTag.Find(L':', 0);
678  if (iFind < 0) {
679    wsTag = m_wsTag;
680  } else {
681    wsTag = m_wsTag.Right(m_wsTag.GetLength() - iFind - 1);
682  }
683}
684void CFDE_XMLElement::GetNamespacePrefix(CFX_WideString& wsPrefix) const {
685  FX_STRSIZE iFind = m_wsTag.Find(L':', 0);
686  if (iFind < 0) {
687    wsPrefix.Empty();
688  } else {
689    wsPrefix = m_wsTag.Left(iFind);
690  }
691}
692void CFDE_XMLElement::GetNamespaceURI(CFX_WideString& wsNamespace) const {
693  CFX_WideString wsAttri(L"xmlns"), wsPrefix;
694  GetNamespacePrefix(wsPrefix);
695  if (wsPrefix.GetLength() > 0) {
696    wsAttri += L":";
697    wsAttri += wsPrefix;
698  }
699  wsNamespace.Empty();
700  CFDE_XMLNode* pNode = (CFDE_XMLNode*)this;
701  while (pNode != NULL) {
702    if (pNode->GetType() != FDE_XMLNODE_Element) {
703      break;
704    }
705    CFDE_XMLElement* pElement = (CFDE_XMLElement*)pNode;
706    if (!pElement->HasAttribute(wsAttri)) {
707      pNode = pNode->GetNodeItem(IFDE_XMLNode::Parent);
708      continue;
709    }
710    pElement->GetString(wsAttri, wsNamespace);
711    break;
712  }
713}
714int32_t CFDE_XMLElement::CountAttributes() const {
715  return m_Attributes.GetSize() / 2;
716}
717FX_BOOL CFDE_XMLElement::GetAttribute(int32_t index,
718                                      CFX_WideString& wsAttriName,
719                                      CFX_WideString& wsAttriValue) const {
720  int32_t iCount = m_Attributes.GetSize();
721  FXSYS_assert(index > -1 && index < iCount / 2);
722  for (int32_t i = 0; i < iCount; i += 2) {
723    if (index == 0) {
724      wsAttriName = m_Attributes[i];
725      wsAttriValue = m_Attributes[i + 1];
726      return TRUE;
727    }
728    index--;
729  }
730  return FALSE;
731}
732FX_BOOL CFDE_XMLElement::HasAttribute(const FX_WCHAR* pwsAttriName) const {
733  int32_t iCount = m_Attributes.GetSize();
734  for (int32_t i = 0; i < iCount; i += 2) {
735    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
736      return TRUE;
737    }
738  }
739  return FALSE;
740}
741void CFDE_XMLElement::GetString(const FX_WCHAR* pwsAttriName,
742                                CFX_WideString& wsAttriValue,
743                                const FX_WCHAR* pwsDefValue) const {
744  int32_t iCount = m_Attributes.GetSize();
745  for (int32_t i = 0; i < iCount; i += 2) {
746    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
747      wsAttriValue = m_Attributes[i + 1];
748      return;
749    }
750  }
751  wsAttriValue = pwsDefValue;
752}
753void CFDE_XMLElement::SetString(const CFX_WideString& wsAttriName,
754                                const CFX_WideString& wsAttriValue) {
755  FXSYS_assert(wsAttriName.GetLength() > 0);
756  int32_t iCount = m_Attributes.GetSize();
757  for (int32_t i = 0; i < iCount; i += 2) {
758    if (m_Attributes[i].Compare(wsAttriName) == 0) {
759      m_Attributes[i] = wsAttriName;
760      m_Attributes[i + 1] = wsAttriValue;
761      return;
762    }
763  }
764  m_Attributes.Add(wsAttriName);
765  m_Attributes.Add(wsAttriValue);
766}
767int32_t CFDE_XMLElement::GetInteger(const FX_WCHAR* pwsAttriName,
768                                    int32_t iDefValue) const {
769  int32_t iCount = m_Attributes.GetSize();
770  for (int32_t i = 0; i < iCount; i += 2) {
771    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
772      return FXSYS_wtoi((const FX_WCHAR*)m_Attributes[i + 1]);
773    }
774  }
775  return iDefValue;
776}
777void CFDE_XMLElement::SetInteger(const FX_WCHAR* pwsAttriName,
778                                 int32_t iAttriValue) {
779  CFX_WideString wsValue;
780  wsValue.Format(L"%d", iAttriValue);
781  SetString(pwsAttriName, wsValue);
782}
783FX_FLOAT CFDE_XMLElement::GetFloat(const FX_WCHAR* pwsAttriName,
784                                   FX_FLOAT fDefValue) const {
785  int32_t iCount = m_Attributes.GetSize();
786  for (int32_t i = 0; i < iCount; i += 2) {
787    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
788      return FX_wcstof((const FX_WCHAR*)m_Attributes[i + 1]);
789    }
790  }
791  return fDefValue;
792}
793void CFDE_XMLElement::SetFloat(const FX_WCHAR* pwsAttriName,
794                               FX_FLOAT fAttriValue) {
795  CFX_WideString wsValue;
796  wsValue.Format(L"%f", fAttriValue);
797  SetString(pwsAttriName, wsValue);
798}
799void CFDE_XMLElement::RemoveAttribute(const FX_WCHAR* pwsAttriName) {
800  int32_t iCount = m_Attributes.GetSize();
801  for (int32_t i = 0; i < iCount; i += 2) {
802    if (m_Attributes[i].Compare(pwsAttriName) == 0) {
803      m_Attributes.RemoveAt(i + 1);
804      m_Attributes.RemoveAt(i);
805      return;
806    }
807  }
808}
809void CFDE_XMLElement::GetTextData(CFX_WideString& wsText) const {
810  CFX_WideTextBuf buffer;
811  CFDE_XMLNode* pChild = m_pChild;
812  while (pChild != NULL) {
813    switch (pChild->GetType()) {
814      case FDE_XMLNODE_Text:
815        buffer << ((CFDE_XMLText*)pChild)->m_wsText;
816        break;
817      case FDE_XMLNODE_CharData:
818        buffer << ((CFDE_XMLCharData*)pChild)->m_wsCharData;
819        break;
820      default:
821        break;
822    }
823    pChild = pChild->m_pNext;
824  }
825  wsText = buffer.GetWideString();
826}
827void CFDE_XMLElement::SetTextData(const CFX_WideString& wsText) {
828  if (wsText.GetLength() < 1) {
829    return;
830  }
831  InsertChildNode(new CFDE_XMLText(wsText));
832}
833IFDE_XMLText* IFDE_XMLText::Create(const CFX_WideString& wsText) {
834  return (IFDE_XMLText*)new CFDE_XMLText(wsText);
835}
836CFDE_XMLText::CFDE_XMLText(const CFX_WideString& wsText)
837    : CFDE_XMLNode(), m_wsText(wsText) {}
838CFDE_XMLNode* CFDE_XMLText::Clone(FX_BOOL bRecursive) {
839  CFDE_XMLText* pClone = new CFDE_XMLText(m_wsText);
840  return pClone;
841}
842IFDE_XMLCharData* IFDE_XMLCharData::Create(const CFX_WideString& wsCData) {
843  return (IFDE_XMLCharData*)new CFDE_XMLCharData(wsCData);
844}
845CFDE_XMLCharData::CFDE_XMLCharData(const CFX_WideString& wsCData)
846    : CFDE_XMLDeclaration(), m_wsCharData(wsCData) {}
847CFDE_XMLNode* CFDE_XMLCharData::Clone(FX_BOOL bRecursive) {
848  CFDE_XMLCharData* pClone = new CFDE_XMLCharData(m_wsCharData);
849  return pClone;
850}
851IFDE_XMLDoc* IFDE_XMLDoc::Create() {
852  return (IFDE_XMLDoc*)new CFDE_XMLDoc;
853}
854CFDE_XMLDoc::CFDE_XMLDoc()
855    : m_pRoot(NULL), m_pSyntaxParser(NULL), m_pXMLParser(NULL) {
856  Reset(TRUE);
857  CFDE_XMLInstruction* pXML = new CFDE_XMLInstruction(L"xml");
858  m_pRoot->InsertChildNode(pXML);
859}
860CFDE_XMLDoc::~CFDE_XMLDoc() {
861  Reset(FALSE);
862}
863void CFDE_XMLDoc::Reset(FX_BOOL bInitRoot) {
864  m_iStatus = 0;
865  m_pStream = NULL;
866  if (bInitRoot) {
867    if (m_pRoot == NULL) {
868      m_pRoot = new CFDE_XMLNode;
869    } else {
870      m_pRoot->DeleteChildren();
871    }
872  } else {
873    if (m_pRoot != NULL) {
874      m_pRoot->Release();
875      m_pRoot = NULL;
876    }
877  }
878  ReleaseParser();
879}
880void CFDE_XMLDoc::ReleaseParser() {
881  if (m_pXMLParser != NULL) {
882    m_pXMLParser->Release();
883    m_pXMLParser = NULL;
884  }
885  if (m_pSyntaxParser != NULL) {
886    m_pSyntaxParser->Release();
887    m_pSyntaxParser = NULL;
888  }
889}
890FX_BOOL CFDE_XMLDoc::LoadXML(IFX_Stream* pXMLStream,
891                             int32_t iXMLPlaneSize,
892                             int32_t iTextDataSize,
893                             FDE_LPXMLREADERHANDLER pHandler) {
894  if (pXMLStream == NULL) {
895    return FALSE;
896  }
897  Reset(TRUE);
898  iXMLPlaneSize = iXMLPlaneSize / 1024;
899  if (iXMLPlaneSize < 1) {
900    iXMLPlaneSize = 1;
901  }
902  iXMLPlaneSize *= 1024;
903  if (iXMLPlaneSize < 4096) {
904    iXMLPlaneSize = 4096;
905  }
906  iTextDataSize = iTextDataSize / 128;
907  if (iTextDataSize < 1) {
908    iTextDataSize = 1;
909  }
910  iTextDataSize *= 128;
911  if (iTextDataSize < 128) {
912    iTextDataSize = 128;
913  }
914  m_pStream = pXMLStream;
915  FX_WORD wCodePage = m_pStream->GetCodePage();
916  if (wCodePage != FX_CODEPAGE_UTF16LE && wCodePage != FX_CODEPAGE_UTF16BE &&
917      wCodePage != FX_CODEPAGE_UTF8) {
918    m_pStream->SetCodePage(FX_CODEPAGE_UTF8);
919  }
920  m_pSyntaxParser = IFDE_XMLSyntaxParser::Create();
921  if (m_pSyntaxParser == NULL) {
922    return FALSE;
923  }
924  m_pSyntaxParser->Init(m_pStream, iXMLPlaneSize, iTextDataSize);
925  if (pHandler == NULL) {
926    m_pXMLParser = new CFDE_XMLDOMParser(m_pRoot, m_pSyntaxParser);
927  } else {
928    m_pXMLParser = new CFDE_XMLSAXParser(pHandler, m_pSyntaxParser);
929  }
930  return TRUE;
931}
932FX_BOOL CFDE_XMLDoc::LoadXML(IFDE_XMLParser* pXMLParser) {
933  if (pXMLParser == NULL) {
934    return FALSE;
935  }
936  Reset(TRUE);
937  m_pXMLParser = pXMLParser;
938  return m_pXMLParser != NULL;
939}
940int32_t CFDE_XMLDoc::DoLoad(IFX_Pause* pPause) {
941  if (m_iStatus >= 100) {
942    return m_iStatus;
943  }
944  FXSYS_assert(m_pXMLParser != NULL);
945  return m_iStatus = m_pXMLParser->DoParser(pPause);
946}
947void CFDE_XMLDoc::CloseXML() {
948  ReleaseParser();
949}
950void CFDE_XMLDoc::SaveXMLNode(IFX_Stream* pXMLStream, IFDE_XMLNode* pINode) {
951  CFDE_XMLNode* pNode = (CFDE_XMLNode*)pINode;
952  FXSYS_assert(pXMLStream != NULL && pNode != NULL);
953  switch (pNode->GetType()) {
954    case FDE_XMLNODE_Instruction: {
955      CFX_WideString ws;
956      CFDE_XMLInstruction* pInstruction = (CFDE_XMLInstruction*)pNode;
957      if (pInstruction->m_wsTarget.CompareNoCase(L"xml") == 0) {
958        ws = L"<?xml version=\"1.0\" encoding=\"";
959        FX_WORD wCodePage = pXMLStream->GetCodePage();
960        if (wCodePage == FX_CODEPAGE_UTF16LE) {
961          ws += L"UTF-16";
962        } else if (wCodePage == FX_CODEPAGE_UTF16BE) {
963          ws += L"UTF-16be";
964        } else {
965          ws += L"UTF-8";
966        }
967        ws += L"\"?>";
968        pXMLStream->WriteString(ws, ws.GetLength());
969      } else {
970        ws.Format(L"<?%s", (const FX_WCHAR*)pInstruction->m_wsTarget);
971        pXMLStream->WriteString(ws, ws.GetLength());
972        CFX_WideStringArray& attributes = pInstruction->m_Attributes;
973        int32_t i, iCount = attributes.GetSize();
974        CFX_WideString wsValue;
975        for (i = 0; i < iCount; i += 2) {
976          ws = L" ";
977          ws += attributes[i];
978          ws += L"=\"";
979          wsValue = attributes[i + 1];
980          wsValue.Replace(L"&", L"&amp;");
981          wsValue.Replace(L"<", L"&lt;");
982          wsValue.Replace(L">", L"&gt;");
983          wsValue.Replace(L"\'", L"&apos;");
984          wsValue.Replace(L"\"", L"&quot;");
985          ws += wsValue;
986          ws += L"\"";
987          pXMLStream->WriteString(ws, ws.GetLength());
988        }
989        CFX_WideStringArray& targetdata = pInstruction->m_TargetData;
990        iCount = targetdata.GetSize();
991        for (i = 0; i < iCount; i++) {
992          ws = L" \"";
993          ws += targetdata[i];
994          ws += L"\"";
995          pXMLStream->WriteString(ws, ws.GetLength());
996        }
997        ws = L"?>";
998        pXMLStream->WriteString(ws, ws.GetLength());
999      }
1000    } break;
1001    case FDE_XMLNODE_Element: {
1002      CFX_WideString ws;
1003      ws = L"<";
1004      ws += ((CFDE_XMLElement*)pNode)->m_wsTag;
1005      pXMLStream->WriteString(ws, ws.GetLength());
1006      CFX_WideStringArray& attributes = ((CFDE_XMLElement*)pNode)->m_Attributes;
1007      int32_t iCount = attributes.GetSize();
1008      CFX_WideString wsValue;
1009      for (int32_t i = 0; i < iCount; i += 2) {
1010        ws = L" ";
1011        ws += attributes[i];
1012        ws += L"=\"";
1013        wsValue = attributes[i + 1];
1014        wsValue.Replace(L"&", L"&amp;");
1015        wsValue.Replace(L"<", L"&lt;");
1016        wsValue.Replace(L">", L"&gt;");
1017        wsValue.Replace(L"\'", L"&apos;");
1018        wsValue.Replace(L"\"", L"&quot;");
1019        ws += wsValue;
1020        ws += L"\"";
1021        pXMLStream->WriteString(ws, ws.GetLength());
1022      }
1023      if (pNode->m_pChild == NULL) {
1024        ws = L"\n/>";
1025        pXMLStream->WriteString(ws, ws.GetLength());
1026      } else {
1027        ws = L"\n>";
1028        pXMLStream->WriteString(ws, ws.GetLength());
1029        CFDE_XMLNode* pChild = pNode->m_pChild;
1030        while (pChild != NULL) {
1031          SaveXMLNode(pXMLStream, (IFDE_XMLNode*)pChild);
1032          pChild = pChild->m_pNext;
1033        }
1034        ws = L"</";
1035        ws += ((CFDE_XMLElement*)pNode)->m_wsTag;
1036        ws += L"\n>";
1037        pXMLStream->WriteString(ws, ws.GetLength());
1038      }
1039    } break;
1040    case FDE_XMLNODE_Text: {
1041      CFX_WideString ws = ((CFDE_XMLText*)pNode)->m_wsText;
1042      ws.Replace(L"&", L"&amp;");
1043      ws.Replace(L"<", L"&lt;");
1044      ws.Replace(L">", L"&gt;");
1045      ws.Replace(L"\'", L"&apos;");
1046      ws.Replace(L"\"", L"&quot;");
1047      pXMLStream->WriteString(ws, ws.GetLength());
1048    } break;
1049    case FDE_XMLNODE_CharData: {
1050      CFX_WideString ws = L"<![CDATA[";
1051      ws += ((CFDE_XMLCharData*)pNode)->m_wsCharData;
1052      ws += L"]]>";
1053      pXMLStream->WriteString(ws, ws.GetLength());
1054    } break;
1055    case FDE_XMLNODE_Unknown:
1056      break;
1057    default:
1058      break;
1059  }
1060}
1061void CFDE_XMLDoc::SaveXML(IFX_Stream* pXMLStream, FX_BOOL bSaveBOM) {
1062  if (pXMLStream == NULL || pXMLStream == m_pStream) {
1063    m_pStream->Seek(FX_STREAMSEEK_Begin, 0);
1064    pXMLStream = m_pStream;
1065  }
1066  FXSYS_assert((pXMLStream->GetAccessModes() & FX_STREAMACCESS_Text) != 0);
1067  FXSYS_assert((pXMLStream->GetAccessModes() & FX_STREAMACCESS_Write) != 0);
1068  FX_WORD wCodePage = pXMLStream->GetCodePage();
1069  if (wCodePage != FX_CODEPAGE_UTF16LE && wCodePage != FX_CODEPAGE_UTF16BE &&
1070      wCodePage != FX_CODEPAGE_UTF8) {
1071    wCodePage = FX_CODEPAGE_UTF8;
1072    pXMLStream->SetCodePage(wCodePage);
1073  }
1074  if (bSaveBOM) {
1075    pXMLStream->WriteString(L"\xFEFF", 1);
1076  }
1077  CFDE_XMLNode* pNode = m_pRoot->m_pChild;
1078  while (pNode != NULL) {
1079    SaveXMLNode(pXMLStream, (IFDE_XMLNode*)pNode);
1080    pNode = pNode->m_pNext;
1081  }
1082  if (pXMLStream == m_pStream) {
1083    int32_t iPos = pXMLStream->GetPosition();
1084    pXMLStream->SetLength(iPos);
1085  }
1086}
1087CFDE_XMLDOMParser::CFDE_XMLDOMParser(CFDE_XMLNode* pRoot,
1088                                     IFDE_XMLSyntaxParser* pParser)
1089    : m_pParser(pParser),
1090      m_pParent(pRoot),
1091      m_pChild(NULL),
1092      m_NodeStack(16),
1093      m_ws1(),
1094      m_ws2() {
1095  m_NodeStack.Push(m_pParent);
1096}
1097CFDE_XMLDOMParser::~CFDE_XMLDOMParser() {
1098  m_NodeStack.RemoveAll();
1099  m_ws1.Empty();
1100  m_ws2.Empty();
1101}
1102int32_t CFDE_XMLDOMParser::DoParser(IFX_Pause* pPause) {
1103  FX_DWORD dwRet;
1104  int32_t iCount = 0;
1105  while (TRUE) {
1106    dwRet = m_pParser->DoSyntaxParse();
1107    switch (dwRet) {
1108      case FDE_XMLSYNTAXSTATUS_InstructionOpen:
1109        break;
1110      case FDE_XMLSYNTAXSTATUS_InstructionClose:
1111        if (m_pChild->GetType() != FDE_XMLNODE_Instruction) {
1112          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1113          break;
1114        }
1115        m_pChild = m_pParent;
1116        break;
1117      case FDE_XMLSYNTAXSTATUS_ElementOpen:
1118      case FDE_XMLSYNTAXSTATUS_ElementBreak:
1119        break;
1120      case FDE_XMLSYNTAXSTATUS_ElementClose:
1121        if (m_pChild->GetType() != FDE_XMLNODE_Element) {
1122          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1123          break;
1124        }
1125        m_pParser->GetTagName(m_ws1);
1126        ((CFDE_XMLElement*)m_pChild)->GetTagName(m_ws2);
1127        if (m_ws1.GetLength() > 0 && m_ws1.Compare(m_ws2) != 0) {
1128          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1129          break;
1130        }
1131        m_NodeStack.Pop();
1132        if (m_NodeStack.GetSize() < 1) {
1133          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1134          break;
1135        }
1136        m_pParent = (CFDE_XMLNode*)*m_NodeStack.GetTopElement();
1137        m_pChild = m_pParent;
1138        iCount++;
1139        break;
1140      case FDE_XMLSYNTAXSTATUS_TargetName:
1141        m_pParser->GetTargetName(m_ws1);
1142        m_pChild = new CFDE_XMLInstruction(m_ws1);
1143        m_pParent->InsertChildNode(m_pChild);
1144        m_ws1.Empty();
1145        break;
1146      case FDE_XMLSYNTAXSTATUS_TagName:
1147        m_pParser->GetTagName(m_ws1);
1148        m_pChild = new CFDE_XMLElement(m_ws1);
1149        m_pParent->InsertChildNode(m_pChild);
1150        m_NodeStack.Push(m_pChild);
1151        m_pParent = m_pChild;
1152        break;
1153      case FDE_XMLSYNTAXSTATUS_AttriName:
1154        m_pParser->GetAttributeName(m_ws1);
1155        break;
1156      case FDE_XMLSYNTAXSTATUS_AttriValue:
1157        if (m_pChild == NULL) {
1158          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1159          break;
1160        }
1161        m_pParser->GetAttributeName(m_ws2);
1162        if (m_pChild->GetType() == FDE_XMLNODE_Element) {
1163          ((CFDE_XMLElement*)m_pChild)->SetString(m_ws1, m_ws2);
1164        } else if (m_pChild->GetType() == FDE_XMLNODE_Instruction) {
1165          ((CFDE_XMLInstruction*)m_pChild)->SetString(m_ws1, m_ws2);
1166        }
1167        m_ws1.Empty();
1168        break;
1169      case FDE_XMLSYNTAXSTATUS_Text:
1170        m_pParser->GetTextData(m_ws1);
1171        m_pChild = new CFDE_XMLText(m_ws1);
1172        m_pParent->InsertChildNode(m_pChild);
1173        m_pChild = m_pParent;
1174        break;
1175      case FDE_XMLSYNTAXSTATUS_CData:
1176        m_pParser->GetTextData(m_ws1);
1177        m_pChild = new CFDE_XMLCharData(m_ws1);
1178        m_pParent->InsertChildNode(m_pChild);
1179        m_pChild = m_pParent;
1180        break;
1181      case FDE_XMLSYNTAXSTATUS_TargetData:
1182        if (m_pChild == NULL ||
1183            m_pChild->GetType() != FDE_XMLNODE_Instruction) {
1184          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1185          break;
1186        }
1187        if (!m_ws1.IsEmpty()) {
1188          ((CFDE_XMLInstruction*)m_pChild)->AppendData(m_ws1);
1189        }
1190        m_pParser->GetTargetData(m_ws1);
1191        ((CFDE_XMLInstruction*)m_pChild)->AppendData(m_ws1);
1192        m_ws1.Empty();
1193        break;
1194      default:
1195        break;
1196    }
1197    if (dwRet == FDE_XMLSYNTAXSTATUS_Error ||
1198        dwRet == FDE_XMLSYNTAXSTATUS_EOS) {
1199      break;
1200    }
1201    if (pPause != NULL && iCount > 500 && pPause->NeedToPauseNow()) {
1202      break;
1203    }
1204  }
1205  return m_pParser->GetStatus();
1206}
1207CFDE_XMLSAXParser::CFDE_XMLSAXParser(FDE_LPXMLREADERHANDLER pHandler,
1208                                     IFDE_XMLSyntaxParser* pParser)
1209    : m_pHandler(pHandler),
1210      m_pParser(pParser),
1211      m_TagStack(16),
1212      m_pTagTop(NULL),
1213      m_ws1(),
1214      m_ws2() {}
1215CFDE_XMLSAXParser::~CFDE_XMLSAXParser() {
1216  m_TagStack.RemoveAll();
1217  m_ws1.Empty();
1218  m_ws2.Empty();
1219}
1220int32_t CFDE_XMLSAXParser::DoParser(IFX_Pause* pPause) {
1221  FX_DWORD dwRet = 0;
1222  int32_t iCount = 0;
1223  while (TRUE) {
1224    dwRet = m_pParser->DoSyntaxParse();
1225    switch (dwRet) {
1226      case FDE_XMLSYNTAXSTATUS_ElementBreak:
1227        if (m_pTagTop == NULL) {
1228          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1229          break;
1230        }
1231        if (m_pTagTop->eType == FDE_XMLNODE_Element) {
1232          m_pHandler->OnTagBreak(m_pHandler, m_pTagTop->wsTagName);
1233        }
1234        break;
1235      case FDE_XMLSYNTAXSTATUS_ElementClose:
1236        if (m_pTagTop == NULL || m_pTagTop->eType != FDE_XMLNODE_Element) {
1237          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1238          break;
1239        }
1240        m_pParser->GetTagName(m_ws1);
1241        if (m_ws1.GetLength() > 0 && m_ws1.Compare(m_pTagTop->wsTagName) != 0) {
1242          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1243          break;
1244        } else if (m_ws1.GetLength() == 0) {
1245          m_pHandler->OnTagBreak(m_pHandler, m_pTagTop->wsTagName);
1246        }
1247        m_pHandler->OnTagClose(m_pHandler, m_pTagTop->wsTagName);
1248        Pop();
1249        iCount++;
1250        break;
1251      case FDE_XMLSYNTAXSTATUS_TargetName: {
1252        m_pParser->GetTargetName(m_ws1);
1253        CFDE_XMLTAG xmlTag;
1254        xmlTag.wsTagName = m_ws1;
1255        xmlTag.eType = FDE_XMLNODE_Instruction;
1256        Push(xmlTag);
1257        m_pHandler->OnTagEnter(m_pHandler, FDE_XMLNODE_Instruction,
1258                               m_pTagTop->wsTagName);
1259        m_ws1.Empty();
1260      } break;
1261      case FDE_XMLSYNTAXSTATUS_TagName: {
1262        m_pParser->GetTargetName(m_ws1);
1263        CFDE_XMLTAG xmlTag;
1264        xmlTag.wsTagName = m_ws1;
1265        xmlTag.eType = FDE_XMLNODE_Element;
1266        Push(xmlTag);
1267        m_pHandler->OnTagEnter(m_pHandler, FDE_XMLNODE_Element,
1268                               m_pTagTop->wsTagName);
1269      } break;
1270      case FDE_XMLSYNTAXSTATUS_AttriName:
1271        m_pParser->GetTargetName(m_ws1);
1272        break;
1273      case FDE_XMLSYNTAXSTATUS_AttriValue:
1274        m_pParser->GetAttributeName(m_ws2);
1275        if (m_pTagTop == NULL) {
1276          dwRet = FDE_XMLSYNTAXSTATUS_Error;
1277          break;
1278        }
1279        if (m_pTagTop->eType == FDE_XMLNODE_Element) {
1280          m_pHandler->OnAttribute(m_pHandler, m_ws1, m_ws2);
1281        }
1282        m_ws1.Empty();
1283        break;
1284      case FDE_XMLSYNTAXSTATUS_CData:
1285        m_pParser->GetTextData(m_ws1);
1286        m_pHandler->OnData(m_pHandler, FDE_XMLNODE_CharData, m_ws1);
1287        break;
1288      case FDE_XMLSYNTAXSTATUS_Text:
1289        m_pParser->GetTextData(m_ws1);
1290        m_pHandler->OnData(m_pHandler, FDE_XMLNODE_Text, m_ws1);
1291        break;
1292      case FDE_XMLSYNTAXSTATUS_TargetData:
1293        m_pParser->GetTargetData(m_ws1);
1294        m_pHandler->OnData(m_pHandler, FDE_XMLNODE_Instruction, m_ws1);
1295        m_ws1.Empty();
1296        break;
1297      default:
1298        break;
1299    }
1300    if (dwRet == FDE_XMLSYNTAXSTATUS_Error ||
1301        dwRet == FDE_XMLSYNTAXSTATUS_EOS) {
1302      break;
1303    }
1304    if (pPause != NULL && iCount > 500 && pPause->NeedToPauseNow()) {
1305      break;
1306    }
1307  }
1308  return m_pParser->GetStatus();
1309}
1310inline void CFDE_XMLSAXParser::Push(const CFDE_XMLTAG& xmlTag) {
1311  m_TagStack.Push(xmlTag);
1312  m_pTagTop = m_TagStack.GetTopElement();
1313}
1314inline void CFDE_XMLSAXParser::Pop() {
1315  m_TagStack.Pop();
1316  m_pTagTop = m_TagStack.GetTopElement();
1317}
1318#ifdef _FDE_BLOCK_BUFFER
1319CFDE_BlockBuffer::CFDE_BlockBuffer(int32_t iAllocStep)
1320    : m_iDataLength(0),
1321      m_iBufferSize(0),
1322      m_iAllocStep(iAllocStep),
1323      m_iStartPosition(0) {
1324}
1325CFDE_BlockBuffer::~CFDE_BlockBuffer() {
1326  ClearBuffer();
1327}
1328FX_WCHAR* CFDE_BlockBuffer::GetAvailableBlock(int32_t& iIndexInBlock) {
1329  iIndexInBlock = 0;
1330  if (!m_BlockArray.GetSize()) {
1331    return nullptr;
1332  }
1333  int32_t iRealIndex = m_iStartPosition + m_iDataLength;
1334  if (iRealIndex == m_iBufferSize) {
1335    FX_WCHAR* pBlock = FX_Alloc(FX_WCHAR, m_iAllocStep);
1336    m_BlockArray.Add(pBlock);
1337    m_iBufferSize += m_iAllocStep;
1338    return pBlock;
1339  }
1340  iIndexInBlock = iRealIndex % m_iAllocStep;
1341  return (FX_WCHAR*)m_BlockArray[iRealIndex / m_iAllocStep];
1342}
1343FX_BOOL CFDE_BlockBuffer::InitBuffer(int32_t iBufferSize) {
1344  ClearBuffer();
1345  int32_t iNumOfBlock = (iBufferSize - 1) / m_iAllocStep + 1;
1346  for (int32_t i = 0; i < iNumOfBlock; i++) {
1347    m_BlockArray.Add(FX_Alloc(FX_WCHAR, m_iAllocStep));
1348  }
1349  m_iBufferSize = iNumOfBlock * m_iAllocStep;
1350  return TRUE;
1351}
1352void CFDE_BlockBuffer::SetTextChar(int32_t iIndex, FX_WCHAR ch) {
1353  if (iIndex < 0) {
1354    return;
1355  }
1356  int32_t iRealIndex = m_iStartPosition + iIndex;
1357  int32_t iBlockIndex = iRealIndex / m_iAllocStep;
1358  int32_t iInnerIndex = iRealIndex % m_iAllocStep;
1359  int32_t iBlockSize = m_BlockArray.GetSize();
1360  if (iBlockIndex >= iBlockSize) {
1361    int32_t iNewBlocks = iBlockIndex - iBlockSize + 1;
1362    do {
1363      FX_WCHAR* pBlock = FX_Alloc(FX_WCHAR, m_iAllocStep);
1364      m_BlockArray.Add(pBlock);
1365      m_iBufferSize += m_iAllocStep;
1366    } while (--iNewBlocks);
1367  }
1368  FX_WCHAR* pTextData = (FX_WCHAR*)m_BlockArray[iBlockIndex];
1369  *(pTextData + iInnerIndex) = ch;
1370  if (m_iDataLength <= iIndex) {
1371    m_iDataLength = iIndex + 1;
1372  }
1373}
1374int32_t CFDE_BlockBuffer::DeleteTextChars(int32_t iCount, FX_BOOL bDirection) {
1375  if (iCount <= 0) {
1376    return m_iDataLength;
1377  }
1378  if (iCount >= m_iDataLength) {
1379    Reset(FALSE);
1380    return 0;
1381  }
1382  if (bDirection) {
1383    m_iStartPosition += iCount;
1384    m_iDataLength -= iCount;
1385  } else {
1386    m_iDataLength -= iCount;
1387  }
1388  return m_iDataLength;
1389}
1390void CFDE_BlockBuffer::GetTextData(CFX_WideString& wsTextData,
1391                                   int32_t iStart,
1392                                   int32_t iLength) const {
1393  wsTextData.Empty();
1394  int32_t iMaybeDataLength = m_iBufferSize - 1 - m_iStartPosition;
1395  if (iStart < 0 || iStart > iMaybeDataLength) {
1396    return;
1397  }
1398  if (iLength == -1 || iLength > iMaybeDataLength) {
1399    iLength = iMaybeDataLength;
1400  }
1401  if (iLength <= 0) {
1402    return;
1403  }
1404  FX_WCHAR* pBuf = wsTextData.GetBuffer(iLength);
1405  if (!pBuf) {
1406    return;
1407  }
1408  int32_t iStartBlockIndex = 0;
1409  int32_t iStartInnerIndex = 0;
1410  TextDataIndex2BufIndex(iStart, iStartBlockIndex, iStartInnerIndex);
1411  int32_t iEndBlockIndex = 0;
1412  int32_t iEndInnerIndex = 0;
1413  TextDataIndex2BufIndex(iStart + iLength, iEndBlockIndex, iEndInnerIndex);
1414  int32_t iPointer = 0;
1415  for (int32_t i = iStartBlockIndex; i <= iEndBlockIndex; i++) {
1416    int32_t iBufferPointer = 0;
1417    int32_t iCopyLength = m_iAllocStep;
1418    if (i == iStartBlockIndex) {
1419      iCopyLength -= iStartInnerIndex;
1420      iBufferPointer = iStartInnerIndex;
1421    }
1422    if (i == iEndBlockIndex) {
1423      iCopyLength -= ((m_iAllocStep - 1) - iEndInnerIndex);
1424    }
1425    FX_WCHAR* pBlockBuf = (FX_WCHAR*)m_BlockArray[i];
1426    FXSYS_memcpy(pBuf + iPointer, pBlockBuf + iBufferPointer,
1427                 iCopyLength * sizeof(FX_WCHAR));
1428    iPointer += iCopyLength;
1429  }
1430  wsTextData.ReleaseBuffer(iLength);
1431}
1432void CFDE_BlockBuffer::TextDataIndex2BufIndex(const int32_t iIndex,
1433                                              int32_t& iBlockIndex,
1434                                              int32_t& iInnerIndex) const {
1435  FXSYS_assert(iIndex >= 0);
1436  int32_t iRealIndex = m_iStartPosition + iIndex;
1437  iBlockIndex = iRealIndex / m_iAllocStep;
1438  iInnerIndex = iRealIndex % m_iAllocStep;
1439}
1440void CFDE_BlockBuffer::ClearBuffer() {
1441  m_iBufferSize = 0;
1442  int32_t iSize = m_BlockArray.GetSize();
1443  for (int32_t i = 0; i < iSize; i++) {
1444    FX_Free(m_BlockArray[i]);
1445    m_BlockArray[i] = NULL;
1446  }
1447  m_BlockArray.RemoveAll();
1448}
1449#endif
1450IFDE_XMLSyntaxParser* IFDE_XMLSyntaxParser::Create() {
1451  return new CFDE_XMLSyntaxParser;
1452}
1453#ifdef _FDE_BLOCK_BUFFER
1454CFDE_XMLSyntaxParser::CFDE_XMLSyntaxParser()
1455    : m_pStream(nullptr),
1456      m_iXMLPlaneSize(-1),
1457      m_iCurrentPos(0),
1458      m_iCurrentNodeNum(-1),
1459      m_iLastNodeNum(-1),
1460      m_iParsedChars(0),
1461      m_iParsedBytes(0),
1462      m_pBuffer(nullptr),
1463      m_iBufferChars(0),
1464      m_bEOS(FALSE),
1465      m_pStart(nullptr),
1466      m_pEnd(nullptr),
1467      m_XMLNodeStack(16),
1468      m_iAllocStep(m_BlockBuffer.GetAllocStep()),
1469      m_iDataLength(m_BlockBuffer.GetDataLengthRef()),
1470      m_pCurrentBlock(nullptr),
1471      m_iIndexInBlock(0),
1472      m_iTextDataLength(0),
1473      m_dwStatus(FDE_XMLSYNTAXSTATUS_None),
1474      m_dwMode(FDE_XMLSYNTAXMODE_Text),
1475      m_wQuotationMark(0),
1476      m_iEntityStart(-1),
1477      m_SkipStack(16) {
1478  m_CurNode.iNodeNum = -1;
1479  m_CurNode.eNodeType = FDE_XMLNODE_Unknown;
1480}
1481void CFDE_XMLSyntaxParser::Init(IFX_Stream* pStream,
1482                                int32_t iXMLPlaneSize,
1483                                int32_t iTextDataSize) {
1484  FXSYS_assert(m_pStream == NULL && m_pBuffer == NULL);
1485  FXSYS_assert(pStream != NULL && iXMLPlaneSize > 0);
1486  int32_t iStreamLength = pStream->GetLength();
1487  FXSYS_assert(iStreamLength > 0);
1488  m_pStream = pStream;
1489  m_iXMLPlaneSize = std::min(iXMLPlaneSize, iStreamLength);
1490  uint8_t bom[4];
1491  m_iCurrentPos = m_pStream->GetBOM(bom);
1492  FXSYS_assert(m_pBuffer == NULL);
1493  m_pBuffer = FX_Alloc(FX_WCHAR, m_iXMLPlaneSize);
1494  m_pStart = m_pEnd = m_pBuffer;
1495  FXSYS_assert(!m_BlockBuffer.IsInitialized());
1496  m_BlockBuffer.InitBuffer();
1497  m_pCurrentBlock = m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1498  m_iParsedBytes = m_iParsedChars = 0;
1499  m_iBufferChars = 0;
1500}
1501FX_DWORD CFDE_XMLSyntaxParser::DoSyntaxParse() {
1502  if (m_dwStatus == FDE_XMLSYNTAXSTATUS_Error ||
1503      m_dwStatus == FDE_XMLSYNTAXSTATUS_EOS) {
1504    return m_dwStatus;
1505  }
1506  FXSYS_assert(m_pStream && m_pBuffer && m_BlockBuffer.IsInitialized());
1507  int32_t iStreamLength = m_pStream->GetLength();
1508  int32_t iPos;
1509  FX_WCHAR ch;
1510  FX_DWORD dwStatus = FDE_XMLSYNTAXSTATUS_None;
1511  while (TRUE) {
1512    if (m_pStart >= m_pEnd) {
1513      if (m_bEOS || m_iCurrentPos >= iStreamLength) {
1514        m_dwStatus = FDE_XMLSYNTAXSTATUS_EOS;
1515        return m_dwStatus;
1516      }
1517      m_iParsedChars += (m_pEnd - m_pBuffer);
1518      m_iParsedBytes = m_iCurrentPos;
1519      m_pStream->Lock();
1520      if (m_pStream->GetPosition() != m_iCurrentPos) {
1521        m_pStream->Seek(FX_STREAMSEEK_Begin, m_iCurrentPos);
1522      }
1523      m_iBufferChars =
1524          m_pStream->ReadString(m_pBuffer, m_iXMLPlaneSize, m_bEOS);
1525      iPos = m_pStream->GetPosition();
1526      m_pStream->Unlock();
1527      if (m_iBufferChars < 1) {
1528        m_iCurrentPos = iStreamLength;
1529        m_dwStatus = FDE_XMLSYNTAXSTATUS_EOS;
1530        return m_dwStatus;
1531      }
1532      m_iCurrentPos = iPos;
1533      m_pStart = m_pBuffer;
1534      m_pEnd = m_pBuffer + m_iBufferChars;
1535    }
1536    while (m_pStart < m_pEnd) {
1537      ch = *m_pStart;
1538      switch (m_dwMode) {
1539        case FDE_XMLSYNTAXMODE_Text:
1540          if (ch == L'<') {
1541            if (m_iDataLength > 0) {
1542              m_iTextDataLength = m_iDataLength;
1543              m_BlockBuffer.Reset();
1544              m_pCurrentBlock =
1545                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1546              m_iEntityStart = -1;
1547              dwStatus = FDE_XMLSYNTAXSTATUS_Text;
1548            } else {
1549              m_pStart++;
1550              m_dwMode = FDE_XMLSYNTAXMODE_Node;
1551            }
1552          } else {
1553            ParseTextChar(ch);
1554          }
1555          break;
1556        case FDE_XMLSYNTAXMODE_Node:
1557          if (ch == L'!') {
1558            m_pStart++;
1559            m_dwMode = FDE_XMLSYNTAXMODE_SkipCommentOrDecl;
1560          } else if (ch == L'/') {
1561            m_pStart++;
1562            m_dwMode = FDE_XMLSYNTAXMODE_CloseElement;
1563          } else if (ch == L'?') {
1564            m_iLastNodeNum++;
1565            m_iCurrentNodeNum = m_iLastNodeNum;
1566            m_CurNode.iNodeNum = m_iLastNodeNum;
1567            m_CurNode.eNodeType = FDE_XMLNODE_Instruction;
1568            m_XMLNodeStack.Push(m_CurNode);
1569            m_pStart++;
1570            m_dwMode = FDE_XMLSYNTAXMODE_Target;
1571            dwStatus = FDE_XMLSYNTAXSTATUS_InstructionOpen;
1572          } else {
1573            m_iLastNodeNum++;
1574            m_iCurrentNodeNum = m_iLastNodeNum;
1575            m_CurNode.iNodeNum = m_iLastNodeNum;
1576            m_CurNode.eNodeType = FDE_XMLNODE_Element;
1577            m_XMLNodeStack.Push(m_CurNode);
1578            m_dwMode = FDE_XMLSYNTAXMODE_Tag;
1579            dwStatus = FDE_XMLSYNTAXSTATUS_ElementOpen;
1580          }
1581          break;
1582        case FDE_XMLSYNTAXMODE_Target:
1583        case FDE_XMLSYNTAXMODE_Tag:
1584          if (!FDE_IsXMLNameChar(ch, m_iDataLength < 1)) {
1585            if (m_iDataLength < 1) {
1586              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1587              return m_dwStatus;
1588            } else {
1589              m_iTextDataLength = m_iDataLength;
1590              m_BlockBuffer.Reset();
1591              m_pCurrentBlock =
1592                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1593              if (m_dwMode != FDE_XMLSYNTAXMODE_Target) {
1594                dwStatus = FDE_XMLSYNTAXSTATUS_TagName;
1595              } else {
1596                dwStatus = FDE_XMLSYNTAXSTATUS_TargetName;
1597              }
1598              m_dwMode = FDE_XMLSYNTAXMODE_AttriName;
1599            }
1600          } else {
1601            if (m_iIndexInBlock == m_iAllocStep) {
1602              m_pCurrentBlock =
1603                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1604              if (!m_pCurrentBlock) {
1605                return FDE_XMLSYNTAXSTATUS_Error;
1606              }
1607            }
1608            m_pCurrentBlock[m_iIndexInBlock++] = ch;
1609            m_iDataLength++;
1610            m_pStart++;
1611          }
1612          break;
1613        case FDE_XMLSYNTAXMODE_AttriName:
1614          if (m_iDataLength < 1 && FDE_IsXMLWhiteSpace(ch)) {
1615            m_pStart++;
1616            break;
1617          }
1618          if (!FDE_IsXMLNameChar(ch, m_iDataLength < 1)) {
1619            if (m_iDataLength < 1) {
1620              if (m_CurNode.eNodeType == FDE_XMLNODE_Element) {
1621                if (ch == L'>' || ch == L'/') {
1622                  m_dwMode = FDE_XMLSYNTAXMODE_BreakElement;
1623                  break;
1624                }
1625              } else if (m_CurNode.eNodeType == FDE_XMLNODE_Instruction) {
1626                if (ch == L'?') {
1627                  m_dwMode = FDE_XMLSYNTAXMODE_CloseInstruction;
1628                  m_pStart++;
1629                } else {
1630                  m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
1631                }
1632                break;
1633              }
1634              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1635              return m_dwStatus;
1636            } else {
1637              if (m_CurNode.eNodeType == FDE_XMLNODE_Instruction) {
1638                if (ch != '=' && !FDE_IsXMLWhiteSpace(ch)) {
1639                  m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
1640                  break;
1641                }
1642              }
1643              m_iTextDataLength = m_iDataLength;
1644              m_BlockBuffer.Reset();
1645              m_pCurrentBlock =
1646                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1647              m_dwMode = FDE_XMLSYNTAXMODE_AttriEqualSign;
1648              dwStatus = FDE_XMLSYNTAXSTATUS_AttriName;
1649            }
1650          } else {
1651            if (m_iIndexInBlock == m_iAllocStep) {
1652              m_pCurrentBlock =
1653                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1654              if (!m_pCurrentBlock) {
1655                return FDE_XMLSYNTAXSTATUS_Error;
1656              }
1657            }
1658            m_pCurrentBlock[m_iIndexInBlock++] = ch;
1659            m_iDataLength++;
1660            m_pStart++;
1661          }
1662          break;
1663        case FDE_XMLSYNTAXMODE_AttriEqualSign:
1664          if (FDE_IsXMLWhiteSpace(ch)) {
1665            m_pStart++;
1666            break;
1667          }
1668          if (ch != L'=') {
1669            if (m_CurNode.eNodeType == FDE_XMLNODE_Instruction) {
1670              m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
1671              break;
1672            }
1673            m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1674            return m_dwStatus;
1675          } else {
1676            m_dwMode = FDE_XMLSYNTAXMODE_AttriQuotation;
1677            m_pStart++;
1678          }
1679          break;
1680        case FDE_XMLSYNTAXMODE_AttriQuotation:
1681          if (FDE_IsXMLWhiteSpace(ch)) {
1682            m_pStart++;
1683            break;
1684          }
1685          if (ch != L'\"' && ch != L'\'') {
1686            m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1687            return m_dwStatus;
1688          } else {
1689            m_wQuotationMark = ch;
1690            m_dwMode = FDE_XMLSYNTAXMODE_AttriValue;
1691            m_pStart++;
1692          }
1693          break;
1694        case FDE_XMLSYNTAXMODE_AttriValue:
1695          if (ch == m_wQuotationMark) {
1696            if (m_iEntityStart > -1) {
1697              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1698              return m_dwStatus;
1699            }
1700            m_iTextDataLength = m_iDataLength;
1701            m_wQuotationMark = 0;
1702            m_BlockBuffer.Reset();
1703            m_pCurrentBlock = m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1704            m_pStart++;
1705            m_dwMode = FDE_XMLSYNTAXMODE_AttriName;
1706            dwStatus = FDE_XMLSYNTAXSTATUS_AttriValue;
1707          } else {
1708            ParseTextChar(ch);
1709          }
1710          break;
1711        case FDE_XMLSYNTAXMODE_CloseInstruction:
1712          if (ch != L'>') {
1713            if (m_iIndexInBlock == m_iAllocStep) {
1714              m_pCurrentBlock =
1715                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1716              if (!m_pCurrentBlock) {
1717                return FDE_XMLSYNTAXSTATUS_Error;
1718              }
1719            }
1720            m_pCurrentBlock[m_iIndexInBlock++] = ch;
1721            m_iDataLength++;
1722            m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
1723          } else if (m_iDataLength > 0) {
1724            m_iTextDataLength = m_iDataLength;
1725            m_BlockBuffer.Reset();
1726            m_pCurrentBlock = m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1727            dwStatus = FDE_XMLSYNTAXSTATUS_TargetData;
1728          } else {
1729            m_pStart++;
1730            FDE_LPXMLNODE pXMLNode = m_XMLNodeStack.GetTopElement();
1731            if (pXMLNode == NULL) {
1732              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1733              return m_dwStatus;
1734            }
1735            m_XMLNodeStack.Pop();
1736            pXMLNode = m_XMLNodeStack.GetTopElement();
1737            if (pXMLNode == NULL) {
1738              m_CurNode.iNodeNum = -1;
1739              m_CurNode.eNodeType = FDE_XMLNODE_Unknown;
1740            } else {
1741              m_CurNode = *pXMLNode;
1742            }
1743            m_iCurrentNodeNum = m_CurNode.iNodeNum;
1744            m_BlockBuffer.Reset();
1745            m_pCurrentBlock = m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1746            m_dwMode = FDE_XMLSYNTAXMODE_Text;
1747            dwStatus = FDE_XMLSYNTAXSTATUS_InstructionClose;
1748          }
1749          break;
1750        case FDE_XMLSYNTAXMODE_BreakElement:
1751          if (ch == L'>') {
1752            m_dwMode = FDE_XMLSYNTAXMODE_Text;
1753            dwStatus = FDE_XMLSYNTAXSTATUS_ElementBreak;
1754          } else if (ch == L'/') {
1755            m_dwMode = FDE_XMLSYNTAXMODE_CloseElement;
1756          } else {
1757            m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1758            return m_dwStatus;
1759          }
1760          m_pStart++;
1761          break;
1762        case FDE_XMLSYNTAXMODE_CloseElement:
1763          if (!FDE_IsXMLNameChar(ch, m_iDataLength < 1)) {
1764            if (ch == L'>') {
1765              FDE_LPXMLNODE pXMLNode = m_XMLNodeStack.GetTopElement();
1766              if (pXMLNode == NULL) {
1767                m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1768                return m_dwStatus;
1769              }
1770              m_XMLNodeStack.Pop();
1771              pXMLNode = m_XMLNodeStack.GetTopElement();
1772              if (pXMLNode == NULL) {
1773                m_CurNode.iNodeNum = -1;
1774                m_CurNode.eNodeType = FDE_XMLNODE_Unknown;
1775              } else {
1776                m_CurNode = *pXMLNode;
1777              }
1778              m_iCurrentNodeNum = m_CurNode.iNodeNum;
1779              m_iTextDataLength = m_iDataLength;
1780              m_BlockBuffer.Reset();
1781              m_pCurrentBlock =
1782                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1783              m_dwMode = FDE_XMLSYNTAXMODE_Text;
1784              dwStatus = FDE_XMLSYNTAXSTATUS_ElementClose;
1785            } else if (!FDE_IsXMLWhiteSpace(ch)) {
1786              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1787              return m_dwStatus;
1788            }
1789          } else {
1790            if (m_iIndexInBlock == m_iAllocStep) {
1791              m_pCurrentBlock =
1792                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1793              if (!m_pCurrentBlock) {
1794                return FDE_XMLSYNTAXSTATUS_Error;
1795              }
1796            }
1797            m_pCurrentBlock[m_iIndexInBlock++] = ch;
1798            m_iDataLength++;
1799          }
1800          m_pStart++;
1801          break;
1802        case FDE_XMLSYNTAXMODE_SkipCommentOrDecl:
1803          if (ch == '-') {
1804            m_dwMode = FDE_XMLSYNTAXMODE_SkipComment;
1805          } else {
1806            m_dwMode = FDE_XMLSYNTAXMODE_SkipDeclNode;
1807            m_SkipChar = L'>';
1808            m_SkipStack.Push(L'>');
1809          }
1810          break;
1811        case FDE_XMLSYNTAXMODE_SkipDeclNode:
1812          if (m_SkipChar == L'\'' || m_SkipChar == L'\"') {
1813            m_pStart++;
1814            if (ch != m_SkipChar) {
1815              break;
1816            }
1817            m_SkipStack.Pop();
1818            FX_DWORD* pDWord = m_SkipStack.GetTopElement();
1819            if (pDWord == NULL) {
1820              m_dwMode = FDE_XMLSYNTAXMODE_Text;
1821            } else {
1822              m_SkipChar = (FX_WCHAR)*pDWord;
1823            }
1824          } else {
1825            switch (ch) {
1826              case L'<':
1827                m_SkipChar = L'>';
1828                m_SkipStack.Push(L'>');
1829                break;
1830              case L'[':
1831                m_SkipChar = L']';
1832                m_SkipStack.Push(L']');
1833                break;
1834              case L'(':
1835                m_SkipChar = L')';
1836                m_SkipStack.Push(L')');
1837                break;
1838              case L'\'':
1839                m_SkipChar = L'\'';
1840                m_SkipStack.Push(L'\'');
1841                break;
1842              case L'\"':
1843                m_SkipChar = L'\"';
1844                m_SkipStack.Push(L'\"');
1845                break;
1846              default:
1847                if (ch == m_SkipChar) {
1848                  m_SkipStack.Pop();
1849                  FX_DWORD* pDWord = m_SkipStack.GetTopElement();
1850                  if (pDWord == NULL) {
1851                    if (m_iDataLength >= 9) {
1852                      CFX_WideString wsHeader;
1853                      m_BlockBuffer.GetTextData(wsHeader, 0, 7);
1854                      if (wsHeader.Equal(FX_WSTRC(L"[CDATA["))) {
1855                        CFX_WideString wsTailer;
1856                        m_BlockBuffer.GetTextData(wsTailer, m_iDataLength - 2,
1857                                                  2);
1858                        if (wsTailer.Equal(FX_WSTRC(L"]]"))) {
1859                          m_BlockBuffer.DeleteTextChars(7, TRUE);
1860                          m_BlockBuffer.DeleteTextChars(2, FALSE);
1861                          dwStatus = FDE_XMLSYNTAXSTATUS_CData;
1862                        }
1863                      }
1864                    }
1865                    m_iTextDataLength = m_iDataLength;
1866                    m_BlockBuffer.Reset();
1867                    m_pCurrentBlock =
1868                        m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1869                    m_dwMode = FDE_XMLSYNTAXMODE_Text;
1870                  } else {
1871                    m_SkipChar = (FX_WCHAR)*pDWord;
1872                  }
1873                }
1874                break;
1875            }
1876            if (m_SkipStack.GetSize() > 0) {
1877              if (m_iIndexInBlock == m_iAllocStep) {
1878                m_pCurrentBlock =
1879                    m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1880                if (!m_pCurrentBlock) {
1881                  return FDE_XMLSYNTAXSTATUS_Error;
1882                }
1883              }
1884              m_pCurrentBlock[m_iIndexInBlock++] = ch;
1885              m_iDataLength++;
1886            }
1887            m_pStart++;
1888          }
1889          break;
1890        case FDE_XMLSYNTAXMODE_SkipComment:
1891          if (ch == L'-') {
1892            if (m_iIndexInBlock == m_iAllocStep) {
1893              m_pCurrentBlock =
1894                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1895              if (!m_pCurrentBlock) {
1896                return FDE_XMLSYNTAXSTATUS_Error;
1897              }
1898            }
1899            m_pCurrentBlock[m_iIndexInBlock++] = L'-';
1900            m_iDataLength++;
1901          } else if (ch == L'>') {
1902            if (m_iDataLength > 1) {
1903              m_BlockBuffer.Reset();
1904              m_pCurrentBlock =
1905                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1906              m_dwMode = FDE_XMLSYNTAXMODE_Text;
1907            }
1908          } else {
1909            m_BlockBuffer.Reset();
1910            m_pCurrentBlock = m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1911          }
1912          m_pStart++;
1913          break;
1914        case FDE_XMLSYNTAXMODE_TargetData:
1915          if (FDE_IsXMLWhiteSpace(ch)) {
1916            if (m_iDataLength < 1) {
1917              m_pStart++;
1918              break;
1919            } else if (m_wQuotationMark == 0) {
1920              m_iTextDataLength = m_iDataLength;
1921              m_wQuotationMark = 0;
1922              m_BlockBuffer.Reset();
1923              m_pCurrentBlock =
1924                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1925              m_pStart++;
1926              dwStatus = FDE_XMLSYNTAXSTATUS_TargetData;
1927              break;
1928            }
1929          }
1930          if (ch == '?') {
1931            m_dwMode = FDE_XMLSYNTAXMODE_CloseInstruction;
1932            m_pStart++;
1933          } else if (ch == '\"') {
1934            if (m_wQuotationMark == 0) {
1935              m_wQuotationMark = ch;
1936              m_pStart++;
1937            } else if (ch == m_wQuotationMark) {
1938              m_iTextDataLength = m_iDataLength;
1939              m_wQuotationMark = 0;
1940              m_BlockBuffer.Reset();
1941              m_pCurrentBlock =
1942                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1943              m_pStart++;
1944              dwStatus = FDE_XMLSYNTAXSTATUS_TargetData;
1945            } else {
1946              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
1947              return m_dwStatus;
1948            }
1949          } else {
1950            if (m_iIndexInBlock == m_iAllocStep) {
1951              m_pCurrentBlock =
1952                  m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
1953              if (!m_pCurrentBlock) {
1954                return FDE_XMLSYNTAXSTATUS_Error;
1955              }
1956            }
1957            m_pCurrentBlock[m_iIndexInBlock++] = ch;
1958            m_iDataLength++;
1959            m_pStart++;
1960          }
1961          break;
1962        default:
1963          break;
1964      }
1965      if (dwStatus != FDE_XMLSYNTAXSTATUS_None) {
1966        return dwStatus;
1967      }
1968    }
1969  }
1970  return 0;
1971}
1972#else
1973CFDE_XMLSyntaxParser::CFDE_XMLSyntaxParser()
1974    : m_pStream(NULL),
1975      m_iXMLPlaneSize(-1),
1976      m_iTextDataSize(256),
1977      m_iCurrentPos(0),
1978      m_iCurrentNodeNum(-1),
1979      m_iLastNodeNum(-1),
1980      m_iParsedChars(0),
1981      m_iParsedBytes(0),
1982      m_pBuffer(NULL),
1983      m_iBufferChars(0),
1984      m_bEOS(FALSE),
1985      m_pStart(NULL),
1986      m_pEnd(NULL),
1987      m_XMLNodeStack(16),
1988      m_pwsTextData(NULL),
1989      m_iDataPos(0),
1990      m_dwStatus(FDE_XMLSYNTAXSTATUS_None),
1991      m_dwMode(FDE_XMLSYNTAXMODE_Text),
1992      m_wQuotationMark(0),
1993      m_iTextDataLength(0),
1994      m_iEntityStart(-1),
1995      m_SkipStack(16) {
1996  m_CurNode.iNodeNum = -1;
1997  m_CurNode.eNodeType = FDE_XMLNODE_Unknown;
1998}
1999void CFDE_XMLSyntaxParser::Init(IFX_Stream* pStream,
2000                                int32_t iXMLPlaneSize,
2001                                int32_t iTextDataSize) {
2002  FXSYS_assert(m_pStream == NULL && m_pBuffer == NULL);
2003  FXSYS_assert(pStream != NULL && iXMLPlaneSize > 0 && iTextDataSize > 0);
2004  int32_t iStreamLength = pStream->GetLength();
2005  FXSYS_assert(iStreamLength > 0);
2006  m_pStream = pStream;
2007  m_iXMLPlaneSize = std::min(iXMLPlaneSize, iStreamLength);
2008  m_iTextDataSize = iTextDataSize;
2009  uint8_t bom[4];
2010  m_iCurrentPos = m_pStream->GetBOM(bom);
2011  FXSYS_assert(m_pBuffer == NULL);
2012  m_pBuffer = FX_Alloc(FX_WCHAR, m_iXMLPlaneSize);
2013  m_pStart = m_pEnd = m_pBuffer;
2014  FXSYS_assert(m_pwsTextData == NULL);
2015  m_pwsTextData = FX_Alloc(FX_WCHAR, m_iTextDataSize);
2016  m_iParsedBytes = 0;
2017  m_iParsedChars = 0;
2018  m_iBufferChars = 0;
2019}
2020FX_DWORD CFDE_XMLSyntaxParser::DoSyntaxParse() {
2021  if (m_dwStatus == FDE_XMLSYNTAXSTATUS_Error ||
2022      m_dwStatus == FDE_XMLSYNTAXSTATUS_EOS) {
2023    return m_dwStatus;
2024  }
2025  FXSYS_assert(m_pStream != NULL && m_pBuffer != NULL && m_pwsTextData != NULL);
2026  int32_t iStreamLength = m_pStream->GetLength();
2027  int32_t iPos;
2028  FX_WCHAR ch;
2029  FX_DWORD dwStatus = FDE_XMLSYNTAXSTATUS_None;
2030  while (TRUE) {
2031    if (m_pStart >= m_pEnd) {
2032      if (m_bEOS || m_iCurrentPos >= iStreamLength) {
2033        m_dwStatus = FDE_XMLSYNTAXSTATUS_EOS;
2034        return m_dwStatus;
2035      }
2036      m_iParsedChars += (m_pEnd - m_pBuffer);
2037      m_iParsedBytes = m_iCurrentPos;
2038      m_pStream->Lock();
2039      if (m_pStream->GetPosition() != m_iCurrentPos) {
2040        m_pStream->Seek(FX_STREAMSEEK_Begin, m_iCurrentPos);
2041      }
2042      m_iBufferChars =
2043          m_pStream->ReadString(m_pBuffer, m_iXMLPlaneSize, m_bEOS);
2044      iPos = m_pStream->GetPosition();
2045      m_pStream->Unlock();
2046      if (m_iBufferChars < 1) {
2047        m_iCurrentPos = iStreamLength;
2048        m_dwStatus = FDE_XMLSYNTAXSTATUS_EOS;
2049        return m_dwStatus;
2050      }
2051      m_iCurrentPos = iPos;
2052      m_pStart = m_pBuffer;
2053      m_pEnd = m_pBuffer + m_iBufferChars;
2054    }
2055    while (m_pStart < m_pEnd) {
2056      ch = *m_pStart;
2057      switch (m_dwMode) {
2058        case FDE_XMLSYNTAXMODE_Text:
2059          if (ch == L'<') {
2060            if (m_iDataPos > 0) {
2061              m_iTextDataLength = m_iDataPos;
2062              m_iDataPos = 0;
2063              m_iEntityStart = -1;
2064              dwStatus = FDE_XMLSYNTAXSTATUS_Text;
2065            } else {
2066              m_pStart++;
2067              m_dwMode = FDE_XMLSYNTAXMODE_Node;
2068            }
2069          } else {
2070            ParseTextChar(ch);
2071          }
2072          break;
2073        case FDE_XMLSYNTAXMODE_Node:
2074          if (ch == L'!') {
2075            m_pStart++;
2076            m_dwMode = FDE_XMLSYNTAXMODE_SkipCommentOrDecl;
2077          } else if (ch == L'/') {
2078            m_pStart++;
2079            m_dwMode = FDE_XMLSYNTAXMODE_CloseElement;
2080          } else if (ch == L'?') {
2081            m_iLastNodeNum++;
2082            m_iCurrentNodeNum = m_iLastNodeNum;
2083            m_CurNode.iNodeNum = m_iLastNodeNum;
2084            m_CurNode.eNodeType = FDE_XMLNODE_Instruction;
2085            m_XMLNodeStack.Push(m_CurNode);
2086            m_pStart++;
2087            m_dwMode = FDE_XMLSYNTAXMODE_Target;
2088            dwStatus = FDE_XMLSYNTAXSTATUS_InstructionOpen;
2089          } else {
2090            m_iLastNodeNum++;
2091            m_iCurrentNodeNum = m_iLastNodeNum;
2092            m_CurNode.iNodeNum = m_iLastNodeNum;
2093            m_CurNode.eNodeType = FDE_XMLNODE_Element;
2094            m_XMLNodeStack.Push(m_CurNode);
2095            m_dwMode = FDE_XMLSYNTAXMODE_Tag;
2096            dwStatus = FDE_XMLSYNTAXSTATUS_ElementOpen;
2097          }
2098          break;
2099        case FDE_XMLSYNTAXMODE_Target:
2100        case FDE_XMLSYNTAXMODE_Tag:
2101          if (!FDE_IsXMLNameChar(ch, m_iDataPos < 1)) {
2102            if (m_iDataPos < 1) {
2103              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2104              return m_dwStatus;
2105            } else {
2106              m_iTextDataLength = m_iDataPos;
2107              m_iDataPos = 0;
2108              if (m_dwMode != FDE_XMLSYNTAXMODE_Target) {
2109                dwStatus = FDE_XMLSYNTAXSTATUS_TagName;
2110              } else {
2111                dwStatus = FDE_XMLSYNTAXSTATUS_TargetName;
2112              }
2113              m_dwMode = FDE_XMLSYNTAXMODE_AttriName;
2114            }
2115          } else {
2116            if (m_iDataPos >= m_iTextDataSize) {
2117              ReallocTextDataBuffer();
2118            }
2119            m_pwsTextData[m_iDataPos++] = ch;
2120            m_pStart++;
2121          }
2122          break;
2123        case FDE_XMLSYNTAXMODE_AttriName:
2124          if (m_iDataPos < 1 && FDE_IsXMLWhiteSpace(ch)) {
2125            m_pStart++;
2126            break;
2127          }
2128          if (!FDE_IsXMLNameChar(ch, m_iDataPos < 1)) {
2129            if (m_iDataPos < 1) {
2130              if (m_CurNode.eNodeType == FDE_XMLNODE_Element) {
2131                if (ch == L'>' || ch == L'/') {
2132                  m_dwMode = FDE_XMLSYNTAXMODE_BreakElement;
2133                  break;
2134                }
2135              } else if (m_CurNode.eNodeType == FDE_XMLNODE_Instruction) {
2136                if (ch == L'?') {
2137                  m_dwMode = FDE_XMLSYNTAXMODE_CloseInstruction;
2138                  m_pStart++;
2139                } else {
2140                  m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
2141                }
2142                break;
2143              }
2144              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2145              return m_dwStatus;
2146            } else {
2147              if (m_CurNode.eNodeType == FDE_XMLNODE_Instruction) {
2148                if (ch != '=' && !FDE_IsXMLWhiteSpace(ch)) {
2149                  m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
2150                  break;
2151                }
2152              }
2153              m_iTextDataLength = m_iDataPos;
2154              m_iDataPos = 0;
2155              m_dwMode = FDE_XMLSYNTAXMODE_AttriEqualSign;
2156              dwStatus = FDE_XMLSYNTAXSTATUS_AttriName;
2157            }
2158          } else {
2159            if (m_iDataPos >= m_iTextDataSize) {
2160              ReallocTextDataBuffer();
2161            }
2162            m_pwsTextData[m_iDataPos++] = ch;
2163            m_pStart++;
2164          }
2165          break;
2166        case FDE_XMLSYNTAXMODE_AttriEqualSign:
2167          if (FDE_IsXMLWhiteSpace(ch)) {
2168            m_pStart++;
2169            break;
2170          }
2171          if (ch != L'=') {
2172            if (m_CurNode.eNodeType == FDE_XMLNODE_Instruction) {
2173              m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
2174              break;
2175            }
2176            m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2177            return m_dwStatus;
2178          } else {
2179            m_dwMode = FDE_XMLSYNTAXMODE_AttriQuotation;
2180            m_pStart++;
2181          }
2182          break;
2183        case FDE_XMLSYNTAXMODE_AttriQuotation:
2184          if (FDE_IsXMLWhiteSpace(ch)) {
2185            m_pStart++;
2186            break;
2187          }
2188          if (ch != L'\"' && ch != L'\'') {
2189            m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2190            return m_dwStatus;
2191          } else {
2192            m_wQuotationMark = ch;
2193            m_dwMode = FDE_XMLSYNTAXMODE_AttriValue;
2194            m_pStart++;
2195          }
2196          break;
2197        case FDE_XMLSYNTAXMODE_AttriValue:
2198          if (ch == m_wQuotationMark) {
2199            if (m_iEntityStart > -1) {
2200              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2201              return m_dwStatus;
2202            }
2203            m_iTextDataLength = m_iDataPos;
2204            m_wQuotationMark = 0;
2205            m_iDataPos = 0;
2206            m_pStart++;
2207            m_dwMode = FDE_XMLSYNTAXMODE_AttriName;
2208            dwStatus = FDE_XMLSYNTAXSTATUS_AttriValue;
2209          } else {
2210            ParseTextChar(ch);
2211          }
2212          break;
2213        case FDE_XMLSYNTAXMODE_CloseInstruction:
2214          if (ch != L'>') {
2215            if (m_iDataPos >= m_iTextDataSize) {
2216              ReallocTextDataBuffer();
2217            }
2218            m_pwsTextData[m_iDataPos++] = ch;
2219            m_dwMode = FDE_XMLSYNTAXMODE_TargetData;
2220          } else if (m_iDataPos > 0) {
2221            m_iTextDataLength = m_iDataPos;
2222            m_iDataPos = 0;
2223            dwStatus = FDE_XMLSYNTAXSTATUS_TargetData;
2224          } else {
2225            m_pStart++;
2226            FDE_LPXMLNODE pXMLNode = m_XMLNodeStack.GetTopElement();
2227            if (pXMLNode == NULL) {
2228              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2229              return m_dwStatus;
2230            }
2231            m_XMLNodeStack.Pop();
2232            pXMLNode = m_XMLNodeStack.GetTopElement();
2233            if (pXMLNode == NULL) {
2234              m_CurNode.iNodeNum = -1;
2235              m_CurNode.eNodeType = FDE_XMLNODE_Unknown;
2236            } else {
2237              m_CurNode = *pXMLNode;
2238            }
2239            m_iCurrentNodeNum = m_CurNode.iNodeNum;
2240            m_iDataPos = 0;
2241            m_dwMode = FDE_XMLSYNTAXMODE_Text;
2242            dwStatus = FDE_XMLSYNTAXSTATUS_InstructionClose;
2243          }
2244          break;
2245        case FDE_XMLSYNTAXMODE_BreakElement:
2246          if (ch == L'>') {
2247            m_dwMode = FDE_XMLSYNTAXMODE_Text;
2248            dwStatus = FDE_XMLSYNTAXSTATUS_ElementBreak;
2249          } else if (ch == L'/') {
2250            m_dwMode = FDE_XMLSYNTAXMODE_CloseElement;
2251          } else {
2252            m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2253            return m_dwStatus;
2254          }
2255          m_pStart++;
2256          break;
2257        case FDE_XMLSYNTAXMODE_CloseElement:
2258          if (!FDE_IsXMLNameChar(ch, m_iDataPos < 1)) {
2259            if (ch == L'>') {
2260              FDE_LPXMLNODE pXMLNode = m_XMLNodeStack.GetTopElement();
2261              if (pXMLNode == NULL) {
2262                m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2263                return m_dwStatus;
2264              }
2265              m_XMLNodeStack.Pop();
2266              pXMLNode = m_XMLNodeStack.GetTopElement();
2267              if (pXMLNode == NULL) {
2268                m_CurNode.iNodeNum = -1;
2269                m_CurNode.eNodeType = FDE_XMLNODE_Unknown;
2270              } else {
2271                m_CurNode = *pXMLNode;
2272              }
2273              m_iCurrentNodeNum = m_CurNode.iNodeNum;
2274              m_iTextDataLength = m_iDataPos;
2275              m_iDataPos = 0;
2276              m_dwMode = FDE_XMLSYNTAXMODE_Text;
2277              dwStatus = FDE_XMLSYNTAXSTATUS_ElementClose;
2278            } else if (!FDE_IsXMLWhiteSpace(ch)) {
2279              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2280              return m_dwStatus;
2281            }
2282          } else {
2283            if (m_iDataPos >= m_iTextDataSize) {
2284              ReallocTextDataBuffer();
2285            }
2286            m_pwsTextData[m_iDataPos++] = ch;
2287          }
2288          m_pStart++;
2289          break;
2290        case FDE_XMLSYNTAXMODE_SkipCommentOrDecl:
2291          if (ch == '-') {
2292            m_dwMode = FDE_XMLSYNTAXMODE_SkipComment;
2293          } else {
2294            m_dwMode = FDE_XMLSYNTAXMODE_SkipDeclNode;
2295            m_SkipChar = L'>';
2296            m_SkipStack.Push(L'>');
2297          }
2298          break;
2299        case FDE_XMLSYNTAXMODE_SkipDeclNode:
2300          if (m_SkipChar == L'\'' || m_SkipChar == L'\"') {
2301            m_pStart++;
2302            if (ch != m_SkipChar) {
2303              break;
2304            }
2305            m_SkipStack.Pop();
2306            FX_DWORD* pDWord = m_SkipStack.GetTopElement();
2307            if (pDWord == NULL) {
2308              m_dwMode = FDE_XMLSYNTAXMODE_Text;
2309            } else {
2310              m_SkipChar = (FX_WCHAR)*pDWord;
2311            }
2312          } else {
2313            switch (ch) {
2314              case L'<':
2315                m_SkipChar = L'>';
2316                m_SkipStack.Push(L'>');
2317                break;
2318              case L'[':
2319                m_SkipChar = L']';
2320                m_SkipStack.Push(L']');
2321                break;
2322              case L'(':
2323                m_SkipChar = L')';
2324                m_SkipStack.Push(L')');
2325                break;
2326              case L'\'':
2327                m_SkipChar = L'\'';
2328                m_SkipStack.Push(L'\'');
2329                break;
2330              case L'\"':
2331                m_SkipChar = L'\"';
2332                m_SkipStack.Push(L'\"');
2333                break;
2334              default:
2335                if (ch == m_SkipChar) {
2336                  m_SkipStack.Pop();
2337                  FX_DWORD* pDWord = m_SkipStack.GetTopElement();
2338                  if (pDWord == NULL) {
2339                    m_iTextDataLength = m_iDataPos;
2340                    m_iDataPos = 0;
2341                    if (m_iTextDataLength >= 9 &&
2342                        FXSYS_memcmp(m_pwsTextData, L"[CDATA[",
2343                                     7 * sizeof(FX_WCHAR)) == 0 &&
2344                        FXSYS_memcmp(m_pwsTextData + m_iTextDataLength - 2,
2345                                     L"]]", 2 * sizeof(FX_WCHAR)) == 0) {
2346                      m_iTextDataLength -= 9;
2347                      FXSYS_memmove(m_pwsTextData, m_pwsTextData + 7,
2348                                    m_iTextDataLength * sizeof(FX_WCHAR));
2349                      dwStatus = FDE_XMLSYNTAXSTATUS_CData;
2350                    }
2351                    m_dwMode = FDE_XMLSYNTAXMODE_Text;
2352                  } else {
2353                    m_SkipChar = (FX_WCHAR)*pDWord;
2354                  }
2355                }
2356                break;
2357            }
2358            if (m_SkipStack.GetSize() > 0) {
2359              if (m_iDataPos >= m_iTextDataSize) {
2360                ReallocTextDataBuffer();
2361              }
2362              m_pwsTextData[m_iDataPos++] = ch;
2363            }
2364            m_pStart++;
2365          }
2366          break;
2367        case FDE_XMLSYNTAXMODE_SkipComment:
2368          if (ch == L'-') {
2369            m_iDataPos++;
2370          } else if (ch == L'>') {
2371            if (m_iDataPos > 1) {
2372              m_iDataPos = 0;
2373              m_dwMode = FDE_XMLSYNTAXMODE_Text;
2374            }
2375          } else {
2376            m_iDataPos = 0;
2377          }
2378          m_pStart++;
2379          break;
2380        case FDE_XMLSYNTAXMODE_TargetData:
2381          if (FDE_IsXMLWhiteSpace(ch)) {
2382            if (m_iDataPos < 1) {
2383              m_pStart++;
2384              break;
2385            } else if (m_wQuotationMark == 0) {
2386              m_iTextDataLength = m_iDataPos;
2387              m_wQuotationMark = 0;
2388              m_iDataPos = 0;
2389              m_pStart++;
2390              dwStatus = FDE_XMLSYNTAXSTATUS_TargetData;
2391              break;
2392            }
2393          }
2394          if (ch == '?') {
2395            m_dwMode = FDE_XMLSYNTAXMODE_CloseInstruction;
2396            m_pStart++;
2397          } else if (ch == '\"') {
2398            if (m_wQuotationMark == 0) {
2399              m_wQuotationMark = ch;
2400              m_pStart++;
2401            } else if (ch == m_wQuotationMark) {
2402              m_iTextDataLength = m_iDataPos;
2403              m_wQuotationMark = 0;
2404              m_iDataPos = 0;
2405              m_pStart++;
2406              dwStatus = FDE_XMLSYNTAXSTATUS_TargetData;
2407            } else {
2408              m_dwStatus = FDE_XMLSYNTAXSTATUS_Error;
2409              return m_dwStatus;
2410            }
2411          } else {
2412            if (m_iDataPos >= m_iTextDataSize) {
2413              ReallocTextDataBuffer();
2414            }
2415            m_pwsTextData[m_iDataPos++] = ch;
2416            m_pStart++;
2417          }
2418          break;
2419        default:
2420          break;
2421      }
2422      if (dwStatus != FDE_XMLSYNTAXSTATUS_None) {
2423        return dwStatus;
2424      }
2425    }
2426  }
2427  return 0;
2428}
2429#endif
2430CFDE_XMLSyntaxParser::~CFDE_XMLSyntaxParser() {
2431#ifdef _FDE_BLOCK_BUFFER
2432  if (m_pCurrentBlock) {
2433    m_pCurrentBlock = NULL;
2434  }
2435#else
2436  FX_Free(m_pwsTextData);
2437#endif
2438  FX_Free(m_pBuffer);
2439}
2440int32_t CFDE_XMLSyntaxParser::GetStatus() const {
2441  if (m_pStream == NULL) {
2442    return -1;
2443  }
2444  int32_t iStreamLength = m_pStream->GetLength();
2445  if (iStreamLength < 1) {
2446    return 100;
2447  }
2448  if (m_dwStatus == FDE_XMLSYNTAXSTATUS_Error) {
2449    return -1;
2450  }
2451  if (m_dwStatus == FDE_XMLSYNTAXSTATUS_EOS) {
2452    return 100;
2453  }
2454  return m_iParsedBytes * 100 / iStreamLength;
2455}
2456static int32_t FX_GetUTF8EncodeLength(const FX_WCHAR* pSrc, int32_t iSrcLen) {
2457  FX_DWORD unicode = 0;
2458  int32_t iDstNum = 0;
2459  while (iSrcLen-- > 0) {
2460    unicode = *pSrc++;
2461    int nbytes = 0;
2462    if ((FX_DWORD)unicode < 0x80) {
2463      nbytes = 1;
2464    } else if ((FX_DWORD)unicode < 0x800) {
2465      nbytes = 2;
2466    } else if ((FX_DWORD)unicode < 0x10000) {
2467      nbytes = 3;
2468    } else if ((FX_DWORD)unicode < 0x200000) {
2469      nbytes = 4;
2470    } else if ((FX_DWORD)unicode < 0x4000000) {
2471      nbytes = 5;
2472    } else {
2473      nbytes = 6;
2474    }
2475    iDstNum += nbytes;
2476  }
2477  return iDstNum;
2478}
2479FX_FILESIZE CFDE_XMLSyntaxParser::GetCurrentBinaryPos() const {
2480  if (m_pStream == NULL) {
2481    return 0;
2482  }
2483  int32_t nSrcLen = m_pStart - m_pBuffer;
2484  int32_t nDstLen = FX_GetUTF8EncodeLength(m_pBuffer, nSrcLen);
2485  return m_iParsedBytes + nDstLen;
2486}
2487#ifdef _FDE_BLOCK_BUFFER
2488void CFDE_XMLSyntaxParser::ParseTextChar(FX_WCHAR ch) {
2489  if (m_iIndexInBlock == m_iAllocStep) {
2490    m_pCurrentBlock = m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
2491    if (!m_pCurrentBlock) {
2492      return;
2493    }
2494  }
2495  m_pCurrentBlock[m_iIndexInBlock++] = ch;
2496  m_iDataLength++;
2497  if (m_iEntityStart > -1 && ch == L';') {
2498    CFX_WideString csEntity;
2499    m_BlockBuffer.GetTextData(csEntity, m_iEntityStart + 1,
2500                              (m_iDataLength - 1) - m_iEntityStart - 1);
2501    int32_t iLen = csEntity.GetLength();
2502    if (iLen > 0) {
2503      if (csEntity[0] == L'#') {
2504        ch = 0;
2505        FX_WCHAR w;
2506        if (iLen > 1 && csEntity[1] == L'x') {
2507          for (int32_t i = 2; i < iLen; i++) {
2508            w = csEntity[i];
2509            if (w >= L'0' && w <= L'9') {
2510              ch = (ch << 4) + w - L'0';
2511            } else if (w >= L'A' && w <= L'F') {
2512              ch = (ch << 4) + w - 55;
2513            } else if (w >= L'a' && w <= L'f') {
2514              ch = (ch << 4) + w - 87;
2515            } else {
2516              break;
2517            }
2518          }
2519        } else {
2520          for (int32_t i = 1; i < iLen; i++) {
2521            w = csEntity[i];
2522            if (w < L'0' || w > L'9') {
2523              break;
2524            }
2525            ch = ch * 10 + w - L'0';
2526          }
2527        }
2528        if (ch != 0) {
2529          m_BlockBuffer.SetTextChar(m_iEntityStart, ch);
2530          m_iEntityStart++;
2531        }
2532      } else {
2533        if (csEntity.Compare(L"amp") == 0) {
2534          m_BlockBuffer.SetTextChar(m_iEntityStart, L'&');
2535          m_iEntityStart++;
2536        } else if (csEntity.Compare(L"lt") == 0) {
2537          m_BlockBuffer.SetTextChar(m_iEntityStart, L'<');
2538          m_iEntityStart++;
2539        } else if (csEntity.Compare(L"gt") == 0) {
2540          m_BlockBuffer.SetTextChar(m_iEntityStart, L'>');
2541          m_iEntityStart++;
2542        } else if (csEntity.Compare(L"apos") == 0) {
2543          m_BlockBuffer.SetTextChar(m_iEntityStart, L'\'');
2544          m_iEntityStart++;
2545        } else if (csEntity.Compare(L"quot") == 0) {
2546          m_BlockBuffer.SetTextChar(m_iEntityStart, L'\"');
2547          m_iEntityStart++;
2548        }
2549      }
2550    }
2551    m_BlockBuffer.DeleteTextChars(m_iDataLength - m_iEntityStart, FALSE);
2552    m_pCurrentBlock = m_BlockBuffer.GetAvailableBlock(m_iIndexInBlock);
2553    m_iEntityStart = -1;
2554  } else {
2555    if (m_iEntityStart < 0 && ch == L'&') {
2556      m_iEntityStart = m_iDataLength - 1;
2557    }
2558  }
2559  m_pStart++;
2560}
2561#else
2562void CFDE_XMLSyntaxParser::ParseTextChar(FX_WCHAR ch) {
2563  if (m_iDataPos >= m_iTextDataSize) {
2564    ReallocTextDataBuffer();
2565  }
2566  m_pwsTextData[m_iDataPos] = ch;
2567  if (m_iEntityStart > -1 && ch == L';') {
2568    CFX_WideString csEntity(m_pwsTextData + m_iEntityStart + 1,
2569                            m_iDataPos - m_iEntityStart - 1);
2570    int32_t iLen = csEntity.GetLength();
2571    if (iLen > 0) {
2572      if (csEntity[0] == L'#') {
2573        ch = 0;
2574        FX_WCHAR w;
2575        if (iLen > 1 && csEntity[1] == L'x') {
2576          for (int32_t i = 2; i < iLen; i++) {
2577            w = csEntity[i];
2578            if (w >= L'0' && w <= L'9') {
2579              ch = (ch << 4) + w - L'0';
2580            } else if (w >= L'A' && w <= L'F') {
2581              ch = (ch << 4) + w - 55;
2582            } else if (w >= L'a' && w <= L'f') {
2583              ch = (ch << 4) + w - 87;
2584            } else {
2585              break;
2586            }
2587          }
2588        } else {
2589          for (int32_t i = 1; i < iLen; i++) {
2590            w = csEntity[i];
2591            if (w < L'0' || w > L'9') {
2592              break;
2593            }
2594            ch = ch * 10 + w - L'0';
2595          }
2596        }
2597        if (ch != 0) {
2598          m_pwsTextData[m_iEntityStart++] = ch;
2599        }
2600      } else {
2601        if (csEntity.Compare(L"amp") == 0) {
2602          m_pwsTextData[m_iEntityStart++] = L'&';
2603        } else if (csEntity.Compare(L"lt") == 0) {
2604          m_pwsTextData[m_iEntityStart++] = L'<';
2605        } else if (csEntity.Compare(L"gt") == 0) {
2606          m_pwsTextData[m_iEntityStart++] = L'>';
2607        } else if (csEntity.Compare(L"apos") == 0) {
2608          m_pwsTextData[m_iEntityStart++] = L'\'';
2609        } else if (csEntity.Compare(L"quot") == 0) {
2610          m_pwsTextData[m_iEntityStart++] = L'\"';
2611        }
2612      }
2613    }
2614    m_iDataPos = m_iEntityStart;
2615    m_iEntityStart = -1;
2616  } else {
2617    if (m_iEntityStart < 0 && ch == L'&') {
2618      m_iEntityStart = m_iDataPos;
2619    }
2620    m_iDataPos++;
2621  }
2622  m_pStart++;
2623}
2624void CFDE_XMLSyntaxParser::ReallocTextDataBuffer() {
2625  FXSYS_assert(m_pwsTextData != NULL);
2626  if (m_iTextDataSize <= 1024 * 1024) {
2627    m_iTextDataSize *= 2;
2628  } else {
2629    m_iTextDataSize += 1024 * 1024;
2630  }
2631  m_pwsTextData = FX_Realloc(FX_WCHAR, m_pwsTextData, m_iTextDataSize);
2632}
2633void CFDE_XMLSyntaxParser::GetData(CFX_WideString& wsData) const {
2634  FX_WCHAR* pBuf = wsData.GetBuffer(m_iTextDataLength);
2635  FXSYS_memcpy(pBuf, m_pwsTextData, m_iTextDataLength * sizeof(FX_WCHAR));
2636  wsData.ReleaseBuffer(m_iTextDataLength);
2637}
2638#endif
2639