diff options
Diffstat (limited to 'xfa/fxfa/parser/cxfa_document.cpp')
-rw-r--r-- | xfa/fxfa/parser/cxfa_document.cpp | 427 |
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); + } +} |