blob: 374fb98c529addc0acc96f0830cd9f6284505f0e [file] [log] [blame]
Dan Sinclair1770c022016-03-14 14:14:16 -04001// 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
dsinclaira52ab742016-09-29 13:59:29 -07007#include "core/fxcrt/fx_ext.h"
dsinclairdf4bc592016-03-31 20:34:43 -07008#include "xfa/fxfa/app/xfa_ffnotify.h"
dsinclairc1515ef2016-07-20 06:16:06 -07009#include "xfa/fxfa/parser/cscript_datawindow.h"
10#include "xfa/fxfa/parser/cscript_eventpseudomodel.h"
11#include "xfa/fxfa/parser/cscript_hostpseudomodel.h"
12#include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
13#include "xfa/fxfa/parser/cscript_logpseudomodel.h"
14#include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
dsinclair16280242016-07-21 12:03:47 -070015#include "xfa/fxfa/parser/cxfa_document.h"
dsinclair34f86b02016-07-11 08:42:33 -070016#include "xfa/fxfa/parser/cxfa_document_parser.h"
dsinclair0b851ff2016-07-21 12:03:01 -070017#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
dsinclair31f87402016-07-20 06:34:45 -070018#include "xfa/fxfa/parser/cxfa_scriptcontext.h"
Dan Sinclair1770c022016-03-14 14:14:16 -040019#include "xfa/fxfa/parser/xfa_localemgr.h"
20#include "xfa/fxfa/parser/xfa_object.h"
dsinclair31f87402016-07-20 06:34:45 -070021#include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
Dan Sinclair1770c022016-03-14 14:14:16 -040022#include "xfa/fxfa/parser/xfa_utils.h"
23
dsinclair16280242016-07-21 12:03:47 -070024namespace {
25
26void MergeNodeRecurse(CXFA_Document* pDocument,
27 CXFA_Node* pDestNodeParent,
28 CXFA_Node* pProtoNode) {
29 CXFA_Node* pExistingNode = nullptr;
30 for (CXFA_Node* pFormChild =
31 pDestNodeParent->GetNodeItem(XFA_NODEITEM_FirstChild);
32 pFormChild;
33 pFormChild = pFormChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
34 if (pFormChild->GetElementType() == pProtoNode->GetElementType() &&
35 pFormChild->GetNameHash() == pProtoNode->GetNameHash() &&
36 pFormChild->IsUnusedNode()) {
37 pFormChild->ClearFlag(XFA_NodeFlag_UnusedNode);
38 pExistingNode = pFormChild;
39 break;
40 }
41 }
42
43 if (pExistingNode) {
44 pExistingNode->SetTemplateNode(pProtoNode);
45 for (CXFA_Node* pTemplateChild =
46 pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
47 pTemplateChild; pTemplateChild = pTemplateChild->GetNodeItem(
48 XFA_NODEITEM_NextSibling)) {
49 MergeNodeRecurse(pDocument, pExistingNode, pTemplateChild);
50 }
51 return;
52 }
tsepezd19e9122016-11-02 15:43:18 -070053 CXFA_Node* pNewNode = pProtoNode->Clone(true);
dsinclair16280242016-07-21 12:03:47 -070054 pNewNode->SetTemplateNode(pProtoNode);
55 pDestNodeParent->InsertChild(pNewNode, nullptr);
56}
57
58void MergeNode(CXFA_Document* pDocument,
59 CXFA_Node* pDestNode,
60 CXFA_Node* pProtoNode) {
61 {
62 CXFA_NodeIterator sIterator(pDestNode);
63 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
64 pNode = sIterator.MoveToNext()) {
65 pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
66 }
67 }
68 pDestNode->SetTemplateNode(pProtoNode);
69 for (CXFA_Node* pTemplateChild =
70 pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
71 pTemplateChild;
72 pTemplateChild = pTemplateChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
73 MergeNodeRecurse(pDocument, pDestNode, pTemplateChild);
74 }
75 {
76 CXFA_NodeIterator sIterator(pDestNode);
77 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
78 pNode = sIterator.MoveToNext()) {
79 pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
80 }
81 }
82}
83
84} // namespace
85
dsinclairdf4bc592016-03-31 20:34:43 -070086CXFA_Document::CXFA_Document(CXFA_DocumentParser* pParser)
Dan Sinclair1770c022016-03-14 14:14:16 -040087 : m_pParser(pParser),
88 m_pScriptContext(nullptr),
89 m_pLayoutProcessor(nullptr),
90 m_pRootNode(nullptr),
91 m_pLocalMgr(nullptr),
92 m_pScriptDataWindow(nullptr),
93 m_pScriptEvent(nullptr),
94 m_pScriptHost(nullptr),
95 m_pScriptLog(nullptr),
96 m_pScriptLayout(nullptr),
97 m_pScriptSignature(nullptr),
98 m_eCurVersionMode(XFA_VERSION_DEFAULT),
99 m_dwDocFlags(0) {
100 ASSERT(m_pParser);
101}
dsinclair16280242016-07-21 12:03:47 -0700102
Dan Sinclair1770c022016-03-14 14:14:16 -0400103CXFA_Document::~CXFA_Document() {
104 delete m_pRootNode;
105 PurgeNodes();
106}
thestig495bda12016-04-28 17:29:19 -0700107
Dan Sinclair1770c022016-03-14 14:14:16 -0400108void CXFA_Document::ClearLayoutData() {
thestig495bda12016-04-28 17:29:19 -0700109 delete m_pLayoutProcessor;
110 m_pLayoutProcessor = nullptr;
tsepezf1a52ca2016-05-18 13:22:57 -0700111 delete m_pScriptContext;
112 m_pScriptContext = nullptr;
thestig495bda12016-04-28 17:29:19 -0700113 delete m_pLocalMgr;
114 m_pLocalMgr = nullptr;
115 delete m_pScriptDataWindow;
116 m_pScriptDataWindow = nullptr;
117 delete m_pScriptEvent;
118 m_pScriptEvent = nullptr;
119 delete m_pScriptHost;
120 m_pScriptHost = nullptr;
121 delete m_pScriptLog;
122 m_pScriptLog = nullptr;
123 delete m_pScriptLayout;
124 m_pScriptLayout = nullptr;
125 delete m_pScriptSignature;
126 m_pScriptSignature = nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400127}
thestig495bda12016-04-28 17:29:19 -0700128
Dan Sinclair1770c022016-03-14 14:14:16 -0400129void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) {
dsinclair16280242016-07-21 12:03:47 -0700130 if (m_pRootNode)
Dan Sinclair1770c022016-03-14 14:14:16 -0400131 AddPurgeNode(m_pRootNode);
dsinclair16280242016-07-21 12:03:47 -0700132
Dan Sinclair1770c022016-03-14 14:14:16 -0400133 m_pRootNode = pNewRoot;
134 RemovePurgeNode(pNewRoot);
135}
dsinclaircbfef572016-05-18 13:16:12 -0700136
dsinclaira1b07722016-07-11 08:20:58 -0700137CFDE_XMLDoc* CXFA_Document::GetXMLDoc() const {
138 return m_pParser->GetXMLDoc();
139}
140
dsinclairdf4bc592016-03-31 20:34:43 -0700141CXFA_FFNotify* CXFA_Document::GetNotify() const {
Dan Sinclair1770c022016-03-14 14:14:16 -0400142 return m_pParser->GetNotify();
143}
dsinclaircbfef572016-05-18 13:16:12 -0700144
145CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400146 switch (dwNodeNameHash) {
147 case XFA_HASHCODE_Data: {
148 CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
dsinclair16280242016-07-21 12:03:47 -0700149 if (!pDatasetsNode)
dsinclair85d1f2c2016-06-23 12:40:16 -0700150 return nullptr;
dsinclair16280242016-07-21 12:03:47 -0700151
Dan Sinclair1770c022016-03-14 14:14:16 -0400152 for (CXFA_Node* pDatasetsChild =
dsinclair56a8b192016-06-21 14:15:25 -0700153 pDatasetsNode->GetFirstChildByClass(XFA_Element::DataGroup);
Dan Sinclair1770c022016-03-14 14:14:16 -0400154 pDatasetsChild;
dsinclair56a8b192016-06-21 14:15:25 -0700155 pDatasetsChild = pDatasetsChild->GetNextSameClassSibling(
156 XFA_Element::DataGroup)) {
dsinclair16280242016-07-21 12:03:47 -0700157 if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data)
Dan Sinclair1770c022016-03-14 14:14:16 -0400158 continue;
dsinclair16280242016-07-21 12:03:47 -0700159
Dan Sinclair1770c022016-03-14 14:14:16 -0400160 CFX_WideString wsNamespaceURI;
dsinclair16280242016-07-21 12:03:47 -0700161 if (!pDatasetsChild->TryNamespace(wsNamespaceURI))
Dan Sinclair1770c022016-03-14 14:14:16 -0400162 continue;
dsinclair16280242016-07-21 12:03:47 -0700163
Dan Sinclair1770c022016-03-14 14:14:16 -0400164 CFX_WideString wsDatasetsURI;
dsinclair16280242016-07-21 12:03:47 -0700165 if (!pDatasetsNode->TryNamespace(wsDatasetsURI))
Dan Sinclair1770c022016-03-14 14:14:16 -0400166 continue;
dsinclair16280242016-07-21 12:03:47 -0700167 if (wsNamespaceURI == wsDatasetsURI)
Dan Sinclair1770c022016-03-14 14:14:16 -0400168 return pDatasetsChild;
Dan Sinclair1770c022016-03-14 14:14:16 -0400169 }
dsinclair85d1f2c2016-06-23 12:40:16 -0700170 return nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400171 }
Dan Sinclair1770c022016-03-14 14:14:16 -0400172 case XFA_HASHCODE_Record: {
173 CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data));
dsinclair85d1f2c2016-06-23 12:40:16 -0700174 return pData ? pData->GetFirstChildByClass(XFA_Element::DataGroup)
175 : nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400176 }
177 case XFA_HASHCODE_DataWindow: {
dsinclair85d1f2c2016-06-23 12:40:16 -0700178 if (!m_pScriptDataWindow)
Dan Sinclair1770c022016-03-14 14:14:16 -0400179 m_pScriptDataWindow = new CScript_DataWindow(this);
Dan Sinclair1770c022016-03-14 14:14:16 -0400180 return m_pScriptDataWindow;
181 }
182 case XFA_HASHCODE_Event: {
dsinclair85d1f2c2016-06-23 12:40:16 -0700183 if (!m_pScriptEvent)
Dan Sinclair1770c022016-03-14 14:14:16 -0400184 m_pScriptEvent = new CScript_EventPseudoModel(this);
Dan Sinclair1770c022016-03-14 14:14:16 -0400185 return m_pScriptEvent;
186 }
187 case XFA_HASHCODE_Host: {
dsinclair85d1f2c2016-06-23 12:40:16 -0700188 if (!m_pScriptHost)
Dan Sinclair1770c022016-03-14 14:14:16 -0400189 m_pScriptHost = new CScript_HostPseudoModel(this);
Dan Sinclair1770c022016-03-14 14:14:16 -0400190 return m_pScriptHost;
191 }
192 case XFA_HASHCODE_Log: {
dsinclair85d1f2c2016-06-23 12:40:16 -0700193 if (!m_pScriptLog)
Dan Sinclair1770c022016-03-14 14:14:16 -0400194 m_pScriptLog = new CScript_LogPseudoModel(this);
Dan Sinclair1770c022016-03-14 14:14:16 -0400195 return m_pScriptLog;
196 }
197 case XFA_HASHCODE_Signature: {
dsinclair85d1f2c2016-06-23 12:40:16 -0700198 if (!m_pScriptSignature)
Dan Sinclair1770c022016-03-14 14:14:16 -0400199 m_pScriptSignature = new CScript_SignaturePseudoModel(this);
Dan Sinclair1770c022016-03-14 14:14:16 -0400200 return m_pScriptSignature;
201 }
202 case XFA_HASHCODE_Layout: {
dsinclair85d1f2c2016-06-23 12:40:16 -0700203 if (!m_pScriptLayout)
Dan Sinclair1770c022016-03-14 14:14:16 -0400204 m_pScriptLayout = new CScript_LayoutPseudoModel(this);
Dan Sinclair1770c022016-03-14 14:14:16 -0400205 return m_pScriptLayout;
206 }
207 default:
208 return m_pRootNode->GetFirstChildByName(dwNodeNameHash);
209 }
210}
dsinclair16280242016-07-21 12:03:47 -0700211
dsinclair56a8b192016-06-21 14:15:25 -0700212CXFA_Node* CXFA_Document::CreateNode(uint32_t dwPacket, XFA_Element eElement) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400213 return CreateNode(XFA_GetPacketByID(dwPacket), eElement);
214}
tsepezaadedf92016-05-12 10:08:06 -0700215
Dan Sinclair1770c022016-03-14 14:14:16 -0400216CXFA_Node* CXFA_Document::CreateNode(const XFA_PACKETINFO* pPacket,
dsinclair56a8b192016-06-21 14:15:25 -0700217 XFA_Element eElement) {
tsepezaadedf92016-05-12 10:08:06 -0700218 if (!pPacket)
219 return nullptr;
220
Dan Sinclair1770c022016-03-14 14:14:16 -0400221 const XFA_ELEMENTINFO* pElement = XFA_GetElementByID(eElement);
222 if (pElement && (pElement->dwPackets & pPacket->eName)) {
dsinclairc1df5d42016-07-18 06:36:51 -0700223 CXFA_Node* pNode =
224 new CXFA_Node(this, pPacket->eName, pElement->eObjectType,
225 pElement->eName, pElement->pName);
tsepezaadedf92016-05-12 10:08:06 -0700226 AddPurgeNode(pNode);
Dan Sinclair1770c022016-03-14 14:14:16 -0400227 return pNode;
228 }
tsepezaadedf92016-05-12 10:08:06 -0700229
230 return nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400231}
tsepezaadedf92016-05-12 10:08:06 -0700232
Dan Sinclair1770c022016-03-14 14:14:16 -0400233void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) {
tsepezaadedf92016-05-12 10:08:06 -0700234 m_PurgeNodes.insert(pNode);
Dan Sinclair1770c022016-03-14 14:14:16 -0400235}
tsepezaadedf92016-05-12 10:08:06 -0700236
tsepezd19e9122016-11-02 15:43:18 -0700237bool CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) {
tsepezaadedf92016-05-12 10:08:06 -0700238 return !!m_PurgeNodes.erase(pNode);
Dan Sinclair1770c022016-03-14 14:14:16 -0400239}
tsepezaadedf92016-05-12 10:08:06 -0700240
Dan Sinclair1770c022016-03-14 14:14:16 -0400241void CXFA_Document::PurgeNodes() {
tsepezaadedf92016-05-12 10:08:06 -0700242 for (CXFA_Node* pNode : m_PurgeNodes)
Dan Sinclair1770c022016-03-14 14:14:16 -0400243 delete pNode;
tsepezaadedf92016-05-12 10:08:06 -0700244
245 m_PurgeNodes.clear();
Dan Sinclair1770c022016-03-14 14:14:16 -0400246}
tsepezaadedf92016-05-12 10:08:06 -0700247
tsepezd19e9122016-11-02 15:43:18 -0700248void CXFA_Document::SetFlag(uint32_t dwFlag, bool bOn) {
dsinclair16280242016-07-21 12:03:47 -0700249 if (bOn)
Dan Sinclair1770c022016-03-14 14:14:16 -0400250 m_dwDocFlags |= dwFlag;
dsinclair16280242016-07-21 12:03:47 -0700251 else
Dan Sinclair1770c022016-03-14 14:14:16 -0400252 m_dwDocFlags &= ~dwFlag;
Dan Sinclair1770c022016-03-14 14:14:16 -0400253}
dsinclair16280242016-07-21 12:03:47 -0700254
tsepezd19e9122016-11-02 15:43:18 -0700255bool CXFA_Document::IsInteractive() {
dsinclair16280242016-07-21 12:03:47 -0700256 if (m_dwDocFlags & XFA_DOCFLAG_HasInteractive)
tsepez7d89e722016-05-04 13:38:11 -0700257 return !!(m_dwDocFlags & XFA_DOCFLAG_Interactive);
dsinclair16280242016-07-21 12:03:47 -0700258
Dan Sinclair1770c022016-03-14 14:14:16 -0400259 CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config));
dsinclair16280242016-07-21 12:03:47 -0700260 if (!pConfig)
tsepezd19e9122016-11-02 15:43:18 -0700261 return false;
dsinclair16280242016-07-21 12:03:47 -0700262
Dan Sinclair1770c022016-03-14 14:14:16 -0400263 CFX_WideString wsInteractive;
dsinclair56a8b192016-06-21 14:15:25 -0700264 CXFA_Node* pPresent = pConfig->GetFirstChildByClass(XFA_Element::Present);
dsinclair16280242016-07-21 12:03:47 -0700265 if (!pPresent)
tsepezd19e9122016-11-02 15:43:18 -0700266 return false;
dsinclair16280242016-07-21 12:03:47 -0700267
dsinclair56a8b192016-06-21 14:15:25 -0700268 CXFA_Node* pPDF = pPresent->GetFirstChildByClass(XFA_Element::Pdf);
dsinclair16280242016-07-21 12:03:47 -0700269 if (!pPDF)
tsepezd19e9122016-11-02 15:43:18 -0700270 return false;
dsinclair16280242016-07-21 12:03:47 -0700271
dsinclairb94d7c92016-09-21 12:07:00 -0700272 CXFA_Node* pFormFiller = pPDF->GetChild(0, XFA_Element::Interactive);
273 if (pFormFiller) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400274 m_dwDocFlags |= XFA_DOCFLAG_HasInteractive;
dsinclairb94d7c92016-09-21 12:07:00 -0700275 if (pFormFiller->TryContent(wsInteractive) &&
Dan Sinclair1770c022016-03-14 14:14:16 -0400276 wsInteractive == FX_WSTRC(L"1")) {
277 m_dwDocFlags |= XFA_DOCFLAG_Interactive;
tsepezd19e9122016-11-02 15:43:18 -0700278 return true;
Dan Sinclair1770c022016-03-14 14:14:16 -0400279 }
280 }
tsepezd19e9122016-11-02 15:43:18 -0700281 return false;
Dan Sinclair1770c022016-03-14 14:14:16 -0400282}
dsinclair16280242016-07-21 12:03:47 -0700283
Dan Sinclair1770c022016-03-14 14:14:16 -0400284CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() {
285 if (!m_pLocalMgr) {
Dan Sinclairc8fd3312017-01-02 17:17:02 -0500286 m_pLocalMgr =
287 new CXFA_LocaleMgr(ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)),
288 GetNotify()->GetAppProvider()->GetLanguage());
Dan Sinclair1770c022016-03-14 14:14:16 -0400289 }
290 return m_pLocalMgr;
291}
dsinclair16280242016-07-21 12:03:47 -0700292
dsinclairec3da5b2016-05-25 16:42:05 -0700293CXFA_ScriptContext* CXFA_Document::InitScriptContext(v8::Isolate* pIsolate) {
dsinclairdf4bc592016-03-31 20:34:43 -0700294 if (!m_pScriptContext)
295 m_pScriptContext = new CXFA_ScriptContext(this);
dsinclairec3da5b2016-05-25 16:42:05 -0700296 m_pScriptContext->Initialize(pIsolate);
Dan Sinclair1770c022016-03-14 14:14:16 -0400297 return m_pScriptContext;
298}
dsinclair16280242016-07-21 12:03:47 -0700299
dsinclairdf4bc592016-03-31 20:34:43 -0700300CXFA_ScriptContext* CXFA_Document::GetScriptContext() {
301 if (!m_pScriptContext)
302 m_pScriptContext = new CXFA_ScriptContext(this);
Dan Sinclair1770c022016-03-14 14:14:16 -0400303 return m_pScriptContext;
304}
dsinclair16280242016-07-21 12:03:47 -0700305
Dan Sinclair1770c022016-03-14 14:14:16 -0400306XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
307 CFX_WideString& wsTemplateNS) {
308 CFX_WideStringC wsTemplateURIPrefix =
309 XFA_GetPacketByIndex(XFA_PACKET_Template)->pURI;
310 FX_STRSIZE nPrefixLength = wsTemplateURIPrefix.GetLength();
tsepezbd9748d2016-04-13 21:40:19 -0700311 if (CFX_WideStringC(wsTemplateNS.c_str(), wsTemplateNS.GetLength()) !=
Dan Sinclair1770c022016-03-14 14:14:16 -0400312 wsTemplateURIPrefix) {
313 return XFA_VERSION_UNKNOWN;
314 }
315 FX_STRSIZE nDotPos = wsTemplateNS.Find('.', nPrefixLength);
dsinclair16280242016-07-21 12:03:47 -0700316 if (nDotPos == (FX_STRSIZE)-1)
Dan Sinclair1770c022016-03-14 14:14:16 -0400317 return XFA_VERSION_UNKNOWN;
dsinclair16280242016-07-21 12:03:47 -0700318
tsepezbd9748d2016-04-13 21:40:19 -0700319 int8_t iMajor = FXSYS_wtoi(
320 wsTemplateNS.Mid(nPrefixLength, nDotPos - nPrefixLength).c_str());
Dan Sinclair1770c022016-03-14 14:14:16 -0400321 int8_t iMinor = FXSYS_wtoi(
tsepezbd9748d2016-04-13 21:40:19 -0700322 wsTemplateNS.Mid(nDotPos + 1, wsTemplateNS.GetLength() - nDotPos - 2)
323 .c_str());
Dan Sinclair1770c022016-03-14 14:14:16 -0400324 XFA_VERSION eVersion = (XFA_VERSION)((int32_t)iMajor * 100 + iMinor);
dsinclair16280242016-07-21 12:03:47 -0700325 if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX)
Dan Sinclair1770c022016-03-14 14:14:16 -0400326 return XFA_VERSION_UNKNOWN;
dsinclair16280242016-07-21 12:03:47 -0700327
Dan Sinclair1770c022016-03-14 14:14:16 -0400328 m_eCurVersionMode = eVersion;
329 return eVersion;
330}
dsinclair16280242016-07-21 12:03:47 -0700331
Dan Sinclair1770c022016-03-14 14:14:16 -0400332CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
333 const CFX_WideStringC& wsID) {
dsinclair16280242016-07-21 12:03:47 -0700334 if (!pRoot || wsID.IsEmpty())
dsinclair85d1f2c2016-06-23 12:40:16 -0700335 return nullptr;
dsinclair16280242016-07-21 12:03:47 -0700336
Dan Sinclair1770c022016-03-14 14:14:16 -0400337 CXFA_NodeIterator sIterator(pRoot);
338 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
339 pNode = sIterator.MoveToNext()) {
340 CFX_WideStringC wsIDVal;
341 if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
dsinclair16280242016-07-21 12:03:47 -0700342 if (wsIDVal == wsID)
Dan Sinclair1770c022016-03-14 14:14:16 -0400343 return pNode;
Dan Sinclair1770c022016-03-14 14:14:16 -0400344 }
345 }
dsinclair85d1f2c2016-06-23 12:40:16 -0700346 return nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400347}
dsinclair16280242016-07-21 12:03:47 -0700348
Dan Sinclair1770c022016-03-14 14:14:16 -0400349void CXFA_Document::DoProtoMerge() {
350 CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(XFA_HASHCODE_Template));
dsinclair16280242016-07-21 12:03:47 -0700351 if (!pTemplateRoot)
Dan Sinclair1770c022016-03-14 14:14:16 -0400352 return;
dsinclair16280242016-07-21 12:03:47 -0700353
tsepez6bb3b892017-01-05 12:18:41 -0800354 std::map<uint32_t, CXFA_Node*> mIDMap;
Dan Sinclair1770c022016-03-14 14:14:16 -0400355 CXFA_NodeSet sUseNodes;
356 CXFA_NodeIterator sIterator(pTemplateRoot);
357 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
358 pNode = sIterator.MoveToNext()) {
359 CFX_WideStringC wsIDVal;
360 if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
tsepezb6853cf2016-04-25 11:23:43 -0700361 mIDMap[FX_HashCode_GetW(wsIDVal, false)] = pNode;
Dan Sinclair1770c022016-03-14 14:14:16 -0400362 }
363 CFX_WideStringC wsUseVal;
364 if (pNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) && !wsUseVal.IsEmpty()) {
tsepezaadedf92016-05-12 10:08:06 -0700365 sUseNodes.insert(pNode);
Dan Sinclair1770c022016-03-14 14:14:16 -0400366 } else if (pNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
367 !wsUseVal.IsEmpty()) {
tsepezaadedf92016-05-12 10:08:06 -0700368 sUseNodes.insert(pNode);
Dan Sinclair1770c022016-03-14 14:14:16 -0400369 }
370 }
dsinclair16280242016-07-21 12:03:47 -0700371
tsepezaadedf92016-05-12 10:08:06 -0700372 for (CXFA_Node* pUseHrefNode : sUseNodes) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400373 CFX_WideString wsUseVal;
374 CFX_WideStringC wsURI, wsID, wsSOM;
375 if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
376 !wsUseVal.IsEmpty()) {
377 FX_STRSIZE uSharpPos = wsUseVal.Find('#');
378 if (uSharpPos < 0) {
tsepez4d31d0c2016-04-19 14:11:59 -0700379 wsURI = wsUseVal.AsStringC();
Dan Sinclair1770c022016-03-14 14:14:16 -0400380 } else {
tsepezbd9748d2016-04-13 21:40:19 -0700381 wsURI = CFX_WideStringC(wsUseVal.c_str(), uSharpPos);
Dan Sinclair1770c022016-03-14 14:14:16 -0400382 FX_STRSIZE uLen = wsUseVal.GetLength();
383 if (uLen >= uSharpPos + 5 &&
tsepezbd9748d2016-04-13 21:40:19 -0700384 CFX_WideStringC(wsUseVal.c_str() + uSharpPos, 5) ==
Dan Sinclair1770c022016-03-14 14:14:16 -0400385 FX_WSTRC(L"#som(") &&
386 wsUseVal[uLen - 1] == ')') {
tsepezbd9748d2016-04-13 21:40:19 -0700387 wsSOM = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 5,
Dan Sinclair1770c022016-03-14 14:14:16 -0400388 uLen - 1 - uSharpPos - 5);
389 } else {
tsepezbd9748d2016-04-13 21:40:19 -0700390 wsID = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 1,
Dan Sinclair1770c022016-03-14 14:14:16 -0400391 uLen - uSharpPos - 1);
392 }
393 }
394 } else if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) &&
395 !wsUseVal.IsEmpty()) {
dsinclair16280242016-07-21 12:03:47 -0700396 if (wsUseVal[0] == '#')
tsepezbd9748d2016-04-13 21:40:19 -0700397 wsID = CFX_WideStringC(wsUseVal.c_str() + 1, wsUseVal.GetLength() - 1);
dsinclair16280242016-07-21 12:03:47 -0700398 else
tsepezbd9748d2016-04-13 21:40:19 -0700399 wsSOM = CFX_WideStringC(wsUseVal.c_str(), wsUseVal.GetLength());
Dan Sinclair1770c022016-03-14 14:14:16 -0400400 }
dsinclair16280242016-07-21 12:03:47 -0700401
402 if (!wsURI.IsEmpty() && wsURI != FX_WSTRC(L"."))
Dan Sinclair1770c022016-03-14 14:14:16 -0400403 continue;
dsinclair16280242016-07-21 12:03:47 -0700404
dsinclair85d1f2c2016-06-23 12:40:16 -0700405 CXFA_Node* pProtoNode = nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400406 if (!wsSOM.IsEmpty()) {
tsepez736f28a2016-03-25 14:19:51 -0700407 uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
Dan Sinclair1770c022016-03-14 14:14:16 -0400408 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
409 XFA_RESOLVENODE_Siblings;
410 XFA_RESOLVENODE_RS resoveNodeRS;
411 int32_t iRet = m_pScriptContext->ResolveObjects(pUseHrefNode, wsSOM,
412 resoveNodeRS, dwFlag);
tsepez6bb3b892017-01-05 12:18:41 -0800413 if (iRet > 0 && resoveNodeRS.nodes[0]->IsNode())
Dan Sinclair1770c022016-03-14 14:14:16 -0400414 pProtoNode = resoveNodeRS.nodes[0]->AsNode();
Dan Sinclair1770c022016-03-14 14:14:16 -0400415 } else if (!wsID.IsEmpty()) {
tsepez6bb3b892017-01-05 12:18:41 -0800416 auto it = mIDMap.find(FX_HashCode_GetW(wsID, false));
417 if (it == mIDMap.end())
Dan Sinclair1770c022016-03-14 14:14:16 -0400418 continue;
tsepez6bb3b892017-01-05 12:18:41 -0800419 pProtoNode = it->second;
Dan Sinclair1770c022016-03-14 14:14:16 -0400420 }
dsinclair16280242016-07-21 12:03:47 -0700421 if (!pProtoNode)
Dan Sinclair1770c022016-03-14 14:14:16 -0400422 continue;
dsinclair16280242016-07-21 12:03:47 -0700423
424 MergeNode(this, pUseHrefNode, pProtoNode);
Dan Sinclair1770c022016-03-14 14:14:16 -0400425 }
426}