C++程序  |  1265行  |  45.01 KB

// Copyright 2016 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fxfa/parser/cxfa_simple_parser.h"

#include <utility>
#include <vector>

#include "core/fxcrt/cfx_checksumcontext.h"
#include "core/fxcrt/cfx_seekablestreamproxy.h"
#include "core/fxcrt/cfx_widetextbuf.h"
#include "core/fxcrt/fx_codepage.h"
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/xml/cfx_xmlchardata.h"
#include "core/fxcrt/xml/cfx_xmldoc.h"
#include "core/fxcrt/xml/cfx_xmlelement.h"
#include "core/fxcrt/xml/cfx_xmlinstruction.h"
#include "core/fxcrt/xml/cfx_xmlnode.h"
#include "core/fxcrt/xml/cfx_xmlparser.h"
#include "core/fxcrt/xml/cfx_xmltext.h"
#include "fxjs/xfa/cjx_object.h"
#include "third_party/base/logging.h"
#include "third_party/base/ptr_util.h"
#include "xfa/fxfa/fxfa.h"
#include "xfa/fxfa/parser/cxfa_document.h"
#include "xfa/fxfa/parser/cxfa_node.h"
#include "xfa/fxfa/parser/cxfa_subform.h"
#include "xfa/fxfa/parser/cxfa_template.h"
#include "xfa/fxfa/parser/xfa_basic_data.h"
#include "xfa/fxfa/parser/xfa_utils.h"

namespace {

struct PacketInfo {
  uint32_t hash;
  const wchar_t* name;
  XFA_PacketType packet_type;
  const wchar_t* uri;
  uint32_t flags;
};
const PacketInfo PacketData[] = {
    {0x0, nullptr, XFA_PacketType::User, nullptr,
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTMANY},
    {0x811929d, L"sourceSet", XFA_PacketType::SourceSet,
     L"http://www.xfa.org/schema/xfa-source-set/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0xb843dba, L"pdf", XFA_PacketType::Pdf, L"http://ns.adobe.com/xdp/pdf/",
     XFA_XDPPACKET_FLAGS_COMPLETEMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0xc56afbf, L"xdc", XFA_PacketType::Xdc, L"http://www.xfa.org/schema/xdc/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0xc56afcc, L"xdp", XFA_PacketType::Xdp, L"http://ns.adobe.com/xdp/",
     XFA_XDPPACKET_FLAGS_COMPLETEMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0x132a8fbc, L"xmpmeta", XFA_PacketType::Xmpmeta,
     L"http://ns.adobe.com/xmpmeta/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTMANY},
    {0x48d004a8, L"xfdf", XFA_PacketType::Xfdf, L"http://ns.adobe.com/xfdf/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0x4e1e39b6, L"config", XFA_PacketType::Config,
     L"http://www.xfa.org/schema/xci/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0x5473b6dc, L"localeSet", XFA_PacketType::LocaleSet,
     L"http://www.xfa.org/schema/xfa-locale-set/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0x6038580a, L"stylesheet", XFA_PacketType::Stylesheet,
     L"http://www.w3.org/1999/XSL/Transform",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTMANY},
    {0x803550fc, L"template", XFA_PacketType::Template,
     L"http://www.xfa.org/schema/xfa-template/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0x8b036f32, L"signature", XFA_PacketType::Signature,
     L"http://www.w3.org/2000/09/xmldsig#",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0x99b95079, L"datasets", XFA_PacketType::Datasets,
     L"http://www.xfa.org/schema/xfa-data/",
     XFA_XDPPACKET_FLAGS_PREFIXMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0xcd309ff4, L"form", XFA_PacketType::Form,
     L"http://www.xfa.org/schema/xfa-form/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
    {0xe14c801c, L"connectionSet", XFA_PacketType::ConnectionSet,
     L"http://www.xfa.org/schema/xfa-connection-set/",
     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
};

const PacketInfo* GetPacketByIndex(XFA_PacketType ePacket) {
  return PacketData + static_cast<uint8_t>(ePacket);
}

const PacketInfo* GetPacketByName(const WideStringView& wsName) {
  if (wsName.IsEmpty())
    return nullptr;

  uint32_t hash = FX_HashCode_GetW(wsName, false);
  auto* elem = std::lower_bound(
      std::begin(PacketData), std::end(PacketData), hash,
      [](const PacketInfo& a, uint32_t hash) { return a.hash < hash; });
  if (elem != std::end(PacketData) && elem->hash == hash)
    return elem;
  return nullptr;
}

CFX_XMLNode* GetDocumentNode(CFX_XMLDoc* pXMLDoc,
                             bool bVerifyWellFormness = false) {
  if (!pXMLDoc)
    return nullptr;

  for (CFX_XMLNode* pXMLNode =
           pXMLDoc->GetRoot()->GetNodeItem(CFX_XMLNode::FirstChild);
       pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
    if (pXMLNode->GetType() != FX_XMLNODE_Element)
      continue;

    if (!bVerifyWellFormness)
      return pXMLNode;

    for (CFX_XMLNode* pNextNode =
             pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
         pNextNode;
         pNextNode = pNextNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
      if (pNextNode->GetType() == FX_XMLNODE_Element)
        return nullptr;
    }
    return pXMLNode;
  }
  return nullptr;
}

WideString GetElementTagNamespaceURI(CFX_XMLElement* pElement) {
  WideString wsNodeStr = pElement->GetNamespacePrefix();
  WideString wsNamespaceURI;
  if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNodeStr,
                                                  &wsNamespaceURI)) {
    return WideString();
  }
  return wsNamespaceURI;
}

bool MatchNodeName(CFX_XMLNode* pNode,
                   const WideStringView& wsLocalTagName,
                   const WideStringView& wsNamespaceURIPrefix,
                   uint32_t eMatchFlags = XFA_XDPPACKET_FLAGS_NOMATCH) {
  if (!pNode || pNode->GetType() != FX_XMLNODE_Element)
    return false;

  CFX_XMLElement* pElement = reinterpret_cast<CFX_XMLElement*>(pNode);
  WideString wsNodeStr = pElement->GetLocalTagName();
  if (wsNodeStr != wsLocalTagName)
    return false;

  wsNodeStr = GetElementTagNamespaceURI(pElement);
  if (eMatchFlags & XFA_XDPPACKET_FLAGS_NOMATCH)
    return true;
  if (eMatchFlags & XFA_XDPPACKET_FLAGS_PREFIXMATCH) {
    return wsNodeStr.Left(wsNamespaceURIPrefix.GetLength()) ==
           wsNamespaceURIPrefix;
  }

  return wsNodeStr == wsNamespaceURIPrefix;
}

bool GetAttributeLocalName(const WideStringView& wsAttributeName,
                           WideString& wsLocalAttrName) {
  WideString wsAttrName(wsAttributeName);
  auto pos = wsAttrName.Find(L':', 0);
  if (!pos.has_value()) {
    wsLocalAttrName = wsAttrName;
    return false;
  }
  wsLocalAttrName = wsAttrName.Right(wsAttrName.GetLength() - pos.value() - 1);
  return true;
}

bool ResolveAttribute(CFX_XMLElement* pElement,
                      const WideString& wsAttrName,
                      WideString& wsLocalAttrName,
                      WideString& wsNamespaceURI) {
  WideString wsNSPrefix;
  if (GetAttributeLocalName(wsAttrName.AsStringView(), wsLocalAttrName)) {
    wsNSPrefix = wsAttrName.Left(wsAttrName.GetLength() -
                                 wsLocalAttrName.GetLength() - 1);
  }
  if (wsLocalAttrName == L"xmlns" || wsNSPrefix == L"xmlns" ||
      wsNSPrefix == L"xml") {
    return false;
  }
  if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNSPrefix,
                                                  &wsNamespaceURI)) {
    wsNamespaceURI.clear();
    return false;
  }
  return true;
}

