OLD | NEW |
| (Empty) |
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/include/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_parser.h" | |
16 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" | |
17 #include "xfa/fxfa/parser/cxfa_scriptcontext.h" | |
18 #include "xfa/fxfa/parser/xfa_document.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 CXFA_Document::CXFA_Document(CXFA_DocumentParser* pParser) | |
25 : m_pParser(pParser), | |
26 m_pScriptContext(nullptr), | |
27 m_pLayoutProcessor(nullptr), | |
28 m_pRootNode(nullptr), | |
29 m_pLocalMgr(nullptr), | |
30 m_pScriptDataWindow(nullptr), | |
31 m_pScriptEvent(nullptr), | |
32 m_pScriptHost(nullptr), | |
33 m_pScriptLog(nullptr), | |
34 m_pScriptLayout(nullptr), | |
35 m_pScriptSignature(nullptr), | |
36 m_eCurVersionMode(XFA_VERSION_DEFAULT), | |
37 m_dwDocFlags(0) { | |
38 ASSERT(m_pParser); | |
39 } | |
40 CXFA_Document::~CXFA_Document() { | |
41 delete m_pRootNode; | |
42 PurgeNodes(); | |
43 } | |
44 | |
45 void CXFA_Document::ClearLayoutData() { | |
46 delete m_pLayoutProcessor; | |
47 m_pLayoutProcessor = nullptr; | |
48 delete m_pScriptContext; | |
49 m_pScriptContext = nullptr; | |
50 delete m_pLocalMgr; | |
51 m_pLocalMgr = nullptr; | |
52 delete m_pScriptDataWindow; | |
53 m_pScriptDataWindow = nullptr; | |
54 delete m_pScriptEvent; | |
55 m_pScriptEvent = nullptr; | |
56 delete m_pScriptHost; | |
57 m_pScriptHost = nullptr; | |
58 delete m_pScriptLog; | |
59 m_pScriptLog = nullptr; | |
60 delete m_pScriptLayout; | |
61 m_pScriptLayout = nullptr; | |
62 delete m_pScriptSignature; | |
63 m_pScriptSignature = nullptr; | |
64 } | |
65 | |
66 void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) { | |
67 if (m_pRootNode) { | |
68 AddPurgeNode(m_pRootNode); | |
69 } | |
70 m_pRootNode = pNewRoot; | |
71 RemovePurgeNode(pNewRoot); | |
72 } | |
73 | |
74 CFDE_XMLDoc* CXFA_Document::GetXMLDoc() const { | |
75 return m_pParser->GetXMLDoc(); | |
76 } | |
77 | |
78 CXFA_FFNotify* CXFA_Document::GetNotify() const { | |
79 return m_pParser->GetNotify(); | |
80 } | |
81 | |
82 CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) { | |
83 switch (dwNodeNameHash) { | |
84 case XFA_HASHCODE_Data: { | |
85 CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets)); | |
86 if (!pDatasetsNode) { | |
87 return nullptr; | |
88 } | |
89 for (CXFA_Node* pDatasetsChild = | |
90 pDatasetsNode->GetFirstChildByClass(XFA_Element::DataGroup); | |
91 pDatasetsChild; | |
92 pDatasetsChild = pDatasetsChild->GetNextSameClassSibling( | |
93 XFA_Element::DataGroup)) { | |
94 if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data) { | |
95 continue; | |
96 } | |
97 CFX_WideString wsNamespaceURI; | |
98 if (!pDatasetsChild->TryNamespace(wsNamespaceURI)) { | |
99 continue; | |
100 } | |
101 CFX_WideString wsDatasetsURI; | |
102 if (!pDatasetsNode->TryNamespace(wsDatasetsURI)) { | |
103 continue; | |
104 } | |
105 if (wsNamespaceURI == wsDatasetsURI) { | |
106 return pDatasetsChild; | |
107 } | |
108 } | |
109 return nullptr; | |
110 } | |
111 case XFA_HASHCODE_Record: { | |
112 CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data)); | |
113 return pData ? pData->GetFirstChildByClass(XFA_Element::DataGroup) | |
114 : nullptr; | |
115 } | |
116 case XFA_HASHCODE_DataWindow: { | |
117 if (!m_pScriptDataWindow) | |
118 m_pScriptDataWindow = new CScript_DataWindow(this); | |
119 return m_pScriptDataWindow; | |
120 } | |
121 case XFA_HASHCODE_Event: { | |
122 if (!m_pScriptEvent) | |
123 m_pScriptEvent = new CScript_EventPseudoModel(this); | |
124 return m_pScriptEvent; | |
125 } | |
126 case XFA_HASHCODE_Host: { | |
127 if (!m_pScriptHost) | |
128 m_pScriptHost = new CScript_HostPseudoModel(this); | |
129 return m_pScriptHost; | |
130 } | |
131 case XFA_HASHCODE_Log: { | |
132 if (!m_pScriptLog) | |
133 m_pScriptLog = new CScript_LogPseudoModel(this); | |
134 return m_pScriptLog; | |
135 } | |
136 case XFA_HASHCODE_Signature: { | |
137 if (!m_pScriptSignature) | |
138 m_pScriptSignature = new CScript_SignaturePseudoModel(this); | |
139 return m_pScriptSignature; | |
140 } | |
141 case XFA_HASHCODE_Layout: { | |
142 if (!m_pScriptLayout) | |
143 m_pScriptLayout = new CScript_LayoutPseudoModel(this); | |
144 return m_pScriptLayout; | |
145 } | |
146 default: | |
147 return m_pRootNode->GetFirstChildByName(dwNodeNameHash); | |
148 } | |
149 } | |
150 CXFA_Node* CXFA_Document::CreateNode(uint32_t dwPacket, XFA_Element eElement) { | |
151 return CreateNode(XFA_GetPacketByID(dwPacket), eElement); | |
152 } | |
153 | |
154 CXFA_Node* CXFA_Document::CreateNode(const XFA_PACKETINFO* pPacket, | |
155 XFA_Element eElement) { | |
156 if (!pPacket) | |
157 return nullptr; | |
158 | |
159 const XFA_ELEMENTINFO* pElement = XFA_GetElementByID(eElement); | |
160 if (pElement && (pElement->dwPackets & pPacket->eName)) { | |
161 CXFA_Node* pNode = | |
162 new CXFA_Node(this, pPacket->eName, pElement->eObjectType, | |
163 pElement->eName, pElement->pName); | |
164 AddPurgeNode(pNode); | |
165 return pNode; | |
166 } | |
167 | |
168 return nullptr; | |
169 } | |
170 | |
171 void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) { | |
172 m_PurgeNodes.insert(pNode); | |
173 } | |
174 | |
175 FX_BOOL CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) { | |
176 return !!m_PurgeNodes.erase(pNode); | |
177 } | |
178 | |
179 void CXFA_Document::PurgeNodes() { | |
180 for (CXFA_Node* pNode : m_PurgeNodes) | |
181 delete pNode; | |
182 | |
183 m_PurgeNodes.clear(); | |
184 } | |
185 | |
186 void CXFA_Document::SetFlag(uint32_t dwFlag, FX_BOOL bOn) { | |
187 if (bOn) { | |
188 m_dwDocFlags |= dwFlag; | |
189 } else { | |
190 m_dwDocFlags &= ~dwFlag; | |
191 } | |
192 } | |
193 FX_BOOL CXFA_Document::IsInteractive() { | |
194 if (m_dwDocFlags & XFA_DOCFLAG_HasInteractive) { | |
195 return !!(m_dwDocFlags & XFA_DOCFLAG_Interactive); | |
196 } | |
197 CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config)); | |
198 if (!pConfig) { | |
199 return FALSE; | |
200 } | |
201 CFX_WideString wsInteractive; | |
202 CXFA_Node* pPresent = pConfig->GetFirstChildByClass(XFA_Element::Present); | |
203 if (!pPresent) { | |
204 return FALSE; | |
205 } | |
206 CXFA_Node* pPDF = pPresent->GetFirstChildByClass(XFA_Element::Pdf); | |
207 if (!pPDF) { | |
208 return FALSE; | |
209 } | |
210 CXFA_Node* pInteractive = pPDF->GetChild(0, XFA_Element::Interactive); | |
211 if (pInteractive) { | |
212 m_dwDocFlags |= XFA_DOCFLAG_HasInteractive; | |
213 if (pInteractive->TryContent(wsInteractive) && | |
214 wsInteractive == FX_WSTRC(L"1")) { | |
215 m_dwDocFlags |= XFA_DOCFLAG_Interactive; | |
216 return TRUE; | |
217 } | |
218 } | |
219 return FALSE; | |
220 } | |
221 CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() { | |
222 if (!m_pLocalMgr) { | |
223 CFX_WideString wsLanguage; | |
224 GetNotify()->GetAppProvider()->GetLanguage(wsLanguage); | |
225 m_pLocalMgr = new CXFA_LocaleMgr( | |
226 ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)), wsLanguage); | |
227 } | |
228 return m_pLocalMgr; | |
229 } | |
230 CXFA_ScriptContext* CXFA_Document::InitScriptContext(v8::Isolate* pIsolate) { | |
231 if (!m_pScriptContext) | |
232 m_pScriptContext = new CXFA_ScriptContext(this); | |
233 m_pScriptContext->Initialize(pIsolate); | |
234 return m_pScriptContext; | |
235 } | |
236 CXFA_ScriptContext* CXFA_Document::GetScriptContext() { | |
237 if (!m_pScriptContext) | |
238 m_pScriptContext = new CXFA_ScriptContext(this); | |
239 return m_pScriptContext; | |
240 } | |
241 XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber( | |
242 CFX_WideString& wsTemplateNS) { | |
243 CFX_WideStringC wsTemplateURIPrefix = | |
244 XFA_GetPacketByIndex(XFA_PACKET_Template)->pURI; | |
245 FX_STRSIZE nPrefixLength = wsTemplateURIPrefix.GetLength(); | |
246 if (CFX_WideStringC(wsTemplateNS.c_str(), wsTemplateNS.GetLength()) != | |
247 wsTemplateURIPrefix) { | |
248 return XFA_VERSION_UNKNOWN; | |
249 } | |
250 FX_STRSIZE nDotPos = wsTemplateNS.Find('.', nPrefixLength); | |
251 if (nDotPos == (FX_STRSIZE)-1) { | |
252 return XFA_VERSION_UNKNOWN; | |
253 } | |
254 int8_t iMajor = FXSYS_wtoi( | |
255 wsTemplateNS.Mid(nPrefixLength, nDotPos - nPrefixLength).c_str()); | |
256 int8_t iMinor = FXSYS_wtoi( | |
257 wsTemplateNS.Mid(nDotPos + 1, wsTemplateNS.GetLength() - nDotPos - 2) | |
258 .c_str()); | |
259 XFA_VERSION eVersion = (XFA_VERSION)((int32_t)iMajor * 100 + iMinor); | |
260 if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX) { | |
261 return XFA_VERSION_UNKNOWN; | |
262 } | |
263 m_eCurVersionMode = eVersion; | |
264 return eVersion; | |
265 } | |
266 CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot, | |
267 const CFX_WideStringC& wsID) { | |
268 if (!pRoot || wsID.IsEmpty()) { | |
269 return nullptr; | |
270 } | |
271 CXFA_NodeIterator sIterator(pRoot); | |
272 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode; | |
273 pNode = sIterator.MoveToNext()) { | |
274 CFX_WideStringC wsIDVal; | |
275 if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) { | |
276 if (wsIDVal == wsID) { | |
277 return pNode; | |
278 } | |
279 } | |
280 } | |
281 return nullptr; | |
282 } | |
283 static void XFA_ProtoMerge_MergeNodeRecurse(CXFA_Document* pDocument, | |
284 CXFA_Node* pDestNodeParent, | |
285 CXFA_Node* pProtoNode) { | |
286 CXFA_Node* pExistingNode = nullptr; | |
287 for (CXFA_Node* pFormChild = | |
288 pDestNodeParent->GetNodeItem(XFA_NODEITEM_FirstChild); | |
289 pFormChild; | |
290 pFormChild = pFormChild->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
291 if (pFormChild->GetElementType() == pProtoNode->GetElementType() && | |
292 pFormChild->GetNameHash() == pProtoNode->GetNameHash() && | |
293 pFormChild->IsUnusedNode()) { | |
294 pFormChild->ClearFlag(XFA_NodeFlag_UnusedNode); | |
295 pExistingNode = pFormChild; | |
296 break; | |
297 } | |
298 } | |
299 if (pExistingNode) { | |
300 pExistingNode->SetTemplateNode(pProtoNode); | |
301 for (CXFA_Node* pTemplateChild = | |
302 pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
303 pTemplateChild; pTemplateChild = pTemplateChild->GetNodeItem( | |
304 XFA_NODEITEM_NextSibling)) { | |
305 XFA_ProtoMerge_MergeNodeRecurse(pDocument, pExistingNode, pTemplateChild); | |
306 } | |
307 return; | |
308 } | |
309 CXFA_Node* pNewNode = pProtoNode->Clone(TRUE); | |
310 pNewNode->SetTemplateNode(pProtoNode); | |
311 pDestNodeParent->InsertChild(pNewNode, nullptr); | |
312 } | |
313 static void XFA_ProtoMerge_MergeNode(CXFA_Document* pDocument, | |
314 CXFA_Node* pDestNode, | |
315 CXFA_Node* pProtoNode) { | |
316 { | |
317 CXFA_NodeIterator sIterator(pDestNode); | |
318 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode; | |
319 pNode = sIterator.MoveToNext()) { | |
320 pNode->SetFlag(XFA_NodeFlag_UnusedNode, true); | |
321 } | |
322 } | |
323 pDestNode->SetTemplateNode(pProtoNode); | |
324 for (CXFA_Node* pTemplateChild = | |
325 pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
326 pTemplateChild; | |
327 pTemplateChild = pTemplateChild->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
328 XFA_ProtoMerge_MergeNodeRecurse(pDocument, pDestNode, pTemplateChild); | |
329 } | |
330 { | |
331 CXFA_NodeIterator sIterator(pDestNode); | |
332 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode; | |
333 pNode = sIterator.MoveToNext()) { | |
334 pNode->ClearFlag(XFA_NodeFlag_UnusedNode); | |
335 } | |
336 } | |
337 } | |
338 void CXFA_Document::DoProtoMerge() { | |
339 CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(XFA_HASHCODE_Template)); | |
340 if (!pTemplateRoot) { | |
341 return; | |
342 } | |
343 CFX_MapPtrTemplate<uint32_t, CXFA_Node*> mIDMap; | |
344 CXFA_NodeSet sUseNodes; | |
345 CXFA_NodeIterator sIterator(pTemplateRoot); | |
346 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode; | |
347 pNode = sIterator.MoveToNext()) { | |
348 CFX_WideStringC wsIDVal; | |
349 if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) { | |
350 mIDMap[FX_HashCode_GetW(wsIDVal, false)] = pNode; | |
351 } | |
352 CFX_WideStringC wsUseVal; | |
353 if (pNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) && !wsUseVal.IsEmpty()) { | |
354 sUseNodes.insert(pNode); | |
355 } else if (pNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) && | |
356 !wsUseVal.IsEmpty()) { | |
357 sUseNodes.insert(pNode); | |
358 } | |
359 } | |
360 for (CXFA_Node* pUseHrefNode : sUseNodes) { | |
361 CFX_WideString wsUseVal; | |
362 CFX_WideStringC wsURI, wsID, wsSOM; | |
363 if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) && | |
364 !wsUseVal.IsEmpty()) { | |
365 FX_STRSIZE uSharpPos = wsUseVal.Find('#'); | |
366 if (uSharpPos < 0) { | |
367 wsURI = wsUseVal.AsStringC(); | |
368 } else { | |
369 wsURI = CFX_WideStringC(wsUseVal.c_str(), uSharpPos); | |
370 FX_STRSIZE uLen = wsUseVal.GetLength(); | |
371 if (uLen >= uSharpPos + 5 && | |
372 CFX_WideStringC(wsUseVal.c_str() + uSharpPos, 5) == | |
373 FX_WSTRC(L"#som(") && | |
374 wsUseVal[uLen - 1] == ')') { | |
375 wsSOM = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 5, | |
376 uLen - 1 - uSharpPos - 5); | |
377 } else { | |
378 wsID = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 1, | |
379 uLen - uSharpPos - 1); | |
380 } | |
381 } | |
382 } else if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) && | |
383 !wsUseVal.IsEmpty()) { | |
384 if (wsUseVal[0] == '#') { | |
385 wsID = CFX_WideStringC(wsUseVal.c_str() + 1, wsUseVal.GetLength() - 1); | |
386 } else { | |
387 wsSOM = CFX_WideStringC(wsUseVal.c_str(), wsUseVal.GetLength()); | |
388 } | |
389 } | |
390 if (!wsURI.IsEmpty() && wsURI != FX_WSTRC(L".")) { | |
391 continue; | |
392 } | |
393 CXFA_Node* pProtoNode = nullptr; | |
394 if (!wsSOM.IsEmpty()) { | |
395 uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes | | |
396 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent | | |
397 XFA_RESOLVENODE_Siblings; | |
398 XFA_RESOLVENODE_RS resoveNodeRS; | |
399 int32_t iRet = m_pScriptContext->ResolveObjects(pUseHrefNode, wsSOM, | |
400 resoveNodeRS, dwFlag); | |
401 if (iRet > 0 && resoveNodeRS.nodes[0]->IsNode()) { | |
402 pProtoNode = resoveNodeRS.nodes[0]->AsNode(); | |
403 } | |
404 } else if (!wsID.IsEmpty()) { | |
405 if (!mIDMap.Lookup(FX_HashCode_GetW(wsID, false), pProtoNode)) { | |
406 continue; | |
407 } | |
408 } | |
409 if (!pProtoNode) { | |
410 continue; | |
411 } | |
412 XFA_ProtoMerge_MergeNode(this, pUseHrefNode, pProtoNode); | |
413 } | |
414 } | |
OLD | NEW |