1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/src/foxitlib.h"
8 #include "xfa/src/fxfa/src/common/xfa_utils.h"
9 #include "xfa/src/fxfa/src/common/xfa_object.h"
10 #include "xfa/src/fxfa/src/common/xfa_document.h"
11 #include "xfa/src/fxfa/src/common/xfa_parser.h"
12 #include "xfa/src/fxfa/src/common/xfa_script.h"
13 #include "xfa/src/fxfa/src/common/xfa_docdata.h"
14 #include "xfa/src/fxfa/src/common/xfa_doclayout.h"
15 #include "xfa/src/fxfa/src/common/xfa_localemgr.h"
16 #include "xfa/src/fxfa/src/common/xfa_fm2jsapi.h"
17 #include "xfa_basic_imp.h"
18 #include "xfa_document_layout_imp.h"
19 #include "xfa_script_datawindow.h"
20 #include "xfa_script_eventpseudomodel.h"
21 #include "xfa_script_hostpseudomodel.h"
22 #include "xfa_script_logpseudomodel.h"
23 #include "xfa_script_layoutpseudomodel.h"
24 #include "xfa_script_signaturepseudomodel.h"
CXFA_Document(IXFA_DocParser * pParser)25 CXFA_Document::CXFA_Document(IXFA_DocParser* pParser)
26 : m_pParser(pParser),
27 m_pScriptContext(nullptr),
28 m_pLayoutProcessor(nullptr),
29 m_pRootNode(nullptr),
30 m_pLocalMgr(nullptr),
31 m_pScriptDataWindow(nullptr),
32 m_pScriptEvent(nullptr),
33 m_pScriptHost(nullptr),
34 m_pScriptLog(nullptr),
35 m_pScriptLayout(nullptr),
36 m_pScriptSignature(nullptr),
37 m_eCurVersionMode(XFA_VERSION_DEFAULT),
38 m_dwDocFlags(0) {
39 ASSERT(m_pParser);
40 }
~CXFA_Document()41 CXFA_Document::~CXFA_Document() {
42 delete m_pRootNode;
43 PurgeNodes();
44 }
ClearLayoutData()45 void CXFA_Document::ClearLayoutData() {
46 if (m_pLayoutProcessor) {
47 delete m_pLayoutProcessor;
48 m_pLayoutProcessor = NULL;
49 }
50 if (m_pScriptContext) {
51 m_pScriptContext->Release();
52 m_pScriptContext = NULL;
53 }
54 if (m_pLocalMgr) {
55 delete m_pLocalMgr;
56 m_pLocalMgr = NULL;
57 }
58 if (m_pScriptDataWindow) {
59 delete m_pScriptDataWindow;
60 m_pScriptDataWindow = NULL;
61 }
62 if (m_pScriptEvent) {
63 delete m_pScriptEvent;
64 m_pScriptEvent = NULL;
65 }
66 if (m_pScriptHost) {
67 delete m_pScriptHost;
68 m_pScriptHost = NULL;
69 }
70 if (m_pScriptLog) {
71 delete m_pScriptLog;
72 m_pScriptLog = NULL;
73 }
74 if (m_pScriptLayout) {
75 delete m_pScriptLayout;
76 m_pScriptLayout = NULL;
77 }
78 if (m_pScriptSignature) {
79 delete m_pScriptSignature;
80 m_pScriptSignature = NULL;
81 }
82 }
SetRoot(CXFA_Node * pNewRoot)83 void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) {
84 if (m_pRootNode) {
85 AddPurgeNode(m_pRootNode);
86 }
87 m_pRootNode = pNewRoot;
88 RemovePurgeNode(pNewRoot);
89 }
GetNotify() const90 IXFA_Notify* CXFA_Document::GetNotify() const {
91 return m_pParser->GetNotify();
92 }
GetXFANode(const CFX_WideStringC & wsNodeName)93 CXFA_Object* CXFA_Document::GetXFANode(const CFX_WideStringC& wsNodeName) {
94 return GetXFANode(
95 FX_HashCode_String_GetW(wsNodeName.GetPtr(), wsNodeName.GetLength()));
96 }
GetXFANode(FX_DWORD dwNodeNameHash)97 CXFA_Object* CXFA_Document::GetXFANode(FX_DWORD dwNodeNameHash) {
98 switch (dwNodeNameHash) {
99 case XFA_HASHCODE_Data: {
100 CXFA_Node* pDatasetsNode = (CXFA_Node*)GetXFANode(XFA_HASHCODE_Datasets);
101 if (!pDatasetsNode) {
102 return NULL;
103 }
104 for (CXFA_Node* pDatasetsChild =
105 pDatasetsNode->GetFirstChildByClass(XFA_ELEMENT_DataGroup);
106 pDatasetsChild;
107 pDatasetsChild =
108 pDatasetsChild->GetNextSameClassSibling(XFA_ELEMENT_DataGroup)) {
109 if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data) {
110 continue;
111 }
112 CFX_WideString wsNamespaceURI;
113 if (!pDatasetsChild->TryNamespace(wsNamespaceURI)) {
114 continue;
115 }
116 CFX_WideString wsDatasetsURI;
117 if (!pDatasetsNode->TryNamespace(wsDatasetsURI)) {
118 continue;
119 }
120 if (wsNamespaceURI == wsDatasetsURI) {
121 return pDatasetsChild;
122 }
123 }
124 }
125 return NULL;
126 case XFA_HASHCODE_Record: {
127 CXFA_Node* pData = (CXFA_Node*)GetXFANode(XFA_HASHCODE_Data);
128 return pData ? pData->GetFirstChildByClass(XFA_ELEMENT_DataGroup) : NULL;
129 }
130 case XFA_HASHCODE_DataWindow: {
131 if (m_pScriptDataWindow == NULL) {
132 m_pScriptDataWindow = new CScript_DataWindow(this);
133 }
134 return m_pScriptDataWindow;
135 }
136 case XFA_HASHCODE_Event: {
137 if (m_pScriptEvent == NULL) {
138 m_pScriptEvent = new CScript_EventPseudoModel(this);
139 }
140 return m_pScriptEvent;
141 }
142 case XFA_HASHCODE_Host: {
143 if (m_pScriptHost == NULL) {
144 m_pScriptHost = new CScript_HostPseudoModel(this);
145 }
146 return m_pScriptHost;
147 }
148 case XFA_HASHCODE_Log: {
149 if (m_pScriptLog == NULL) {
150 m_pScriptLog = new CScript_LogPseudoModel(this);
151 }
152 return m_pScriptLog;
153 }
154 case XFA_HASHCODE_Signature: {
155 if (m_pScriptSignature == NULL) {
156 m_pScriptSignature = new CScript_SignaturePseudoModel(this);
157 }
158 return m_pScriptSignature;
159 }
160 case XFA_HASHCODE_Layout: {
161 if (m_pScriptLayout == NULL) {
162 m_pScriptLayout = new CScript_LayoutPseudoModel(this);
163 }
164 return m_pScriptLayout;
165 }
166 default:
167 return m_pRootNode->GetFirstChildByName(dwNodeNameHash);
168 }
169 }
CreateNode(FX_DWORD dwPacket,XFA_ELEMENT eElement)170 CXFA_Node* CXFA_Document::CreateNode(FX_DWORD dwPacket, XFA_ELEMENT eElement) {
171 XFA_LPCPACKETINFO pPacket = XFA_GetPacketByID(dwPacket);
172 return CreateNode(pPacket, eElement);
173 }
CreateNode(XFA_LPCPACKETINFO pPacket,XFA_ELEMENT eElement)174 CXFA_Node* CXFA_Document::CreateNode(XFA_LPCPACKETINFO pPacket,
175 XFA_ELEMENT eElement) {
176 if (pPacket == NULL) {
177 return NULL;
178 }
179 XFA_LPCELEMENTINFO pElement = XFA_GetElementByID(eElement);
180 if (pElement && (pElement->dwPackets & pPacket->eName)) {
181 CXFA_Node* pNode = new CXFA_Node(this, pPacket->eName, pElement->eName);
182 if (pNode) {
183 AddPurgeNode(pNode);
184 }
185 return pNode;
186 }
187 return NULL;
188 }
AddPurgeNode(CXFA_Node * pNode)189 void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) {
190 m_rgPurgeNodes.Add(pNode);
191 }
RemovePurgeNode(CXFA_Node * pNode)192 FX_BOOL CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) {
193 return m_rgPurgeNodes.RemoveKey(pNode);
194 }
PurgeNodes()195 void CXFA_Document::PurgeNodes() {
196 FX_POSITION psNode = m_rgPurgeNodes.GetStartPosition();
197 while (psNode) {
198 CXFA_Node* pNode;
199 m_rgPurgeNodes.GetNextAssoc(psNode, pNode);
200 delete pNode;
201 }
202 m_rgPurgeNodes.RemoveAll();
203 }
SetFlag(FX_DWORD dwFlag,FX_BOOL bOn)204 void CXFA_Document::SetFlag(FX_DWORD dwFlag, FX_BOOL bOn) {
205 if (bOn) {
206 m_dwDocFlags |= dwFlag;
207 } else {
208 m_dwDocFlags &= ~dwFlag;
209 }
210 }
IsInteractive()211 FX_BOOL CXFA_Document::IsInteractive() {
212 if (m_dwDocFlags & XFA_DOCFLAG_HasInteractive) {
213 return m_dwDocFlags & XFA_DOCFLAG_Interactive;
214 }
215 CXFA_Node* pConfig = (CXFA_Node*)this->GetXFANode(XFA_HASHCODE_Config);
216 if (!pConfig) {
217 return FALSE;
218 }
219 CFX_WideString wsInteractive;
220 CXFA_Node* pPresent = pConfig->GetFirstChildByClass(XFA_ELEMENT_Present);
221 if (!pPresent) {
222 return FALSE;
223 }
224 CXFA_Node* pPDF = pPresent->GetFirstChildByClass(XFA_ELEMENT_Pdf);
225 if (!pPDF) {
226 return FALSE;
227 }
228 CXFA_Node* pInteractive = pPDF->GetChild(0, XFA_ELEMENT_Interactive);
229 if (pInteractive) {
230 m_dwDocFlags |= XFA_DOCFLAG_HasInteractive;
231 if (pInteractive->TryContent(wsInteractive) &&
232 wsInteractive == FX_WSTRC(L"1")) {
233 m_dwDocFlags |= XFA_DOCFLAG_Interactive;
234 return TRUE;
235 }
236 }
237 return FALSE;
238 }
GetLocalMgr()239 CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() {
240 if (!m_pLocalMgr) {
241 CFX_WideString wsLanguage;
242 this->GetParser()->GetNotify()->GetAppProvider()->GetLanguage(wsLanguage);
243 m_pLocalMgr = new CXFA_LocaleMgr(
244 (CXFA_Node*)this->GetXFANode(XFA_HASHCODE_LocaleSet), wsLanguage);
245 }
246 return m_pLocalMgr;
247 }
InitScriptContext(FXJSE_HRUNTIME hRuntime)248 IXFA_ScriptContext* CXFA_Document::InitScriptContext(FXJSE_HRUNTIME hRuntime) {
249 if (!m_pScriptContext) {
250 m_pScriptContext = XFA_ScriptContext_Create(this);
251 }
252 m_pScriptContext->Initialize(hRuntime);
253 return m_pScriptContext;
254 }
GetScriptContext()255 IXFA_ScriptContext* CXFA_Document::GetScriptContext() {
256 if (!m_pScriptContext) {
257 m_pScriptContext = XFA_ScriptContext_Create(this);
258 }
259 return m_pScriptContext;
260 }
RecognizeXFAVersionNumber(CFX_WideString & wsTemplateNS)261 XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
262 CFX_WideString& wsTemplateNS) {
263 CFX_WideStringC wsTemplateURIPrefix =
264 XFA_GetPacketByIndex(XFA_PACKET_Template)->pURI;
265 FX_STRSIZE nPrefixLength = wsTemplateURIPrefix.GetLength();
266 if (CFX_WideStringC(wsTemplateNS, wsTemplateNS.GetLength()) !=
267 wsTemplateURIPrefix) {
268 return XFA_VERSION_UNKNOWN;
269 }
270 FX_STRSIZE nDotPos = wsTemplateNS.Find('.', nPrefixLength);
271 if (nDotPos == (FX_STRSIZE)-1) {
272 return XFA_VERSION_UNKNOWN;
273 }
274 int8_t iMajor =
275 FXSYS_wtoi(wsTemplateNS.Mid(nPrefixLength, nDotPos - nPrefixLength));
276 int8_t iMinor = FXSYS_wtoi(
277 wsTemplateNS.Mid(nDotPos + 1, wsTemplateNS.GetLength() - nDotPos - 2));
278 XFA_VERSION eVersion = (XFA_VERSION)((int32_t)iMajor * 100 + iMinor);
279 if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX) {
280 return XFA_VERSION_UNKNOWN;
281 }
282 m_eCurVersionMode = eVersion;
283 return eVersion;
284 }
GetNodeByID(CXFA_Node * pRoot,const CFX_WideStringC & wsID)285 CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
286 const CFX_WideStringC& wsID) {
287 if (!pRoot || wsID.IsEmpty()) {
288 return NULL;
289 }
290 CXFA_NodeIterator sIterator(pRoot);
291 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
292 pNode = sIterator.MoveToNext()) {
293 CFX_WideStringC wsIDVal;
294 if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
295 if (wsIDVal == wsID) {
296 return pNode;
297 }
298 }
299 }
300 return NULL;
301 }
XFA_ProtoMerge_MergeNodeRecurse(CXFA_Document * pDocument,CXFA_Node * pDestNodeParent,CXFA_Node * pProtoNode)302 static void XFA_ProtoMerge_MergeNodeRecurse(CXFA_Document* pDocument,
303 CXFA_Node* pDestNodeParent,
304 CXFA_Node* pProtoNode) {
305 CXFA_Node* pExistingNode = NULL;
306 for (CXFA_Node* pFormChild =
307 pDestNodeParent->GetNodeItem(XFA_NODEITEM_FirstChild);
308 pFormChild;
309 pFormChild = pFormChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
310 if (pFormChild->GetClassID() == pProtoNode->GetClassID() &&
311 pFormChild->GetNameHash() == pProtoNode->GetNameHash() &&
312 pFormChild->HasFlag(XFA_NODEFLAG_UnusedNode)) {
313 pFormChild->SetFlag(XFA_NODEFLAG_UnusedNode, FALSE);
314 pExistingNode = pFormChild;
315 break;
316 }
317 }
318 if (pExistingNode) {
319 pExistingNode->SetTemplateNode(pProtoNode);
320 for (CXFA_Node* pTemplateChild =
321 pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
322 pTemplateChild; pTemplateChild = pTemplateChild->GetNodeItem(
323 XFA_NODEITEM_NextSibling)) {
324 XFA_ProtoMerge_MergeNodeRecurse(pDocument, pExistingNode, pTemplateChild);
325 }
326 return;
327 }
328 CXFA_Node* pNewNode = pProtoNode->Clone(TRUE);
329 pNewNode->SetTemplateNode(pProtoNode);
330 pDestNodeParent->InsertChild(pNewNode, NULL);
331 }
XFA_ProtoMerge_MergeNode(CXFA_Document * pDocument,CXFA_Node * pDestNode,CXFA_Node * pProtoNode)332 static void XFA_ProtoMerge_MergeNode(CXFA_Document* pDocument,
333 CXFA_Node* pDestNode,
334 CXFA_Node* pProtoNode) {
335 {
336 CXFA_NodeIterator sIterator(pDestNode);
337 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
338 pNode = sIterator.MoveToNext()) {
339 pNode->SetFlag(XFA_NODEFLAG_UnusedNode);
340 }
341 }
342 pDestNode->SetTemplateNode(pProtoNode);
343 for (CXFA_Node* pTemplateChild =
344 pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
345 pTemplateChild;
346 pTemplateChild = pTemplateChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
347 XFA_ProtoMerge_MergeNodeRecurse(pDocument, pDestNode, pTemplateChild);
348 }
349 {
350 CXFA_NodeIterator sIterator(pDestNode);
351 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
352 pNode = sIterator.MoveToNext()) {
353 pNode->SetFlag(XFA_NODEFLAG_UnusedNode, FALSE);
354 }
355 }
356 }
DoProtoMerge()357 void CXFA_Document::DoProtoMerge() {
358 CXFA_Node* pTemplateRoot = (CXFA_Node*)GetXFANode(XFA_HASHCODE_Template);
359 if (!pTemplateRoot) {
360 return;
361 }
362 CFX_MapPtrTemplate<FX_DWORD, CXFA_Node*> mIDMap;
363 CXFA_NodeSet sUseNodes;
364 CXFA_NodeIterator sIterator(pTemplateRoot);
365 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
366 pNode = sIterator.MoveToNext()) {
367 CFX_WideStringC wsIDVal;
368 if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
369 mIDMap[FX_HashCode_String_GetW(wsIDVal.GetPtr(), wsIDVal.GetLength())] =
370 pNode;
371 }
372 CFX_WideStringC wsUseVal;
373 if (pNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) && !wsUseVal.IsEmpty()) {
374 sUseNodes.Add(pNode);
375 } else if (pNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
376 !wsUseVal.IsEmpty()) {
377 sUseNodes.Add(pNode);
378 }
379 }
380 FX_POSITION pos = sUseNodes.GetStartPosition();
381 while (pos) {
382 CXFA_Node* pUseHrefNode = NULL;
383 sUseNodes.GetNextAssoc(pos, pUseHrefNode);
384 CFX_WideString wsUseVal;
385 CFX_WideStringC wsURI, wsID, wsSOM;
386 if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
387 !wsUseVal.IsEmpty()) {
388 FX_STRSIZE uSharpPos = wsUseVal.Find('#');
389 if (uSharpPos < 0) {
390 wsURI = wsUseVal;
391 } else {
392 wsURI = CFX_WideStringC((const FX_WCHAR*)wsUseVal, uSharpPos);
393 FX_STRSIZE uLen = wsUseVal.GetLength();
394 if (uLen >= uSharpPos + 5 &&
395 CFX_WideStringC((const FX_WCHAR*)wsUseVal + uSharpPos, 5) ==
396 FX_WSTRC(L"#som(") &&
397 wsUseVal[uLen - 1] == ')') {
398 wsSOM = CFX_WideStringC((const FX_WCHAR*)wsUseVal + uSharpPos + 5,
399 uLen - 1 - uSharpPos - 5);
400 } else {
401 wsID = CFX_WideStringC((const FX_WCHAR*)wsUseVal + uSharpPos + 1,
402 uLen - uSharpPos - 1);
403 }
404 }
405 } else if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) &&
406 !wsUseVal.IsEmpty()) {
407 if (wsUseVal[0] == '#') {
408 wsID = CFX_WideStringC((const FX_WCHAR*)wsUseVal + 1,
409 wsUseVal.GetLength() - 1);
410 } else {
411 wsSOM =
412 CFX_WideStringC((const FX_WCHAR*)wsUseVal, wsUseVal.GetLength());
413 }
414 }
415 if (!wsURI.IsEmpty() && wsURI != FX_WSTRC(L".")) {
416 continue;
417 }
418 CXFA_Node* pProtoNode = NULL;
419 if (!wsSOM.IsEmpty()) {
420 FX_DWORD dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
421 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
422 XFA_RESOLVENODE_Siblings;
423 XFA_RESOLVENODE_RS resoveNodeRS;
424 int32_t iRet = m_pScriptContext->ResolveObjects(pUseHrefNode, wsSOM,
425 resoveNodeRS, dwFlag);
426 if (iRet > 0 && resoveNodeRS.nodes[0]->IsNode()) {
427 pProtoNode = (CXFA_Node*)resoveNodeRS.nodes[0];
428 }
429 } else if (!wsID.IsEmpty()) {
430 if (!mIDMap.Lookup(
431 FX_HashCode_String_GetW(wsID.GetPtr(), wsID.GetLength()),
432 pProtoNode)) {
433 continue;
434 }
435 }
436 if (!pProtoNode) {
437 continue;
438 }
439 XFA_ProtoMerge_MergeNode(this, pUseHrefNode, pProtoNode);
440 }
441 }
442