bool FindAttributeWithNS(CFX_XMLElement* pElement,
                         const WideStringView& wsLocalAttributeName,
                         const WideStringView& wsNamespaceURIPrefix,
                         WideString& wsValue,
                         bool bMatchNSAsPrefix = false) {
  if (!pElement)
    return false;

  WideString wsAttrNS;
  for (auto it : pElement->GetAttributes()) {
    auto pos = it.first.Find(L':', 0);
    WideString wsNSPrefix;
    if (!pos.has_value()) {
      if (wsLocalAttributeName != it.first)
        continue;
    } else {
      if (wsLocalAttributeName !=
          it.first.Right(it.first.GetLength() - pos.value() - 1)) {
        continue;
      }
      wsNSPrefix = it.first.Left(pos.value());
    }

    if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNSPrefix,
                                                    &wsAttrNS)) {
      continue;
    }
    if (bMatchNSAsPrefix) {
      if (wsAttrNS.Left(wsNamespaceURIPrefix.GetLength()) !=
          wsNamespaceURIPrefix) {
        continue;
      }
    } else {
      if (wsAttrNS != wsNamespaceURIPrefix)
        continue;
    }
    wsValue = it.second;
    return true;
  }
  return false;
}

CFX_XMLNode* GetDataSetsFromXDP(CFX_XMLNode* pXMLDocumentNode) {
  const PacketInfo* datasets_packet =
      GetPacketByIndex(XFA_PacketType::Datasets);
  if (MatchNodeName(pXMLDocumentNode, datasets_packet->name,
                    datasets_packet->uri, datasets_packet->flags)) {
    return pXMLDocumentNode;
  }

  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Xdp);
  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
                     packet->flags)) {
    return nullptr;
  }

  for (CFX_XMLNode* pDatasetsNode =
           pXMLDocumentNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pDatasetsNode;
       pDatasetsNode = pDatasetsNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
    if (MatchNodeName(pDatasetsNode, datasets_packet->name,
                      datasets_packet->uri, datasets_packet->flags)) {
      return pDatasetsNode;
    }
  }
  return nullptr;
}

bool IsStringAllWhitespace(WideString wsText) {
  wsText.TrimRight(L"\x20\x9\xD\xA");
  return wsText.IsEmpty();
}

void ConvertXMLToPlainText(CFX_XMLElement* pRootXMLNode, WideString& wsOutput) {
  for (CFX_XMLNode* pXMLChild =
           pRootXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pXMLChild;
       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
    switch (pXMLChild->GetType()) {
      case FX_XMLNODE_Element: {
        WideString wsTextData =
            static_cast<CFX_XMLElement*>(pXMLChild)->GetTextData();
        wsTextData += L"\n";
        wsOutput += wsTextData;
        break;
      }
      case FX_XMLNODE_Text:
      case FX_XMLNODE_CharData: {
        WideString wsText = static_cast<CFX_XMLText*>(pXMLChild)->GetText();
        if (IsStringAllWhitespace(wsText))
          continue;

        wsOutput = wsText;
        break;
      }
      default:
        NOTREACHED();
        break;
    }
  }
}

WideString GetPlainTextFromRichText(CFX_XMLNode* pXMLNode) {
  if (!pXMLNode)
    return L"";

  WideString wsPlainText;
  switch (pXMLNode->GetType()) {
    case FX_XMLNODE_Element: {
      CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
      WideString wsTag = pXMLElement->GetLocalTagName();
      uint32_t uTag = FX_HashCode_GetW(wsTag.AsStringView(), true);
      if (uTag == 0x0001f714) {
        wsPlainText += L"\n";
      } else if (uTag == 0x00000070) {
        if (!wsPlainText.IsEmpty()) {
          wsPlainText += L"\n";
        }
      } else if (uTag == 0xa48ac63) {
        if (!wsPlainText.IsEmpty() &&
            wsPlainText[wsPlainText.GetLength() - 1] != '\n') {
          wsPlainText += L"\n";
        }
      }
      break;
    }
    case FX_XMLNODE_Text:
    case FX_XMLNODE_CharData: {
      WideString wsContent = static_cast<CFX_XMLText*>(pXMLNode)->GetText();
      wsPlainText += wsContent;
      break;
    }
    default:
      break;
  }
  for (CFX_XMLNode* pChildXML = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pChildXML;
       pChildXML = pChildXML->GetNodeItem(CFX_XMLNode::NextSibling)) {
    wsPlainText += GetPlainTextFromRichText(pChildXML);
  }

  return wsPlainText;
}

}  // namespace

