• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/fxcrt/fx_ext.h"
8 #include "xfa/fxfa/app/xfa_ffnotify.h"
9 #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"
15 #include "xfa/fxfa/parser/cxfa_document.h"
16 #include "xfa/fxfa/parser/cxfa_document_parser.h"
17 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
18 #include "xfa/fxfa/parser/cxfa_scriptcontext.h"
19 #include "xfa/fxfa/parser/xfa_localemgr.h"
20 #include "xfa/fxfa/parser/xfa_object.h"
21 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
22 #include "xfa/fxfa/parser/xfa_utils.h"
23 
24 namespace {
25 
MergeNodeRecurse(CXFA_Document * pDocument,CXFA_Node * pDestNodeParent,CXFA_Node * pProtoNode)26 void 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   }
53   CXFA_Node* pNewNode = pProtoNode->Clone(true);
54   pNewNode->SetTemplateNode(pProtoNode);
55   pDestNodeParent->InsertChild(pNewNode, nullptr);
56 }
57 
MergeNode(CXFA_Document * pDocument,CXFA_Node * pDestNode,CXFA_Node * pProtoNode)58 void 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 
CXFA_Document(CXFA_DocumentParser * pParser)86 CXFA_Document::CXFA_Document(CXFA_DocumentParser* pParser)
87     : 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 }
102 
~CXFA_Document()103 CXFA_Document::~CXFA_Document() {
104   delete m_pRootNode;
105   PurgeNodes();
106 }
107 
GetLayoutProcessor()108 CXFA_LayoutProcessor* CXFA_Document::GetLayoutProcessor() {
109   if (!m_pLayoutProcessor)
110     m_pLayoutProcessor = new CXFA_LayoutProcessor(this);
111   return m_pLayoutProcessor;
112 }
113 
GetDocLayout()114 CXFA_LayoutProcessor* CXFA_Document::GetDocLayout() {
115   return GetLayoutProcessor();
116 }
117 
ClearLayoutData()118 void CXFA_Document::ClearLayoutData() {
119   delete m_pLayoutProcessor;
120   m_pLayoutProcessor = nullptr;
121   delete m_pScriptContext;
122   m_pScriptContext = nullptr;
123   delete m_pLocalMgr;
124   m_pLocalMgr = nullptr;
125   delete m_pScriptDataWindow;
126   m_pScriptDataWindow = nullptr;
127   delete m_pScriptEvent;
128   m_pScriptEvent = nullptr;
129   delete m_pScriptHost;
130   m_pScriptHost = nullptr;
131   delete m_pScriptLog;
132   m_pScriptLog = nullptr;
133   delete m_pScriptLayout;
134   m_pScriptLayout = nullptr;
135   delete m_pScriptSignature;
136   m_pScriptSignature = nullptr;
137 }
138 
SetRoot(CXFA_Node * pNewRoot)139 void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) {
140   if (m_pRootNode)
141     AddPurgeNode(m_pRootNode);
142 
143   m_pRootNode = pNewRoot;
144   RemovePurgeNode(pNewRoot);
145 }
146 
GetXMLDoc() const147 CFDE_XMLDoc* CXFA_Document::GetXMLDoc() const {
148   return m_pParser->GetXMLDoc();
149 }
150 
GetNotify() const151 CXFA_FFNotify* CXFA_Document::GetNotify() const {
152   return m_pParser->GetNotify();
153 }
154 
GetXFAObject(XFA_HashCode dwNodeNameHash)155 CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) {
156   switch (dwNodeNameHash) {
157     case XFA_HASHCODE_Data: {
158       CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
159       if (!pDatasetsNode)
160         return nullptr;
161 
162       for (CXFA_Node* pDatasetsChild =
163                pDatasetsNode->GetFirstChildByClass(XFA_Element::DataGroup);
164            pDatasetsChild;
165            pDatasetsChild = pDatasetsChild->GetNextSameClassSibling(
166                XFA_Element::DataGroup)) {
167         if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data)
168           continue;
169 
170         CFX_WideString wsNamespaceURI;
171         if (!pDatasetsChild->TryNamespace(wsNamespaceURI))
172           continue;
173 
174         CFX_WideString wsDatasetsURI;
175         if (!pDatasetsNode->TryNamespace(wsDatasetsURI))
176           continue;
177         if (wsNamespaceURI == wsDatasetsURI)
178           return pDatasetsChild;
179       }
180       return nullptr;
181     }
182     case XFA_HASHCODE_Record: {
183       CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data));
184       return pData ? pData->GetFirstChildByClass(XFA_Element::DataGroup)
185                    : nullptr;
186     }
187     case XFA_HASHCODE_DataWindow: {
188       if (!m_pScriptDataWindow)
189         m_pScriptDataWindow = new CScript_DataWindow(this);
190       return m_pScriptDataWindow;
191     }
192     case XFA_HASHCODE_Event: {
193       if (!m_pScriptEvent)
194         m_pScriptEvent = new CScript_EventPseudoModel(this);
195       return m_pScriptEvent;
196     }
197     case XFA_HASHCODE_Host: {
198       if (!m_pScriptHost)
199         m_pScriptHost = new CScript_HostPseudoModel(this);
200       return m_pScriptHost;
201     }
202     case XFA_HASHCODE_Log: {
203       if (!m_pScriptLog)
204         m_pScriptLog = new CScript_LogPseudoModel(this);
205       return m_pScriptLog;
206     }
207     case XFA_HASHCODE_Signature: {
208       if (!m_pScriptSignature)
209         m_pScriptSignature = new CScript_SignaturePseudoModel(this);
210       return m_pScriptSignature;
211     }
212     case XFA_HASHCODE_Layout: {
213       if (!m_pScriptLayout)
214         m_pScriptLayout = new CScript_LayoutPseudoModel(this);
215       return m_pScriptLayout;
216     }
217     default:
218       return m_pRootNode->GetFirstChildByName(dwNodeNameHash);
219   }
220 }
221 
CreateNode(uint32_t dwPacket,XFA_Element eElement)222 CXFA_Node* CXFA_Document::CreateNode(uint32_t dwPacket, XFA_Element eElement) {
223   return CreateNode(XFA_GetPacketByID(dwPacket), eElement);
224 }
225 
CreateNode(const XFA_PACKETINFO * pPacket,XFA_Element eElement)226 CXFA_Node* CXFA_Document::CreateNode(const XFA_PACKETINFO* pPacket,
227                                      XFA_Element eElement) {
228   if (!pPacket)
229     return nullptr;
230 
231   const XFA_ELEMENTINFO* pElement = XFA_GetElementByID(eElement);
232   if (pElement && (pElement->dwPackets & pPacket->eName)) {
233     CXFA_Node* pNode =
234         new CXFA_Node(this, pPacket->eName, pElement->eObjectType,
235                       pElement->eName, pElement->pName);
236     AddPurgeNode(pNode);
237     return pNode;
238   }
239 
240   return nullptr;
241 }
242 
AddPurgeNode(CXFA_Node * pNode)243 void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) {
244   m_PurgeNodes.insert(pNode);
245 }
246 
RemovePurgeNode(CXFA_Node * pNode)247 bool CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) {
248   return !!m_PurgeNodes.erase(pNode);
249 }
250 
PurgeNodes()251 void CXFA_Document::PurgeNodes() {
252   for (CXFA_Node* pNode : m_PurgeNodes)
253     delete pNode;
254 
255   m_PurgeNodes.clear();
256 }
257 
SetFlag(uint32_t dwFlag,bool bOn)258 void CXFA_Document::SetFlag(uint32_t dwFlag, bool bOn) {
259   if (bOn)
260     m_dwDocFlags |= dwFlag;
261   else
262     m_dwDocFlags &= ~dwFlag;
263 }
264 
IsInteractive()265 bool CXFA_Document::IsInteractive() {
266   if (m_dwDocFlags & XFA_DOCFLAG_HasInteractive)
267     return !!(m_dwDocFlags & XFA_DOCFLAG_Interactive);
268 
269   CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config));
270   if (!pConfig)
271     return false;
272 
273   CFX_WideString wsInteractive;
274   CXFA_Node* pPresent = pConfig->GetFirstChildByClass(XFA_Element::Present);
275   if (!pPresent)
276     return false;
277 
278   CXFA_Node* pPDF = pPresent->GetFirstChildByClass(XFA_Element::Pdf);
279   if (!pPDF)
280     return false;
281 
282   CXFA_Node* pFormFiller = pPDF->GetChild(0, XFA_Element::Interactive);
283   if (pFormFiller) {
284     m_dwDocFlags |= XFA_DOCFLAG_HasInteractive;
285     if (pFormFiller->TryContent(wsInteractive) && wsInteractive == L"1") {
286       m_dwDocFlags |= XFA_DOCFLAG_Interactive;
287       return true;
288     }
289   }
290   return false;
291 }
292 
GetLocalMgr()293 CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() {
294   if (!m_pLocalMgr) {
295     m_pLocalMgr =
296         new CXFA_LocaleMgr(ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)),
297                            GetNotify()->GetAppProvider()->GetLanguage());
298   }
299   return m_pLocalMgr;
300 }
301 
InitScriptContext(v8::Isolate * pIsolate)302 CXFA_ScriptContext* CXFA_Document::InitScriptContext(v8::Isolate* pIsolate) {
303   if (!m_pScriptContext)
304     m_pScriptContext = new CXFA_ScriptContext(this);
305   m_pScriptContext->Initialize(pIsolate);
306   return m_pScriptContext;
307 }
308 
GetScriptContext()309 CXFA_ScriptContext* CXFA_Document::GetScriptContext() {
310   if (!m_pScriptContext)
311     m_pScriptContext = new CXFA_ScriptContext(this);
312   return m_pScriptContext;
313 }
314 
RecognizeXFAVersionNumber(CFX_WideString & wsTemplateNS)315 XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
316     CFX_WideString& wsTemplateNS) {
317   CFX_WideStringC wsTemplateURIPrefix =
318       XFA_GetPacketByIndex(XFA_PACKET_Template)->pURI;
319   FX_STRSIZE nPrefixLength = wsTemplateURIPrefix.GetLength();
320   if (CFX_WideStringC(wsTemplateNS.c_str(), wsTemplateNS.GetLength()) !=
321       wsTemplateURIPrefix) {
322     return XFA_VERSION_UNKNOWN;
323   }
324   FX_STRSIZE nDotPos = wsTemplateNS.Find('.', nPrefixLength);
325   if (nDotPos == (FX_STRSIZE)-1)
326     return XFA_VERSION_UNKNOWN;
327 
328   int8_t iMajor = FXSYS_wtoi(
329       wsTemplateNS.Mid(nPrefixLength, nDotPos - nPrefixLength).c_str());
330   int8_t iMinor = FXSYS_wtoi(
331       wsTemplateNS.Mid(nDotPos + 1, wsTemplateNS.GetLength() - nDotPos - 2)
332           .c_str());
333   XFA_VERSION eVersion = (XFA_VERSION)((int32_t)iMajor * 100 + iMinor);
334   if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX)
335     return XFA_VERSION_UNKNOWN;
336 
337   m_eCurVersionMode = eVersion;
338   return eVersion;
339 }
340 
GetNodeByID(CXFA_Node * pRoot,const CFX_WideStringC & wsID)341 CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
342                                       const CFX_WideStringC& wsID) {
343   if (!pRoot || wsID.IsEmpty())
344     return nullptr;
345 
346   CXFA_NodeIterator sIterator(pRoot);
347   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
348        pNode = sIterator.MoveToNext()) {
349     CFX_WideStringC wsIDVal;
350     if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
351       if (wsIDVal == wsID)
352         return pNode;
353     }
354   }
355   return nullptr;
356 }
357 
DoProtoMerge()358 void CXFA_Document::DoProtoMerge() {
359   CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(XFA_HASHCODE_Template));
360   if (!pTemplateRoot)
361     return;
362 
363   std::map<uint32_t, CXFA_Node*> mIDMap;
364   CXFA_NodeSet sUseNodes;
365   CXFA_NodeIterator sIterator(pTemplateRoot);
366   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
367        pNode = sIterator.MoveToNext()) {
368     CFX_WideStringC wsIDVal;
369     if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
370       mIDMap[FX_HashCode_GetW(wsIDVal, false)] = pNode;
371     }
372     CFX_WideStringC wsUseVal;
373     if (pNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) && !wsUseVal.IsEmpty()) {
374       sUseNodes.insert(pNode);
375     } else if (pNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
376                !wsUseVal.IsEmpty()) {
377       sUseNodes.insert(pNode);
378     }
379   }
380 
381   for (CXFA_Node* pUseHrefNode : sUseNodes) {
382     CFX_WideString wsUseVal;
383     CFX_WideStringC wsURI, wsID, wsSOM;
384     if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
385         !wsUseVal.IsEmpty()) {
386       FX_STRSIZE uSharpPos = wsUseVal.Find('#');
387       if (uSharpPos < 0) {
388         wsURI = wsUseVal.AsStringC();
389       } else {
390         wsURI = CFX_WideStringC(wsUseVal.c_str(), uSharpPos);
391         FX_STRSIZE uLen = wsUseVal.GetLength();
392         if (uLen >= uSharpPos + 5 &&
393             CFX_WideStringC(wsUseVal.c_str() + uSharpPos, 5) == L"#som(" &&
394             wsUseVal[uLen - 1] == ')') {
395           wsSOM = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 5,
396                                   uLen - 1 - uSharpPos - 5);
397         } else {
398           wsID = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 1,
399                                  uLen - uSharpPos - 1);
400         }
401       }
402     } else if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) &&
403                !wsUseVal.IsEmpty()) {
404       if (wsUseVal[0] == '#')
405         wsID = CFX_WideStringC(wsUseVal.c_str() + 1, wsUseVal.GetLength() - 1);
406       else
407         wsSOM = CFX_WideStringC(wsUseVal.c_str(), wsUseVal.GetLength());
408     }
409 
410     if (!wsURI.IsEmpty() && wsURI != L".")
411       continue;
412 
413     CXFA_Node* pProtoNode = nullptr;
414     if (!wsSOM.IsEmpty()) {
415       uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
416                         XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
417                         XFA_RESOLVENODE_Siblings;
418       XFA_RESOLVENODE_RS resoveNodeRS;
419       int32_t iRet = m_pScriptContext->ResolveObjects(pUseHrefNode, wsSOM,
420                                                       resoveNodeRS, dwFlag);
421       if (iRet > 0 && resoveNodeRS.nodes[0]->IsNode())
422         pProtoNode = resoveNodeRS.nodes[0]->AsNode();
423     } else if (!wsID.IsEmpty()) {
424       auto it = mIDMap.find(FX_HashCode_GetW(wsID, false));
425       if (it == mIDMap.end())
426         continue;
427       pProtoNode = it->second;
428     }
429     if (!pProtoNode)
430       continue;
431 
432     MergeNode(this, pUseHrefNode, pProtoNode);
433   }
434 }
435