summaryrefslogtreecommitdiff
path: root/xfa/fxfa/parser/cxfa_document.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xfa/fxfa/parser/cxfa_document.cpp')
-rw-r--r--xfa/fxfa/parser/cxfa_document.cpp427
1 files changed, 427 insertions, 0 deletions
diff --git a/xfa/fxfa/parser/cxfa_document.cpp b/xfa/fxfa/parser/cxfa_document.cpp
new file mode 100644
index 0000000000..346690b484
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_document.cpp
@@ -0,0 +1,427 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fxcrt/include/fx_ext.h"
+#include "xfa/fxfa/app/xfa_ffnotify.h"
+#include "xfa/fxfa/parser/cscript_datawindow.h"
+#include "xfa/fxfa/parser/cscript_eventpseudomodel.h"
+#include "xfa/fxfa/parser/cscript_hostpseudomodel.h"
+#include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
+#include "xfa/fxfa/parser/cscript_logpseudomodel.h"
+#include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
+#include "xfa/fxfa/parser/cxfa_document_parser.h"
+#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/parser/cxfa_scriptcontext.h"
+#include "xfa/fxfa/parser/xfa_localemgr.h"
+#include "xfa/fxfa/parser/xfa_object.h"
+#include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
+
+namespace {
+
+void MergeNodeRecurse(CXFA_Document* pDocument,
+ CXFA_Node* pDestNodeParent,
+ CXFA_Node* pProtoNode) {
+ CXFA_Node* pExistingNode = nullptr;
+ for (CXFA_Node* pFormChild =
+ pDestNodeParent->GetNodeItem(XFA_NODEITEM_FirstChild);
+ pFormChild;
+ pFormChild = pFormChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
+ if (pFormChild->GetElementType() == pProtoNode->GetElementType() &&
+ pFormChild->GetNameHash() == pProtoNode->GetNameHash() &&
+ pFormChild->IsUnusedNode()) {
+ pFormChild->ClearFlag(XFA_NodeFlag_UnusedNode);
+ pExistingNode = pFormChild;
+ break;
+ }
+ }
+
+ if (pExistingNode) {
+ pExistingNode->SetTemplateNode(pProtoNode);
+ for (CXFA_Node* pTemplateChild =
+ pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
+ pTemplateChild; pTemplateChild = pTemplateChild->GetNodeItem(
+ XFA_NODEITEM_NextSibling)) {
+ MergeNodeRecurse(pDocument, pExistingNode, pTemplateChild);
+ }
+ return;
+ }
+ CXFA_Node* pNewNode = pProtoNode->Clone(TRUE);
+ pNewNode->SetTemplateNode(pProtoNode);
+ pDestNodeParent->InsertChild(pNewNode, nullptr);
+}
+
+void MergeNode(CXFA_Document* pDocument,
+ CXFA_Node* pDestNode,
+ CXFA_Node* pProtoNode) {
+ {
+ CXFA_NodeIterator sIterator(pDestNode);
+ for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
+ pNode = sIterator.MoveToNext()) {
+ pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
+ }
+ }
+ pDestNode->SetTemplateNode(pProtoNode);
+ for (CXFA_Node* pTemplateChild =
+ pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
+ pTemplateChild;
+ pTemplateChild = pTemplateChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
+ MergeNodeRecurse(pDocument, pDestNode, pTemplateChild);
+ }
+ {
+ CXFA_NodeIterator sIterator(pDestNode);
+ for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
+ pNode = sIterator.MoveToNext()) {
+ pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+ }
+ }
+}
+
+} // namespace
+
+CXFA_Document::CXFA_Document(CXFA_DocumentParser* pParser)
+ : m_pParser(pParser),
+ m_pScriptContext(nullptr),
+ m_pLayoutProcessor(nullptr),
+ m_pRootNode(nullptr),
+ m_pLocalMgr(nullptr),
+ m_pScriptDataWindow(nullptr),
+ m_pScriptEvent(nullptr),
+ m_pScriptHost(nullptr),
+ m_pScriptLog(nullptr),
+ m_pScriptLayout(nullptr),
+ m_pScriptSignature(nullptr),
+ m_eCurVersionMode(XFA_VERSION_DEFAULT),
+ m_dwDocFlags(0) {
+ ASSERT(m_pParser);
+}
+
+CXFA_Document::~CXFA_Document() {
+ delete m_pRootNode;
+ PurgeNodes();
+}
+
+void CXFA_Document::ClearLayoutData() {
+ delete m_pLayoutProcessor;
+ m_pLayoutProcessor = nullptr;
+ delete m_pScriptContext;
+ m_pScriptContext = nullptr;
+ delete m_pLocalMgr;
+ m_pLocalMgr = nullptr;
+ delete m_pScriptDataWindow;
+ m_pScriptDataWindow = nullptr;
+ delete m_pScriptEvent;
+ m_pScriptEvent = nullptr;
+ delete m_pScriptHost;
+ m_pScriptHost = nullptr;
+ delete m_pScriptLog;
+ m_pScriptLog = nullptr;
+ delete m_pScriptLayout;
+ m_pScriptLayout = nullptr;
+ delete m_pScriptSignature;
+ m_pScriptSignature = nullptr;
+}
+
+void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) {
+ if (m_pRootNode)
+ AddPurgeNode(m_pRootNode);
+
+ m_pRootNode = pNewRoot;
+ RemovePurgeNode(pNewRoot);
+}
+
+CFDE_XMLDoc* CXFA_Document::GetXMLDoc() const {
+ return m_pParser->GetXMLDoc();
+}
+
+CXFA_FFNotify* CXFA_Document::GetNotify() const {
+ return m_pParser->GetNotify();
+}
+
+CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) {
+ switch (dwNodeNameHash) {
+ case XFA_HASHCODE_Data: {
+ CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
+ if (!pDatasetsNode)
+ return nullptr;
+
+ for (CXFA_Node* pDatasetsChild =
+ pDatasetsNode->GetFirstChildByClass(XFA_Element::DataGroup);
+ pDatasetsChild;
+ pDatasetsChild = pDatasetsChild->GetNextSameClassSibling(
+ XFA_Element::DataGroup)) {
+ if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data)
+ continue;
+
+ CFX_WideString wsNamespaceURI;
+ if (!pDatasetsChild->TryNamespace(wsNamespaceURI))
+ continue;
+
+ CFX_WideString wsDatasetsURI;
+ if (!pDatasetsNode->TryNamespace(wsDatasetsURI))
+ continue;
+ if (wsNamespaceURI == wsDatasetsURI)
+ return pDatasetsChild;
+ }
+ return nullptr;
+ }
+ case XFA_HASHCODE_Record: {
+ CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data));
+ return pData ? pData->GetFirstChildByClass(XFA_Element::DataGroup)
+ : nullptr;
+ }
+ case XFA_HASHCODE_DataWindow: {
+ if (!m_pScriptDataWindow)
+ m_pScriptDataWindow = new CScript_DataWindow(this);
+ return m_pScriptDataWindow;
+ }
+ case XFA_HASHCODE_Event: {
+ if (!m_pScriptEvent)
+ m_pScriptEvent = new CScript_EventPseudoModel(this);
+ return m_pScriptEvent;
+ }
+ case XFA_HASHCODE_Host: {
+ if (!m_pScriptHost)
+ m_pScriptHost = new CScript_HostPseudoModel(this);
+ return m_pScriptHost;
+ }
+ case XFA_HASHCODE_Log: {
+ if (!m_pScriptLog)
+ m_pScriptLog = new CScript_LogPseudoModel(this);
+ return m_pScriptLog;
+ }
+ case XFA_HASHCODE_Signature: {
+ if (!m_pScriptSignature)
+ m_pScriptSignature = new CScript_SignaturePseudoModel(this);
+ return m_pScriptSignature;
+ }
+ case XFA_HASHCODE_Layout: {
+ if (!m_pScriptLayout)
+ m_pScriptLayout = new CScript_LayoutPseudoModel(this);
+ return m_pScriptLayout;
+ }
+ default:
+ return m_pRootNode->GetFirstChildByName(dwNodeNameHash);
+ }
+}
+
+CXFA_Node* CXFA_Document::CreateNode(uint32_t dwPacket, XFA_Element eElement) {
+ return CreateNode(XFA_GetPacketByID(dwPacket), eElement);
+}
+
+CXFA_Node* CXFA_Document::CreateNode(const XFA_PACKETINFO* pPacket,
+ XFA_Element eElement) {
+ if (!pPacket)
+ return nullptr;
+
+ const XFA_ELEMENTINFO* pElement = XFA_GetElementByID(eElement);
+ if (pElement && (pElement->dwPackets & pPacket->eName)) {
+ CXFA_Node* pNode =
+ new CXFA_Node(this, pPacket->eName, pElement->eObjectType,
+ pElement->eName, pElement->pName);
+ AddPurgeNode(pNode);
+ return pNode;
+ }
+
+ return nullptr;
+}
+
+void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) {
+ m_PurgeNodes.insert(pNode);
+}
+
+FX_BOOL CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) {
+ return !!m_PurgeNodes.erase(pNode);
+}
+
+void CXFA_Document::PurgeNodes() {
+ for (CXFA_Node* pNode : m_PurgeNodes)
+ delete pNode;
+
+ m_PurgeNodes.clear();
+}
+
+void CXFA_Document::SetFlag(uint32_t dwFlag, FX_BOOL bOn) {
+ if (bOn)
+ m_dwDocFlags |= dwFlag;
+ else
+ m_dwDocFlags &= ~dwFlag;
+}
+
+FX_BOOL CXFA_Document::IsInteractive() {
+ if (m_dwDocFlags & XFA_DOCFLAG_HasInteractive)
+ return !!(m_dwDocFlags & XFA_DOCFLAG_Interactive);
+
+ CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config));
+ if (!pConfig)
+ return FALSE;
+
+ CFX_WideString wsInteractive;
+ CXFA_Node* pPresent = pConfig->GetFirstChildByClass(XFA_Element::Present);
+ if (!pPresent)
+ return FALSE;
+
+ CXFA_Node* pPDF = pPresent->GetFirstChildByClass(XFA_Element::Pdf);
+ if (!pPDF)
+ return FALSE;
+
+ CXFA_Node* pInteractive = pPDF->GetChild(0, XFA_Element::Interactive);
+ if (pInteractive) {
+ m_dwDocFlags |= XFA_DOCFLAG_HasInteractive;
+ if (pInteractive->TryContent(wsInteractive) &&
+ wsInteractive == FX_WSTRC(L"1")) {
+ m_dwDocFlags |= XFA_DOCFLAG_Interactive;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() {
+ if (!m_pLocalMgr) {
+ CFX_WideString wsLanguage;
+ GetNotify()->GetAppProvider()->GetLanguage(wsLanguage);
+ m_pLocalMgr = new CXFA_LocaleMgr(
+ ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)), wsLanguage);
+ }
+ return m_pLocalMgr;
+}
+
+CXFA_ScriptContext* CXFA_Document::InitScriptContext(v8::Isolate* pIsolate) {
+ if (!m_pScriptContext)
+ m_pScriptContext = new CXFA_ScriptContext(this);
+ m_pScriptContext->Initialize(pIsolate);
+ return m_pScriptContext;
+}
+
+CXFA_ScriptContext* CXFA_Document::GetScriptContext() {
+ if (!m_pScriptContext)
+ m_pScriptContext = new CXFA_ScriptContext(this);
+ return m_pScriptContext;
+}
+
+XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
+ CFX_WideString& wsTemplateNS) {
+ CFX_WideStringC wsTemplateURIPrefix =
+ XFA_GetPacketByIndex(XFA_PACKET_Template)->pURI;
+ FX_STRSIZE nPrefixLength = wsTemplateURIPrefix.GetLength();
+ if (CFX_WideStringC(wsTemplateNS.c_str(), wsTemplateNS.GetLength()) !=
+ wsTemplateURIPrefix) {
+ return XFA_VERSION_UNKNOWN;
+ }
+ FX_STRSIZE nDotPos = wsTemplateNS.Find('.', nPrefixLength);
+ if (nDotPos == (FX_STRSIZE)-1)
+ return XFA_VERSION_UNKNOWN;
+
+ int8_t iMajor = FXSYS_wtoi(
+ wsTemplateNS.Mid(nPrefixLength, nDotPos - nPrefixLength).c_str());
+ int8_t iMinor = FXSYS_wtoi(
+ wsTemplateNS.Mid(nDotPos + 1, wsTemplateNS.GetLength() - nDotPos - 2)
+ .c_str());
+ XFA_VERSION eVersion = (XFA_VERSION)((int32_t)iMajor * 100 + iMinor);
+ if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX)
+ return XFA_VERSION_UNKNOWN;
+
+ m_eCurVersionMode = eVersion;
+ return eVersion;
+}
+
+CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
+ const CFX_WideStringC& wsID) {
+ if (!pRoot || wsID.IsEmpty())
+ return nullptr;
+
+ CXFA_NodeIterator sIterator(pRoot);
+ for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
+ pNode = sIterator.MoveToNext()) {
+ CFX_WideStringC wsIDVal;
+ if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
+ if (wsIDVal == wsID)
+ return pNode;
+ }
+ }
+ return nullptr;
+}
+
+void CXFA_Document::DoProtoMerge() {
+ CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(XFA_HASHCODE_Template));
+ if (!pTemplateRoot)
+ return;
+
+ CFX_MapPtrTemplate<uint32_t, CXFA_Node*> mIDMap;
+ CXFA_NodeSet sUseNodes;
+ CXFA_NodeIterator sIterator(pTemplateRoot);
+ for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
+ pNode = sIterator.MoveToNext()) {
+ CFX_WideStringC wsIDVal;
+ if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
+ mIDMap[FX_HashCode_GetW(wsIDVal, false)] = pNode;
+ }
+ CFX_WideStringC wsUseVal;
+ if (pNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) && !wsUseVal.IsEmpty()) {
+ sUseNodes.insert(pNode);
+ } else if (pNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
+ !wsUseVal.IsEmpty()) {
+ sUseNodes.insert(pNode);
+ }
+ }
+
+ for (CXFA_Node* pUseHrefNode : sUseNodes) {
+ CFX_WideString wsUseVal;
+ CFX_WideStringC wsURI, wsID, wsSOM;
+ if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
+ !wsUseVal.IsEmpty()) {
+ FX_STRSIZE uSharpPos = wsUseVal.Find('#');
+ if (uSharpPos < 0) {
+ wsURI = wsUseVal.AsStringC();
+ } else {
+ wsURI = CFX_WideStringC(wsUseVal.c_str(), uSharpPos);
+ FX_STRSIZE uLen = wsUseVal.GetLength();
+ if (uLen >= uSharpPos + 5 &&
+ CFX_WideStringC(wsUseVal.c_str() + uSharpPos, 5) ==
+ FX_WSTRC(L"#som(") &&
+ wsUseVal[uLen - 1] == ')') {
+ wsSOM = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 5,
+ uLen - 1 - uSharpPos - 5);
+ } else {
+ wsID = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 1,
+ uLen - uSharpPos - 1);
+ }
+ }
+ } else if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) &&
+ !wsUseVal.IsEmpty()) {
+ if (wsUseVal[0] == '#')
+ wsID = CFX_WideStringC(wsUseVal.c_str() + 1, wsUseVal.GetLength() - 1);
+ else
+ wsSOM = CFX_WideStringC(wsUseVal.c_str(), wsUseVal.GetLength());
+ }
+
+ if (!wsURI.IsEmpty() && wsURI != FX_WSTRC(L"."))
+ continue;
+
+ CXFA_Node* pProtoNode = nullptr;
+ if (!wsSOM.IsEmpty()) {
+ uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
+ XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
+ XFA_RESOLVENODE_Siblings;
+ XFA_RESOLVENODE_RS resoveNodeRS;
+ int32_t iRet = m_pScriptContext->ResolveObjects(pUseHrefNode, wsSOM,
+ resoveNodeRS, dwFlag);
+ if (iRet > 0 && resoveNodeRS.nodes[0]->IsNode()) {
+ pProtoNode = resoveNodeRS.nodes[0]->AsNode();
+ }
+ } else if (!wsID.IsEmpty()) {
+ if (!mIDMap.Lookup(FX_HashCode_GetW(wsID, false), pProtoNode)) {
+ continue;
+ }
+ }
+ if (!pProtoNode)
+ continue;
+
+ MergeNode(this, pUseHrefNode, pProtoNode);
+ }
+}