bool XFA_RecognizeRichText(CFX_XMLElement* pRichTextXMLNode) {
  return pRichTextXMLNode && GetElementTagNamespaceURI(pRichTextXMLNode) ==
                                 L"http://www.w3.org/1999/xhtml";
}

CXFA_SimpleParser::CXFA_SimpleParser() : m_bDocumentParser(true) {}

CXFA_SimpleParser::CXFA_SimpleParser(CXFA_Document* pFactory)
    : m_pFactory(pFactory), m_bDocumentParser(false) {}

CXFA_SimpleParser::~CXFA_SimpleParser() {}

void CXFA_SimpleParser::SetFactory(CXFA_Document* pFactory) {
  ASSERT(m_bDocumentParser);
  m_pFactory = pFactory;
}

int32_t CXFA_SimpleParser::StartParse(
    const RetainPtr<IFX_SeekableStream>& pStream,
    XFA_PacketType ePacketID) {
  CloseParser();
  m_pFileRead = pStream;
  m_pStream = pdfium::MakeRetain<CFX_SeekableStreamProxy>(pStream, false);
  uint16_t wCodePage = m_pStream->GetCodePage();
  if (wCodePage != FX_CODEPAGE_UTF16LE && wCodePage != FX_CODEPAGE_UTF16BE &&
      wCodePage != FX_CODEPAGE_UTF8) {
    m_pStream->SetCodePage(FX_CODEPAGE_UTF8);
  }
  m_pXMLDoc = pdfium::MakeUnique<CFX_XMLDoc>();
  auto pNewParser =
      pdfium::MakeUnique<CFX_XMLParser>(m_pXMLDoc->GetRoot(), m_pStream);
  m_pXMLParser = pNewParser.get();
  if (!m_pXMLDoc->LoadXML(std::move(pNewParser)))
    return XFA_PARSESTATUS_StatusErr;

  m_bParseStarted = true;
  m_ePacketID = ePacketID;
  return XFA_PARSESTATUS_Ready;
}

int32_t CXFA_SimpleParser::DoParse() {
  if (!m_pXMLDoc || !m_bParseStarted)
    return XFA_PARSESTATUS_StatusErr;

  int32_t iRet = m_pXMLDoc->DoLoad();
  if (iRet < 0)
    return XFA_PARSESTATUS_SyntaxErr;
  if (iRet < 100)
    return iRet / 2;

  m_pRootNode = ParseAsXDPPacket(GetDocumentNode(m_pXMLDoc.get()), m_ePacketID);
  m_pXMLParser.Release();
  m_pXMLDoc->CloseXML();
  m_pStream.Reset();

  if (!m_pRootNode)
    return XFA_PARSESTATUS_StatusErr;

  return XFA_PARSESTATUS_Done;
}

CFX_XMLNode* CXFA_SimpleParser::ParseXMLData(const ByteString& wsXML) {
  CloseParser();
  m_pXMLDoc = pdfium::MakeUnique<CFX_XMLDoc>();

  auto pStream = pdfium::MakeRetain<CFX_SeekableStreamProxy>(
      const_cast<uint8_t*>(wsXML.raw_str()), wsXML.GetLength());
  auto pParser =
      pdfium::MakeUnique<CFX_XMLParser>(m_pXMLDoc->GetRoot(), pStream);
  pParser->m_dwCheckStatus = 0x03;
  if (!m_pXMLDoc->LoadXML(std::move(pParser)))
    return nullptr;

  int32_t iRet = m_pXMLDoc->DoLoad();
  if (iRet < 0 || iRet >= 100)
    m_pXMLDoc->CloseXML();
  return iRet < 100 ? nullptr : GetDocumentNode(m_pXMLDoc.get());
}

void CXFA_SimpleParser::ConstructXFANode(CXFA_Node* pXFANode,
                                         CFX_XMLNode* pXMLNode) {
  XFA_PacketType ePacketID = pXFANode->GetPacketType();
  if (ePacketID == XFA_PacketType::Datasets) {
    if (pXFANode->GetElementType() == XFA_Element::DataValue) {
      for (CFX_XMLNode* pXMLChild =
               pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
           pXMLChild;
           pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
        FX_XMLNODETYPE eNodeType = pXMLChild->GetType();
        if (eNodeType == FX_XMLNODE_Instruction)
          continue;

        if (eNodeType == FX_XMLNODE_Element) {
          CXFA_Node* pXFAChild = m_pFactory->CreateNode(
              XFA_PacketType::Datasets, XFA_Element::DataValue);
          if (!pXFAChild)
            return;

          CFX_XMLElement* child = static_cast<CFX_XMLElement*>(pXMLChild);
          WideString wsNodeStr = child->GetLocalTagName();
          pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, wsNodeStr, false,
                                          false);
          WideString wsChildValue = GetPlainTextFromRichText(child);
          if (!wsChildValue.IsEmpty())
            pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsChildValue,
                                            false, false);

          pXFANode->InsertChild(pXFAChild, nullptr);
          pXFAChild->SetXMLMappingNode(pXMLChild);
          pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
          break;
        }
      }
      m_pRootNode = pXFANode;
    } else {
      m_pRootNode = DataLoader(pXFANode, pXMLNode, true);
    }
  } else if (pXFANode->IsContentNode()) {
    ParseContentNode(pXFANode, pXMLNode, ePacketID);
    m_pRootNode = pXFANode;
  } else {
    m_pRootNode = NormalLoader(pXFANode, pXMLNode, ePacketID, true);
  }
}

CXFA_Node* CXFA_SimpleParser::GetRootNode() const {
  return m_pRootNode;
}

