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