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/include/fxcrt/fx_ext.h" | |
8 #include "xfa/src/fxfa/fm2js/xfa_fm2jsapi.h" | |
9 #include "xfa/src/fxfa/parser/xfa_basic_imp.h" | |
10 #include "xfa/src/fxfa/parser/xfa_docdata.h" | |
11 #include "xfa/src/fxfa/parser/xfa_doclayout.h" | |
12 #include "xfa/src/fxfa/parser/xfa_document.h" | |
13 #include "xfa/src/fxfa/parser/xfa_document_layout_imp.h" | |
14 #include "xfa/src/fxfa/parser/xfa_localemgr.h" | |
15 #include "xfa/src/fxfa/parser/xfa_object.h" | |
16 #include "xfa/src/fxfa/parser/xfa_parser.h" | |
17 #include "xfa/src/fxfa/parser/xfa_script.h" | |
18 #include "xfa/src/fxfa/parser/xfa_script_datawindow.h" | |
19 #include "xfa/src/fxfa/parser/xfa_script_eventpseudomodel.h" | |
20 #include "xfa/src/fxfa/parser/xfa_script_hostpseudomodel.h" | |
21 #include "xfa/src/fxfa/parser/xfa_script_layoutpseudomodel.h" | |
22 #include "xfa/src/fxfa/parser/xfa_script_logpseudomodel.h" | |
23 #include "xfa/src/fxfa/parser/xfa_script_signaturepseudomodel.h" | |
24 #include "xfa/src/fxfa/parser/xfa_utils.h" | |
25 | |
26 CXFA_Document::CXFA_Document(IXFA_DocParser* pParser) | |
27 : m_pParser(pParser), | |
28 m_pScriptContext(nullptr), | |
29 m_pLayoutProcessor(nullptr), | |
30 m_pRootNode(nullptr), | |
31 m_pLocalMgr(nullptr), | |
32 m_pScriptDataWindow(nullptr), | |
33 m_pScriptEvent(nullptr), | |
34 m_pScriptHost(nullptr), | |
35 m_pScriptLog(nullptr), | |
36 m_pScriptLayout(nullptr), | |
37 m_pScriptSignature(nullptr), | |
38 m_eCurVersionMode(XFA_VERSION_DEFAULT), | |
39 m_dwDocFlags(0) { | |
40 ASSERT(m_pParser); | |
41 } | |
42 CXFA_Document::~CXFA_Document() { | |
43 delete m_pRootNode; | |
44 PurgeNodes(); | |
45 } | |
46 void CXFA_Document::ClearLayoutData() { | |
47 if (m_pLayoutProcessor) { | |
48 delete m_pLayoutProcessor; | |
49 m_pLayoutProcessor = NULL; | |
50 } | |
51 if (m_pScriptContext) { | |
52 m_pScriptContext->Release(); | |
53 m_pScriptContext = NULL; | |
54 } | |
55 if (m_pLocalMgr) { | |
56 delete m_pLocalMgr; | |
57 m_pLocalMgr = NULL; | |
58 } | |
59 if (m_pScriptDataWindow) { | |
60 delete m_pScriptDataWindow; | |
61 m_pScriptDataWindow = NULL; | |
62 } | |
63 if (m_pScriptEvent) { | |
64 delete m_pScriptEvent; | |
65 m_pScriptEvent = NULL; | |
66 } | |
67 if (m_pScriptHost) { | |
68 delete m_pScriptHost; | |
69 m_pScriptHost = NULL; | |
70 } | |
71 if (m_pScriptLog) { | |
72 delete m_pScriptLog; | |
73 m_pScriptLog = NULL; | |
74 } | |
75 if (m_pScriptLayout) { | |
76 delete m_pScriptLayout; | |
77 m_pScriptLayout = NULL; | |
78 } | |
79 if (m_pScriptSignature) { | |
80 delete m_pScriptSignature; | |
81 m_pScriptSignature = NULL; | |
82 } | |
83 } | |
84 void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) { | |
85 if (m_pRootNode) { | |
86 AddPurgeNode(m_pRootNode); | |
87 } | |
88 m_pRootNode = pNewRoot; | |
89 RemovePurgeNode(pNewRoot); | |
90 } | |
91 IXFA_Notify* CXFA_Document::GetNotify() const { | |
92 return m_pParser->GetNotify(); | |
93 } | |
94 CXFA_Object* CXFA_Document::GetXFAObject(const CFX_WideStringC& wsNodeName) { | |
95 return GetXFAObject( | |
96 FX_HashCode_String_GetW(wsNodeName.GetPtr(), wsNodeName.GetLength())); | |
97 } | |
98 CXFA_Object* CXFA_Document::GetXFAObject(FX_DWORD dwNodeNameHash) { | |
99 switch (dwNodeNameHash) { | |
100 case XFA_HASHCODE_Data: { | |
101 CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets)); | |
102 if (!pDatasetsNode) { | |
103 return NULL; | |
104 } | |
105 for (CXFA_Node* pDatasetsChild = | |
106 pDatasetsNode->GetFirstChildByClass(XFA_ELEMENT_DataGroup); | |
107 pDatasetsChild; | |
108 pDatasetsChild = | |
109 pDatasetsChild->GetNextSameClassSibling(XFA_ELEMENT_DataGroup)) { | |
110 if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data) { | |
111 continue; | |
112 } | |
113 CFX_WideString wsNamespaceURI; | |
114 if (!pDatasetsChild->TryNamespace(wsNamespaceURI)) { | |
115 continue; | |
116 } | |
117 CFX_WideString wsDatasetsURI; | |
118 if (!pDatasetsNode->TryNamespace(wsDatasetsURI)) { | |
119 continue; | |
120 } | |
121 if (wsNamespaceURI == wsDatasetsURI) { | |
122 return pDatasetsChild; | |
123 } | |
124 } | |
125 } | |
126 return NULL; | |
127 case XFA_HASHCODE_Record: { | |
128 CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data)); | |
129 return pData ? pData->GetFirstChildByClass(XFA_ELEMENT_DataGroup) : NULL; | |
130 } | |
131 case XFA_HASHCODE_DataWindow: { | |
132 if (m_pScriptDataWindow == NULL) { | |
133 m_pScriptDataWindow = new CScript_DataWindow(this); | |
134 } | |
135 return m_pScriptDataWindow; | |
136 } | |
137 case XFA_HASHCODE_Event: { | |
138 if (m_pScriptEvent == NULL) { | |
139 m_pScriptEvent = new CScript_EventPseudoModel(this); | |
140 } | |
141 return m_pScriptEvent; | |
142 } | |
143 case XFA_HASHCODE_Host: { | |
144 if (m_pScriptHost == NULL) { | |
145 m_pScriptHost = new CScript_HostPseudoModel(this); | |
146 } | |
147 return m_pScriptHost; | |
148 } | |
149 case XFA_HASHCODE_Log: { | |
150 if (m_pScriptLog == NULL) { | |
151 m_pScriptLog = new CScript_LogPseudoModel(this); | |
152 } | |
153 return m_pScriptLog; | |
154 } | |
155 case XFA_HASHCODE_Signature: { | |
156 if (m_pScriptSignature == NULL) { | |
157 m_pScriptSignature = new CScript_SignaturePseudoModel(this); | |
158 } | |
159 return m_pScriptSignature; | |
160 } | |
161 case XFA_HASHCODE_Layout: { | |
162 if (m_pScriptLayout == NULL) { | |
163 m_pScriptLayout = new CScript_LayoutPseudoModel(this); | |
164 } | |
165 return m_pScriptLayout; | |
166 } | |
167 default: | |
168 return m_pRootNode->GetFirstChildByName(dwNodeNameHash); | |
169 } | |
170 } | |
171 CXFA_Node* CXFA_Document::CreateNode(FX_DWORD dwPacket, XFA_ELEMENT eElement) { | |
172 return CreateNode(XFA_GetPacketByID(dwPacket), eElement); | |
173 } | |
174 CXFA_Node* CXFA_Document::CreateNode(const XFA_PACKETINFO* pPacket, | |
175 XFA_ELEMENT eElement) { | |
176 if (pPacket == NULL) { | |
177 return NULL; | |
178 } | |
179 const XFA_ELEMENTINFO* 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 } | |
189 void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) { | |
190 m_rgPurgeNodes.Add(pNode); | |
191 } | |
192 FX_BOOL CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) { | |
193 return m_rgPurgeNodes.RemoveKey(pNode); | |
194 } | |
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 } | |
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 } | |
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 = ToNode(GetXFAObject(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 } | |
239 CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() { | |
240 if (!m_pLocalMgr) { | |
241 CFX_WideString wsLanguage; | |
242 GetParser()->GetNotify()->GetAppProvider()->GetLanguage(wsLanguage); | |
243 m_pLocalMgr = new CXFA_LocaleMgr( | |
244 ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)), wsLanguage); | |
245 } | |
246 return m_pLocalMgr; | |
247 } | |
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 } | |
255 IXFA_ScriptContext* CXFA_Document::GetScriptContext() { | |
256 if (!m_pScriptContext) { | |
257 m_pScriptContext = XFA_ScriptContext_Create(this); | |
258 } | |
259 return m_pScriptContext; | |
260 } | |
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 } | |
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 } | |
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 } | |
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 } | |
357 void CXFA_Document::DoProtoMerge() { | |
358 CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(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 = resoveNodeRS.nodes[0]->AsNode(); | |
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 } | |
OLD | NEW |