CFX_XMLDoc* CXFA_SimpleParser::GetXMLDoc() const {
  return m_pXMLDoc.get();
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket(CFX_XMLNode* pXMLDocumentNode,
                                               XFA_PacketType ePacketID) {
  switch (ePacketID) {
    case XFA_PacketType::Xdp:
      return ParseAsXDPPacket_XDP(pXMLDocumentNode);
    case XFA_PacketType::Config:
      return ParseAsXDPPacket_Config(pXMLDocumentNode);
    case XFA_PacketType::Template:
      return ParseAsXDPPacket_Template(pXMLDocumentNode);
    case XFA_PacketType::Form:
      return ParseAsXDPPacket_Form(pXMLDocumentNode);
    case XFA_PacketType::Datasets:
      return ParseAsXDPPacket_Data(pXMLDocumentNode);
    case XFA_PacketType::Xdc:
      return ParseAsXDPPacket_Xdc(pXMLDocumentNode);
    case XFA_PacketType::LocaleSet:
      return ParseAsXDPPacket_LocaleConnectionSourceSet(
          pXMLDocumentNode, XFA_PacketType::LocaleSet, XFA_Element::LocaleSet);
    case XFA_PacketType::ConnectionSet:
      return ParseAsXDPPacket_LocaleConnectionSourceSet(
          pXMLDocumentNode, XFA_PacketType::ConnectionSet,
          XFA_Element::ConnectionSet);
    case XFA_PacketType::SourceSet:
      return ParseAsXDPPacket_LocaleConnectionSourceSet(
          pXMLDocumentNode, XFA_PacketType::SourceSet, XFA_Element::SourceSet);
    default:
      return ParseAsXDPPacket_User(pXMLDocumentNode);
  }
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_XDP(
    CFX_XMLNode* pXMLDocumentNode) {
  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Xdp);
  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
                     packet->flags)) {
    return nullptr;
  }

  CXFA_Node* pXFARootNode =
      m_pFactory->CreateNode(XFA_PacketType::Xdp, XFA_Element::Xfa);
  if (!pXFARootNode)
    return nullptr;

  m_pRootNode = pXFARootNode;
  pXFARootNode->JSObject()->SetCData(XFA_Attribute::Name, L"xfa", false, false);

  CFX_XMLElement* pElement = static_cast<CFX_XMLElement*>(pXMLDocumentNode);
  for (auto it : pElement->GetAttributes()) {
    if (it.first == L"uuid")
      pXFARootNode->JSObject()->SetCData(XFA_Attribute::Uuid, it.second, false,
                                         false);
    else if (it.first == L"timeStamp")
      pXFARootNode->JSObject()->SetCData(XFA_Attribute::TimeStamp, it.second,
                                         false, false);
  }

  CFX_XMLNode* pXMLConfigDOMRoot = nullptr;
  CXFA_Node* pXFAConfigDOMRoot = nullptr;
  for (CFX_XMLNode* pChildItem =
           pXMLDocumentNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pChildItem;
       pChildItem = pChildItem->GetNodeItem(CFX_XMLNode::NextSibling)) {
    const PacketInfo* pPacketInfo = GetPacketByIndex(XFA_PacketType::Config);
    if (!MatchNodeName(pChildItem, pPacketInfo->name, pPacketInfo->uri,
                       pPacketInfo->flags)) {
      continue;
    }
    if (pXFARootNode->GetFirstChildByName(pPacketInfo->hash))
      return nullptr;

    pXMLConfigDOMRoot = pChildItem;
    pXFAConfigDOMRoot = ParseAsXDPPacket_Config(pXMLConfigDOMRoot);
    if (pXFAConfigDOMRoot)
      pXFARootNode->InsertChild(pXFAConfigDOMRoot, nullptr);
  }

  CFX_XMLNode* pXMLDatasetsDOMRoot = nullptr;
  CFX_XMLNode* pXMLFormDOMRoot = nullptr;
  CFX_XMLNode* pXMLTemplateDOMRoot = nullptr;
  for (CFX_XMLNode* pChildItem =
           pXMLDocumentNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pChildItem;
       pChildItem = pChildItem->GetNodeItem(CFX_XMLNode::NextSibling)) {
    if (!pChildItem || pChildItem->GetType() != FX_XMLNODE_Element)
      continue;
    if (pChildItem == pXMLConfigDOMRoot)
      continue;

    CFX_XMLElement* pElement = reinterpret_cast<CFX_XMLElement*>(pChildItem);
    WideString wsPacketName = pElement->GetLocalTagName();
    const PacketInfo* pPacketInfo =
        GetPacketByName(wsPacketName.AsStringView());
    if (pPacketInfo && pPacketInfo->uri) {
      if (!MatchNodeName(pElement, pPacketInfo->name, pPacketInfo->uri,
                         pPacketInfo->flags)) {
        pPacketInfo = nullptr;
      }
    }
    XFA_PacketType ePacket =
        pPacketInfo ? pPacketInfo->packet_type : XFA_PacketType::User;
    if (ePacket == XFA_PacketType::Xdp)
      continue;
    if (ePacket == XFA_PacketType::Datasets) {
      if (pXMLDatasetsDOMRoot)
        return nullptr;

      pXMLDatasetsDOMRoot = pElement;
    } else if (ePacket == XFA_PacketType::Form) {
      if (pXMLFormDOMRoot)
        return nullptr;

      pXMLFormDOMRoot = pElement;
    } else if (ePacket == XFA_PacketType::Template) {
      // Found a duplicate template packet.
      if (pXMLTemplateDOMRoot)
        return nullptr;

      CXFA_Node* pPacketNode = ParseAsXDPPacket(pElement, ePacket);
      if (pPacketNode) {
        pXMLTemplateDOMRoot = pElement;
        pXFARootNode->InsertChild(pPacketNode, nullptr);
      }
    } else {
      CXFA_Node* pPacketNode = ParseAsXDPPacket(pElement, ePacket);
      if (pPacketNode) {
        if (pPacketInfo &&
            (pPacketInfo->flags & XFA_XDPPACKET_FLAGS_SUPPORTONE) &&
            pXFARootNode->GetFirstChildByName(pPacketInfo->hash)) {
          return nullptr;
        }
        pXFARootNode->InsertChild(pPacketNode, nullptr);
      }
    }
  }

  // No template is found.
  if (!pXMLTemplateDOMRoot)
    return nullptr;

  if (pXMLDatasetsDOMRoot) {
    CXFA_Node* pPacketNode =
        ParseAsXDPPacket(pXMLDatasetsDOMRoot, XFA_PacketType::Datasets);
    if (pPacketNode)
      pXFARootNode->InsertChild(pPacketNode, nullptr);
  }
  if (pXMLFormDOMRoot) {
    CXFA_Node* pPacketNode =
        ParseAsXDPPacket(pXMLFormDOMRoot, XFA_PacketType::Form);
    if (pPacketNode)
      pXFARootNode->InsertChild(pPacketNode, nullptr);
  }

  pXFARootNode->SetXMLMappingNode(pXMLDocumentNode);
  return pXFARootNode;
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Config(
    CFX_XMLNode* pXMLDocumentNode) {
  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Config);
  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
                     packet->flags)) {
    return nullptr;
  }
  CXFA_Node* pNode =
      m_pFactory->CreateNode(XFA_PacketType::Config, XFA_Element::Config);
  if (!pNode)
    return nullptr;

  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Config, true))
    return nullptr;

  pNode->SetXMLMappingNode(pXMLDocumentNode);
  return pNode;
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Template(
    CFX_XMLNode* pXMLDocumentNode) {
  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Template);
  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
                     packet->flags)) {
    return nullptr;
  }

  CXFA_Node* pNode =
      m_pFactory->CreateNode(XFA_PacketType::Template, XFA_Element::Template);
  if (!pNode)
    return nullptr;

  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
  if (m_bDocumentParser) {
    CFX_XMLElement* pXMLDocumentElement =
        static_cast<CFX_XMLElement*>(pXMLDocumentNode);
    WideString wsNamespaceURI = pXMLDocumentElement->GetNamespaceURI();
    if (wsNamespaceURI.IsEmpty())
      wsNamespaceURI = pXMLDocumentElement->GetString(L"xmlns:xfa");

    pNode->GetDocument()->RecognizeXFAVersionNumber(wsNamespaceURI);
  }
  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Template, true))
    return nullptr;

  pNode->SetXMLMappingNode(pXMLDocumentNode);
  return pNode;
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Form(
    CFX_XMLNode* pXMLDocumentNode) {
  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Form);
  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
                     packet->flags)) {
    return nullptr;
  }

  CFX_XMLElement* pXMLDocumentElement =
      static_cast<CFX_XMLElement*>(pXMLDocumentNode);
  WideString wsChecksum = pXMLDocumentElement->GetString(L"checksum");
  if (wsChecksum.GetLength() != 28 || m_pXMLParser->m_dwCheckStatus != 0x03) {
    return nullptr;
  }

  auto pChecksum = pdfium::MakeUnique<CFX_ChecksumContext>();
  pChecksum->StartChecksum();
  pChecksum->UpdateChecksum(m_pFileRead, m_pXMLParser->m_nStart[0],
                            m_pXMLParser->m_nSize[0]);
  pChecksum->UpdateChecksum(m_pFileRead, m_pXMLParser->m_nStart[1],
                            m_pXMLParser->m_nSize[1]);
  pChecksum->FinishChecksum();
  ByteString bsCheck = pChecksum->GetChecksum();
  if (bsCheck != wsChecksum.UTF8Encode())
    return nullptr;

  CXFA_Node* pNode =
      m_pFactory->CreateNode(XFA_PacketType::Form, XFA_Element::Form);
  if (!pNode)
    return nullptr;

  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
  pNode->JSObject()->SetAttribute(XFA_Attribute::Checksum,
                                  wsChecksum.AsStringView(), false);
  CXFA_Template* pTemplateRoot =
      m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
  CXFA_Subform* pTemplateChosen =
      pTemplateRoot ? pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(
                          XFA_Element::Subform)
                    : nullptr;
  bool bUseAttribute = true;
  if (pTemplateChosen &&
      pTemplateChosen->JSObject()->GetEnum(XFA_Attribute::RestoreState) !=
          XFA_AttributeEnum::Auto) {
    bUseAttribute = false;
  }
  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Form,
                    bUseAttribute))
    return nullptr;

  pNode->SetXMLMappingNode(pXMLDocumentNode);
  return pNode;
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Data(
    CFX_XMLNode* pXMLDocumentNode) {
  CFX_XMLNode* pDatasetsXMLNode = GetDataSetsFromXDP(pXMLDocumentNode);
  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Datasets);
  if (pDatasetsXMLNode) {
    CXFA_Node* pNode = m_pFactory->CreateNode(XFA_PacketType::Datasets,
                                              XFA_Element::DataModel);
    if (!pNode)
      return nullptr;

    pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false,
                                false);
    if (!DataLoader(pNode, pDatasetsXMLNode, false))
      return nullptr;

    pNode->SetXMLMappingNode(pDatasetsXMLNode);
    return pNode;
  }

  CFX_XMLNode* pDataXMLNode = nullptr;
  if (MatchNodeName(pXMLDocumentNode, L"data", packet->uri, packet->flags)) {
    static_cast<CFX_XMLElement*>(pXMLDocumentNode)
        ->RemoveAttribute(L"xmlns:xfa");
    pDataXMLNode = pXMLDocumentNode;
  } else {
    CFX_XMLElement* pDataElement = new CFX_XMLElement(L"xfa:data");
    CFX_XMLNode* pParentXMLNode =
        pXMLDocumentNode->GetNodeItem(CFX_XMLNode::Parent);
    if (pParentXMLNode)
      pParentXMLNode->RemoveChildNode(pXMLDocumentNode);

    ASSERT(pXMLDocumentNode->GetType() == FX_XMLNODE_Element);
    if (pXMLDocumentNode->GetType() == FX_XMLNODE_Element) {
      static_cast<CFX_XMLElement*>(pXMLDocumentNode)
          ->RemoveAttribute(L"xmlns:xfa");
    }
    pDataElement->InsertChildNode(pXMLDocumentNode);
    pDataXMLNode = pDataElement;
  }

  if (pDataXMLNode) {
    CXFA_Node* pNode = m_pFactory->CreateNode(XFA_PacketType::Datasets,
                                              XFA_Element::DataGroup);
    if (!pNode) {
      if (pDataXMLNode != pXMLDocumentNode)
        delete pDataXMLNode;
      return nullptr;
    }
    WideString wsLocalName =
        static_cast<CFX_XMLElement*>(pDataXMLNode)->GetLocalTagName();
    pNode->JSObject()->SetCData(XFA_Attribute::Name, wsLocalName, false, false);
    if (!DataLoader(pNode, pDataXMLNode, true))
      return nullptr;

    pNode->SetXMLMappingNode(pDataXMLNode);
    if (pDataXMLNode != pXMLDocumentNode)
      pNode->SetFlag(XFA_NodeFlag_OwnXMLNode, false);
    return pNode;
  }
  return nullptr;
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_LocaleConnectionSourceSet(
    CFX_XMLNode* pXMLDocumentNode,
    XFA_PacketType packet_type,
    XFA_Element element) {
  const PacketInfo* packet = GetPacketByIndex(packet_type);
  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
                     packet->flags)) {
    return nullptr;
  }

  CXFA_Node* pNode = m_pFactory->CreateNode(packet_type, element);
  if (!pNode)
    return nullptr;

  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
  if (!NormalLoader(pNode, pXMLDocumentNode, packet_type, true))
    return nullptr;

  pNode->SetXMLMappingNode(pXMLDocumentNode);
  return pNode;
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Xdc(
    CFX_XMLNode* pXMLDocumentNode) {
  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Xdc);
  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
                     packet->flags))
    return nullptr;

  CXFA_Node* pNode =
      m_pFactory->CreateNode(XFA_PacketType::Xdc, XFA_Element::Xdc);
  if (!pNode)
    return nullptr;

  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
  pNode->SetXMLMappingNode(pXMLDocumentNode);
  return pNode;
}

CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_User(
    CFX_XMLNode* pXMLDocumentNode) {
  CXFA_Node* pNode =
      m_pFactory->CreateNode(XFA_PacketType::Xdp, XFA_Element::Packet);
  if (!pNode)
    return nullptr;

  WideString wsName =
      static_cast<CFX_XMLElement*>(pXMLDocumentNode)->GetLocalTagName();
  pNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
  if (!UserPacketLoader(pNode, pXMLDocumentNode))
    return nullptr;

  pNode->SetXMLMappingNode(pXMLDocumentNode);
  return pNode;
}

CXFA_Node* CXFA_SimpleParser::UserPacketLoader(CXFA_Node* pXFANode,
                                               CFX_XMLNode* pXMLDoc) {
  return pXFANode;
}

CXFA_Node* CXFA_SimpleParser::DataLoader(CXFA_Node* pXFANode,
                                         CFX_XMLNode* pXMLDoc,
                                         bool bDoTransform) {
  ParseDataGroup(pXFANode, pXMLDoc, XFA_PacketType::Datasets);
  return pXFANode;
}

CXFA_Node* CXFA_SimpleParser::NormalLoader(CXFA_Node* pXFANode,
                                           CFX_XMLNode* pXMLDoc,
                                           XFA_PacketType ePacketID,
                                           bool bUseAttribute) {
  bool bOneOfPropertyFound = false;
  for (CFX_XMLNode* pXMLChild = pXMLDoc->GetNodeItem(CFX_XMLNode::FirstChild);
       pXMLChild;
       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
    switch (pXMLChild->GetType()) {
      case FX_XMLNODE_Element: {
        CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
        WideString wsTagName = pXMLElement->GetLocalTagName();
        XFA_Element eType = CXFA_Node::NameToElement(wsTagName);
        if (eType == XFA_Element::Unknown)
          continue;

        if (pXFANode->HasPropertyFlags(
                eType,
                XFA_PROPERTYFLAG_OneOf | XFA_PROPERTYFLAG_DefaultOneOf)) {
          if (bOneOfPropertyFound)
            break;
          bOneOfPropertyFound = true;
        }

        CXFA_Node* pXFAChild = m_pFactory->CreateNode(ePacketID, eType);
        if (!pXFAChild)
          return nullptr;
        if (ePacketID == XFA_PacketType::Config) {
          pXFAChild->JSObject()->SetAttribute(XFA_Attribute::Name,
                                              wsTagName.AsStringView(), false);
        }

        bool IsNeedValue = true;
        for (auto it : pXMLElement->GetAttributes()) {
          WideString wsAttrName;
          GetAttributeLocalName(it.first.AsStringView(), wsAttrName);
          if (wsAttrName == L"nil" && it.second == L"true")
            IsNeedValue = false;

          XFA_Attribute attr =
              CXFA_Node::NameToAttribute(wsAttrName.AsStringView());
          if (attr == XFA_Attribute::Unknown)
            continue;

          if (!bUseAttribute && attr != XFA_Attribute::Name &&
              attr != XFA_Attribute::Save) {
            continue;
          }
          pXFAChild->JSObject()->SetAttribute(attr, it.second.AsStringView(),
                                              false);
        }
        pXFANode->InsertChild(pXFAChild, nullptr);
        if (eType == XFA_Element::Validate || eType == XFA_Element::Locale) {
          if (ePacketID == XFA_PacketType::Config)
            ParseContentNode(pXFAChild, pXMLElement, ePacketID);
          else
            NormalLoader(pXFAChild, pXMLElement, ePacketID, bUseAttribute);

          break;
        }
        switch (pXFAChild->GetObjectType()) {
          case XFA_ObjectType::ContentNode:
          case XFA_ObjectType::TextNode:
          case XFA_ObjectType::NodeC:
          case XFA_ObjectType::NodeV:
            if (IsNeedValue)
              ParseContentNode(pXFAChild, pXMLElement, ePacketID);
            break;
          default:
            NormalLoader(pXFAChild, pXMLElement, ePacketID, bUseAttribute);
            break;
        }
      } break;
      case FX_XMLNODE_Instruction:
        ParseInstruction(pXFANode, static_cast<CFX_XMLInstruction*>(pXMLChild),
                         ePacketID);
        break;
      default:
        break;
    }
  }
  return pXFANode;
}

void CXFA_SimpleParser::ParseContentNode(CXFA_Node* pXFANode,
                                         CFX_XMLNode* pXMLNode,
                                         XFA_PacketType ePacketID) {
  XFA_Element element = XFA_Element::Sharptext;
  if (pXFANode->GetElementType() == XFA_Element::ExData) {
    WideString wsContentType =
        pXFANode->JSObject()->GetCData(XFA_Attribute::ContentType);
    if (wsContentType == L"text/html")
      element = XFA_Element::SharpxHTML;
    else if (wsContentType == L"text/xml")
      element = XFA_Element::Sharpxml;
  }
  if (element == XFA_Element::SharpxHTML)
    pXFANode->SetXMLMappingNode(pXMLNode);

  WideString wsValue;
  for (CFX_XMLNode* pXMLChild = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pXMLChild;
       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
    FX_XMLNODETYPE eNodeType = pXMLChild->GetType();
    if (eNodeType == FX_XMLNODE_Instruction)
      continue;

    if (element == XFA_Element::SharpxHTML) {
      if (eNodeType != FX_XMLNODE_Element)
        break;

      if (XFA_RecognizeRichText(static_cast<CFX_XMLElement*>(pXMLChild)))
        wsValue +=
            GetPlainTextFromRichText(static_cast<CFX_XMLElement*>(pXMLChild));
    } else if (element == XFA_Element::Sharpxml) {
      if (eNodeType != FX_XMLNODE_Element)
        break;

      ConvertXMLToPlainText(static_cast<CFX_XMLElement*>(pXMLChild), wsValue);
    } else {
      if (eNodeType == FX_XMLNODE_Element)
        break;
      if (eNodeType == FX_XMLNODE_Text || eNodeType == FX_XMLNODE_CharData)
        wsValue = static_cast<CFX_XMLText*>(pXMLChild)->GetText();
    }
    break;
  }
  if (!wsValue.IsEmpty()) {
    if (pXFANode->IsContentNode()) {
      CXFA_Node* pContentRawDataNode =
          m_pFactory->CreateNode(ePacketID, element);
      ASSERT(pContentRawDataNode);
      pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value, wsValue,
                                                false, false);
      pXFANode->InsertChild(pContentRawDataNode, nullptr);
    } else {
      pXFANode->JSObject()->SetCData(XFA_Attribute::Value, wsValue, false,
                                     false);
    }
  }
}

void CXFA_SimpleParser::ParseDataGroup(CXFA_Node* pXFANode,
                                       CFX_XMLNode* pXMLNode,
                                       XFA_PacketType ePacketID) {
  for (CFX_XMLNode* pXMLChild = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pXMLChild;
       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
    switch (pXMLChild->GetType()) {
      case FX_XMLNODE_Element: {
        CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
        {
          WideString wsNamespaceURI = GetElementTagNamespaceURI(pXMLElement);
          if (wsNamespaceURI == L"http://www.xfa.com/schema/xfa-package/" ||
              wsNamespaceURI == L"http://www.xfa.org/schema/xfa-package/" ||
              wsNamespaceURI == L"http://www.w3.org/2001/XMLSchema-instance") {
            continue;
          }
        }

        XFA_Element eNodeType = XFA_Element::DataModel;
        if (eNodeType == XFA_Element::DataModel) {
          WideString wsDataNodeAttr;
          if (FindAttributeWithNS(pXMLElement, L"dataNode",
                                  L"http://www.xfa.org/schema/xfa-data/1.0/",
                                  wsDataNodeAttr)) {
            if (wsDataNodeAttr == L"dataGroup")
              eNodeType = XFA_Element::DataGroup;
            else if (wsDataNodeAttr == L"dataValue")
              eNodeType = XFA_Element::DataValue;
          }
        }
        WideString wsContentType;
        if (eNodeType == XFA_Element::DataModel) {
          if (FindAttributeWithNS(pXMLElement, L"contentType",
                                  L"http://www.xfa.org/schema/xfa-data/1.0/",
                                  wsContentType)) {
            if (!wsContentType.IsEmpty())
              eNodeType = XFA_Element::DataValue;
          }
        }
        if (eNodeType == XFA_Element::DataModel) {
          for (CFX_XMLNode* pXMLDataChild =
                   pXMLElement->GetNodeItem(CFX_XMLNode::FirstChild);
               pXMLDataChild; pXMLDataChild = pXMLDataChild->GetNodeItem(
                                  CFX_XMLNode::NextSibling)) {
            if (pXMLDataChild->GetType() == FX_XMLNODE_Element) {
              if (!XFA_RecognizeRichText(
                      static_cast<CFX_XMLElement*>(pXMLDataChild))) {
                eNodeType = XFA_Element::DataGroup;
                break;
              }
            }
          }
        }
        if (eNodeType == XFA_Element::DataModel)
          eNodeType = XFA_Element::DataValue;

        CXFA_Node* pXFAChild =
            m_pFactory->CreateNode(XFA_PacketType::Datasets, eNodeType);
        if (!pXFAChild)
          return;

        pXFAChild->JSObject()->SetCData(
            XFA_Attribute::Name, pXMLElement->GetLocalTagName(), false, false);
        bool bNeedValue = true;

        for (auto it : pXMLElement->GetAttributes()) {
          WideString wsName;
          WideString wsNS;
          if (!ResolveAttribute(pXMLElement, it.first, wsName, wsNS)) {
            continue;
          }
          if (wsName == L"nil" && it.second == L"true") {
            bNeedValue = false;
            continue;
          }
          if (wsNS == L"http://www.xfa.com/schema/xfa-package/" ||
              wsNS == L"http://www.xfa.org/schema/xfa-package/" ||
              wsNS == L"http://www.w3.org/2001/XMLSchema-instance" ||
              wsNS == L"http://www.xfa.org/schema/xfa-data/1.0/") {
            continue;
          }
          CXFA_Node* pXFAMetaData = m_pFactory->CreateNode(
              XFA_PacketType::Datasets, XFA_Element::DataValue);
          if (!pXFAMetaData)
            return;

          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::Name, wsName, false,
                                             false);
          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::QualifiedName,
                                             it.first, false, false);
          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::Value, it.second,
                                             false, false);
          pXFAMetaData->JSObject()->SetEnum(XFA_Attribute::Contains,
                                            XFA_AttributeEnum::MetaData, false);
          pXFAChild->InsertChild(pXFAMetaData, nullptr);
          pXFAMetaData->SetXMLMappingNode(pXMLElement);
          pXFAMetaData->SetFlag(XFA_NodeFlag_Initialized, false);
        }

        if (!bNeedValue) {
          WideString wsNilName(L"xsi:nil");
          pXMLElement->RemoveAttribute(wsNilName.c_str());
        }
        pXFANode->InsertChild(pXFAChild, nullptr);
        if (eNodeType == XFA_Element::DataGroup)
          ParseDataGroup(pXFAChild, pXMLElement, ePacketID);
        else if (bNeedValue)
          ParseDataValue(pXFAChild, pXMLChild, XFA_PacketType::Datasets);

        pXFAChild->SetXMLMappingNode(pXMLElement);
        pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
        continue;
      }
      case FX_XMLNODE_CharData:
      case FX_XMLNODE_Text: {
        CFX_XMLText* pXMLText = static_cast<CFX_XMLText*>(pXMLChild);
        WideString wsText = pXMLText->GetText();
        if (IsStringAllWhitespace(wsText))
          continue;

        CXFA_Node* pXFAChild = m_pFactory->CreateNode(XFA_PacketType::Datasets,
                                                      XFA_Element::DataValue);
        if (!pXFAChild)
          return;

        pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsText, false,
                                        false);
        pXFANode->InsertChild(pXFAChild, nullptr);
        pXFAChild->SetXMLMappingNode(pXMLText);
        pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
        continue;
      }
      default:
        continue;
    }
  }
}

void CXFA_SimpleParser::ParseDataValue(CXFA_Node* pXFANode,
                                       CFX_XMLNode* pXMLNode,
                                       XFA_PacketType ePacketID) {
  CFX_WideTextBuf wsValueTextBuf;
  CFX_WideTextBuf wsCurValueTextBuf;
  bool bMarkAsCompound = false;
  CFX_XMLNode* pXMLCurValueNode = nullptr;
  for (CFX_XMLNode* pXMLChild = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
       pXMLChild;
       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
    FX_XMLNODETYPE eNodeType = pXMLChild->GetType();
    if (eNodeType == FX_XMLNODE_Instruction)
      continue;

    if (eNodeType == FX_XMLNODE_Text || eNodeType == FX_XMLNODE_CharData) {
      WideString wsText = static_cast<CFX_XMLText*>(pXMLChild)->GetText();
      if (!pXMLCurValueNode)
        pXMLCurValueNode = pXMLChild;

      wsCurValueTextBuf << wsText;
    } else if (XFA_RecognizeRichText(static_cast<CFX_XMLElement*>(pXMLChild))) {
      WideString wsText =
          GetPlainTextFromRichText(static_cast<CFX_XMLElement*>(pXMLChild));
      if (!pXMLCurValueNode)
        pXMLCurValueNode = pXMLChild;

      wsCurValueTextBuf << wsText;
    } else {
      bMarkAsCompound = true;
      if (pXMLCurValueNode) {
        WideString wsCurValue = wsCurValueTextBuf.MakeString();
        if (!wsCurValue.IsEmpty()) {
          CXFA_Node* pXFAChild =
              m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
          if (!pXFAChild)
            return;

          pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, L"", false,
                                          false);
          pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsCurValue,
                                          false, false);
          pXFANode->InsertChild(pXFAChild, nullptr);
          pXFAChild->SetXMLMappingNode(pXMLCurValueNode);
          pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
          wsValueTextBuf << wsCurValue;
          wsCurValueTextBuf.Clear();
        }
        pXMLCurValueNode = nullptr;
      }
      CXFA_Node* pXFAChild =
          m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
      if (!pXFAChild)
        return;

      WideString wsNodeStr =
          static_cast<CFX_XMLElement*>(pXMLChild)->GetLocalTagName();
      pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, wsNodeStr, false,
                                      false);
      ParseDataValue(pXFAChild, pXMLChild, ePacketID);
      pXFANode->InsertChild(pXFAChild, nullptr);
      pXFAChild->SetXMLMappingNode(pXMLChild);
      pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
      WideString wsCurValue =
          pXFAChild->JSObject()->GetCData(XFA_Attribute::Value);
      wsValueTextBuf << wsCurValue;
    }
  }
  if (pXMLCurValueNode) {
    WideString wsCurValue = wsCurValueTextBuf.MakeString();
    if (!wsCurValue.IsEmpty()) {
      if (bMarkAsCompound) {
        CXFA_Node* pXFAChild =
            m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
        if (!pXFAChild)
          return;

        pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, L"", false, false);
        pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsCurValue, false,
                                        false);
        pXFANode->InsertChild(pXFAChild, nullptr);
        pXFAChild->SetXMLMappingNode(pXMLCurValueNode);
        pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
      }
      wsValueTextBuf << wsCurValue;
      wsCurValueTextBuf.Clear();
    }
    pXMLCurValueNode = nullptr;
  }
  WideString wsNodeValue = wsValueTextBuf.MakeString();
  pXFANode->JSObject()->SetCData(XFA_Attribute::Value, wsNodeValue, false,
                                 false);
}

void CXFA_SimpleParser::ParseInstruction(CXFA_Node* pXFANode,
                                         CFX_XMLInstruction* pXMLInstruction,
                                         XFA_PacketType ePacketID) {
  if (!m_bDocumentParser)
    return;

  WideString wsTargetName = pXMLInstruction->GetName();
  const std::vector<WideString>& target_data = pXMLInstruction->GetTargetData();
  if (wsTargetName == L"originalXFAVersion") {
    if (target_data.size() > 1 &&
        (pXFANode->GetDocument()->RecognizeXFAVersionNumber(target_data[0]) !=
         XFA_VERSION_UNKNOWN) &&
        target_data[1] == L"v2.7-scripting:1") {
      pXFANode->GetDocument()->SetFlag(XFA_DOCFLAG_Scripting, true);
    }
  } else if (wsTargetName == L"acrobat") {
    if (target_data.size() > 1 && target_data[0] == L"JavaScript" &&
        target_data[1] == L"strictScoping") {
      pXFANode->GetDocument()->SetFlag(XFA_DOCFLAG_StrictScoping, true);
    }
  }
}

void CXFA_SimpleParser::CloseParser() {
  m_pXMLDoc.reset();
  m_pStream.Reset();
}