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 "xfa/src/fxfa/app/xfa_ffdoc.h" | |
8 | |
9 #include "core/include/fpdfapi/cpdf_array.h" | |
10 #include "core/include/fpdfapi/cpdf_document.h" | |
11 #include "core/include/fpdfdoc/fpdf_doc.h" | |
12 #include "core/include/fxcrt/fx_ext.h" | |
13 #include "xfa/include/fwl/core/fwl_note.h" | |
14 #include "xfa/src/fgas/crt/fgas_algorithm.h" | |
15 #include "xfa/src/fxfa/app/xfa_ffapp.h" | |
16 #include "xfa/src/fxfa/app/xfa_ffdocview.h" | |
17 #include "xfa/src/fxfa/app/xfa_ffnotify.h" | |
18 #include "xfa/src/fxfa/app/xfa_ffwidget.h" | |
19 #include "xfa/src/fxfa/app/xfa_fontmgr.h" | |
20 #include "xfa/src/fxfa/parser/xfa_docdata.h" | |
21 #include "xfa/src/fxfa/parser/xfa_parser.h" | |
22 | |
23 CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocProvider* pDocProvider) | |
24 : m_pDocProvider(pDocProvider), | |
25 m_pDocument(nullptr), | |
26 m_pStream(nullptr), | |
27 m_pApp(pApp), | |
28 m_pNotify(nullptr), | |
29 m_pPDFDoc(nullptr), | |
30 m_dwDocType(XFA_DOCTYPE_Static), | |
31 m_bOwnStream(TRUE) {} | |
32 CXFA_FFDoc::~CXFA_FFDoc() { | |
33 CloseDoc(); | |
34 } | |
35 FX_DWORD CXFA_FFDoc::GetDocType() { | |
36 return m_dwDocType; | |
37 } | |
38 int32_t CXFA_FFDoc::StartLoad() { | |
39 m_pNotify = new CXFA_FFNotify(this); | |
40 IXFA_DocParser* pDocParser = IXFA_DocParser::Create(m_pNotify); | |
41 int32_t iStatus = pDocParser->StartParse(m_pStream); | |
42 m_pDocument = pDocParser->GetDocument(); | |
43 return iStatus; | |
44 } | |
45 FX_BOOL XFA_GetPDFContentsFromPDFXML(IFDE_XMLNode* pPDFElement, | |
46 uint8_t*& pByteBuffer, | |
47 int32_t& iBufferSize) { | |
48 IFDE_XMLElement* pDocumentElement = NULL; | |
49 for (IFDE_XMLNode* pXMLNode = | |
50 pPDFElement->GetNodeItem(IFDE_XMLNode::FirstChild); | |
51 pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
52 if (pXMLNode->GetType() == FDE_XMLNODE_Element) { | |
53 CFX_WideString wsTagName; | |
54 IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode; | |
55 pXMLElement->GetTagName(wsTagName); | |
56 if (wsTagName.Equal(FX_WSTRC(L"document"))) { | |
57 pDocumentElement = pXMLElement; | |
58 break; | |
59 } | |
60 } | |
61 } | |
62 if (!pDocumentElement) { | |
63 return FALSE; | |
64 } | |
65 IFDE_XMLElement* pChunkElement = NULL; | |
66 for (IFDE_XMLNode* pXMLNode = | |
67 pDocumentElement->GetNodeItem(IFDE_XMLNode::FirstChild); | |
68 pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
69 if (pXMLNode->GetType() == FDE_XMLNODE_Element) { | |
70 CFX_WideString wsTagName; | |
71 IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode; | |
72 pXMLElement->GetTagName(wsTagName); | |
73 if (wsTagName.Equal(FX_WSTRC(L"chunk"))) { | |
74 pChunkElement = pXMLElement; | |
75 break; | |
76 } | |
77 } | |
78 } | |
79 if (!pChunkElement) { | |
80 return FALSE; | |
81 } | |
82 CFX_WideString wsPDFContent; | |
83 pChunkElement->GetTextData(wsPDFContent); | |
84 iBufferSize = FX_Base64DecodeW(wsPDFContent, wsPDFContent.GetLength(), NULL); | |
85 pByteBuffer = FX_Alloc(uint8_t, iBufferSize + 1); | |
86 pByteBuffer[iBufferSize] = '0'; // FIXME: I bet this is wrong. | |
87 FX_Base64DecodeW(wsPDFContent, wsPDFContent.GetLength(), pByteBuffer); | |
88 return TRUE; | |
89 } | |
90 void XFA_XPDPacket_MergeRootNode(CXFA_Node* pOriginRoot, CXFA_Node* pNewRoot) { | |
91 CXFA_Node* pChildNode = pNewRoot->GetNodeItem(XFA_NODEITEM_FirstChild); | |
92 while (pChildNode) { | |
93 CXFA_Node* pOriginChild = | |
94 pOriginRoot->GetFirstChildByName(pChildNode->GetNameHash()); | |
95 if (pOriginChild) { | |
96 pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling); | |
97 } else { | |
98 CXFA_Node* pNextSibling = | |
99 pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling); | |
100 pNewRoot->RemoveChild(pChildNode); | |
101 pOriginRoot->InsertChild(pChildNode); | |
102 pChildNode = pNextSibling; | |
103 pNextSibling = NULL; | |
104 } | |
105 } | |
106 } | |
107 int32_t CXFA_FFDoc::DoLoad(IFX_Pause* pPause) { | |
108 int32_t iStatus = m_pDocument->GetParser()->DoParse(pPause); | |
109 if (iStatus == XFA_PARSESTATUS_Done && !m_pPDFDoc) { | |
110 CXFA_Node* pPDFNode = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Pdf)); | |
111 if (!pPDFNode) { | |
112 return XFA_PARSESTATUS_SyntaxErr; | |
113 } | |
114 IFDE_XMLNode* pPDFXML = pPDFNode->GetXMLMappingNode(); | |
115 if (pPDFXML->GetType() != FDE_XMLNODE_Element) { | |
116 return XFA_PARSESTATUS_SyntaxErr; | |
117 } | |
118 int32_t iBufferSize = 0; | |
119 uint8_t* pByteBuffer = NULL; | |
120 IFX_FileRead* pXFAReader = NULL; | |
121 if (XFA_GetPDFContentsFromPDFXML(pPDFXML, pByteBuffer, iBufferSize)) { | |
122 pXFAReader = FX_CreateMemoryStream(pByteBuffer, iBufferSize, TRUE); | |
123 } else { | |
124 CFX_WideString wsHref; | |
125 ((IFDE_XMLElement*)pPDFXML)->GetString(L"href", wsHref); | |
126 if (!wsHref.IsEmpty()) { | |
127 pXFAReader = GetDocProvider()->OpenLinkedFile(this, wsHref); | |
128 } | |
129 } | |
130 if (!pXFAReader) { | |
131 return XFA_PARSESTATUS_SyntaxErr; | |
132 } | |
133 CPDF_Document* pPDFDocument = | |
134 GetDocProvider()->OpenPDF(this, pXFAReader, TRUE); | |
135 FXSYS_assert(!m_pPDFDoc); | |
136 if (!OpenDoc(pPDFDocument)) { | |
137 return XFA_PARSESTATUS_SyntaxErr; | |
138 } | |
139 IXFA_Parser* pParser = IXFA_Parser::Create(m_pDocument, TRUE); | |
140 if (!pParser) { | |
141 return XFA_PARSESTATUS_SyntaxErr; | |
142 } | |
143 CXFA_Node* pRootNode = NULL; | |
144 if (pParser->StartParse(m_pStream) == XFA_PARSESTATUS_Ready && | |
145 pParser->DoParse(NULL) == XFA_PARSESTATUS_Done) { | |
146 pRootNode = pParser->GetRootNode(); | |
147 } | |
148 if (pRootNode && m_pDocument->GetRoot()) { | |
149 XFA_XPDPacket_MergeRootNode(m_pDocument->GetRoot(), pRootNode); | |
150 iStatus = XFA_PARSESTATUS_Done; | |
151 } else { | |
152 iStatus = XFA_PARSESTATUS_StatusErr; | |
153 } | |
154 pParser->Release(); | |
155 pParser = NULL; | |
156 } | |
157 return iStatus; | |
158 } | |
159 void CXFA_FFDoc::StopLoad() { | |
160 m_pApp->GetXFAFontMgr()->LoadDocFonts(this); | |
161 m_dwDocType = XFA_DOCTYPE_Static; | |
162 CXFA_Node* pConfig = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config)); | |
163 if (!pConfig) { | |
164 return; | |
165 } | |
166 CXFA_Node* pAcrobat = pConfig->GetFirstChildByClass(XFA_ELEMENT_Acrobat); | |
167 if (!pAcrobat) { | |
168 return; | |
169 } | |
170 CXFA_Node* pAcrobat7 = pAcrobat->GetFirstChildByClass(XFA_ELEMENT_Acrobat7); | |
171 if (!pAcrobat7) { | |
172 return; | |
173 } | |
174 CXFA_Node* pDynamicRender = | |
175 pAcrobat7->GetFirstChildByClass(XFA_ELEMENT_DynamicRender); | |
176 if (!pDynamicRender) { | |
177 return; | |
178 } | |
179 CFX_WideString wsType; | |
180 if (pDynamicRender->TryContent(wsType) && wsType == FX_WSTRC(L"required")) { | |
181 m_dwDocType = XFA_DOCTYPE_Dynamic; | |
182 } | |
183 } | |
184 IXFA_DocView* CXFA_FFDoc::CreateDocView(FX_DWORD dwView) { | |
185 CXFA_FFDocView* pDocView = | |
186 (CXFA_FFDocView*)m_mapTypeToDocView.GetValueAt((void*)(uintptr_t)dwView); | |
187 if (!pDocView) { | |
188 pDocView = new CXFA_FFDocView(this); | |
189 m_mapTypeToDocView.SetAt((void*)(uintptr_t)dwView, pDocView); | |
190 } | |
191 return pDocView; | |
192 } | |
193 CXFA_FFDocView* CXFA_FFDoc::GetDocView(IXFA_DocLayout* pLayout) { | |
194 FX_POSITION ps = m_mapTypeToDocView.GetStartPosition(); | |
195 while (ps) { | |
196 void* pType; | |
197 CXFA_FFDocView* pDocView; | |
198 m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView); | |
199 if (pDocView->GetXFALayout() == pLayout) { | |
200 return pDocView; | |
201 } | |
202 } | |
203 return NULL; | |
204 } | |
205 CXFA_FFDocView* CXFA_FFDoc::GetDocView() { | |
206 FX_POSITION ps = m_mapTypeToDocView.GetStartPosition(); | |
207 if (ps) { | |
208 void* pType; | |
209 CXFA_FFDocView* pDocView; | |
210 m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView); | |
211 return pDocView; | |
212 } | |
213 return NULL; | |
214 } | |
215 FX_BOOL CXFA_FFDoc::OpenDoc(IFX_FileRead* pStream, FX_BOOL bTakeOverFile) { | |
216 m_bOwnStream = bTakeOverFile; | |
217 m_pStream = pStream; | |
218 return TRUE; | |
219 } | |
220 FX_BOOL CXFA_FFDoc::OpenDoc(CPDF_Document* pPDFDoc) { | |
221 if (pPDFDoc == NULL) { | |
222 return FALSE; | |
223 } | |
224 CPDF_Dictionary* pRoot = pPDFDoc->GetRoot(); | |
225 if (pRoot == NULL) { | |
226 return FALSE; | |
227 } | |
228 CPDF_Dictionary* pAcroForm = pRoot->GetDictBy("AcroForm"); | |
229 if (pAcroForm == NULL) { | |
230 return FALSE; | |
231 } | |
232 CPDF_Object* pElementXFA = pAcroForm->GetElementValue("XFA"); | |
233 if (pElementXFA == NULL) { | |
234 return FALSE; | |
235 } | |
236 CFX_ArrayTemplate<CPDF_Stream*> xfaStreams; | |
237 if (pElementXFA->IsArray()) { | |
238 CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA; | |
239 FX_DWORD count = pXFAArray->GetCount() / 2; | |
240 for (FX_DWORD i = 0; i < count; i++) { | |
241 if (CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1)) | |
242 xfaStreams.Add(pStream); | |
243 } | |
244 } else if (pElementXFA->IsStream()) { | |
245 xfaStreams.Add((CPDF_Stream*)pElementXFA); | |
246 } | |
247 if (xfaStreams.GetSize() < 1) { | |
248 return FALSE; | |
249 } | |
250 IFX_FileRead* pFileRead = new CXFA_FileRead(xfaStreams); | |
251 m_pPDFDoc = pPDFDoc; | |
252 if (m_pStream) { | |
253 m_pStream->Release(); | |
254 m_pStream = NULL; | |
255 } | |
256 m_pStream = pFileRead; | |
257 m_bOwnStream = TRUE; | |
258 return TRUE; | |
259 } | |
260 FX_BOOL CXFA_FFDoc::CloseDoc() { | |
261 FX_POSITION psClose = m_mapTypeToDocView.GetStartPosition(); | |
262 while (psClose) { | |
263 void* pType; | |
264 CXFA_FFDocView* pDocView; | |
265 m_mapTypeToDocView.GetNextAssoc(psClose, pType, (void*&)pDocView); | |
266 pDocView->RunDocClose(); | |
267 } | |
268 if (m_pDocument) { | |
269 m_pDocument->ClearLayoutData(); | |
270 } | |
271 FX_POSITION ps = m_mapTypeToDocView.GetStartPosition(); | |
272 while (ps) { | |
273 void* pType; | |
274 CXFA_FFDocView* pDocView; | |
275 m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView); | |
276 delete pDocView; | |
277 } | |
278 m_mapTypeToDocView.RemoveAll(); | |
279 if (m_pDocument) { | |
280 IXFA_Parser* pParser = m_pDocument->GetParser(); | |
281 pParser->Release(); | |
282 m_pDocument = NULL; | |
283 } | |
284 if (m_pNotify) { | |
285 delete m_pNotify; | |
286 m_pNotify = NULL; | |
287 } | |
288 m_pApp->GetXFAFontMgr()->ReleaseDocFonts(this); | |
289 if (m_dwDocType != XFA_DOCTYPE_XDP && m_pStream && m_bOwnStream) { | |
290 m_pStream->Release(); | |
291 m_pStream = NULL; | |
292 } | |
293 ps = m_mapNamedImages.GetStartPosition(); | |
294 while (ps) { | |
295 void* pName; | |
296 FX_IMAGEDIB_AND_DPI* pImage = NULL; | |
297 m_mapNamedImages.GetNextAssoc(ps, pName, (void*&)pImage); | |
298 if (pImage) { | |
299 delete pImage->pDibSource; | |
300 pImage->pDibSource = NULL; | |
301 FX_Free(pImage); | |
302 pImage = NULL; | |
303 } | |
304 } | |
305 m_mapNamedImages.RemoveAll(); | |
306 IFWL_NoteDriver* pNoteDriver = FWL_GetApp()->GetNoteDriver(); | |
307 pNoteDriver->ClearEventTargets(FALSE); | |
308 return TRUE; | |
309 } | |
310 void CXFA_FFDoc::SetDocType(FX_DWORD dwType) { | |
311 m_dwDocType = dwType; | |
312 } | |
313 CPDF_Document* CXFA_FFDoc::GetPDFDoc() { | |
314 return m_pPDFDoc; | |
315 } | |
316 | |
317 CFX_DIBitmap* CXFA_FFDoc::GetPDFNamedImage(const CFX_WideStringC& wsName, | |
318 int32_t& iImageXDpi, | |
319 int32_t& iImageYDpi) { | |
320 if (!m_pPDFDoc) | |
321 return nullptr; | |
322 | |
323 FX_DWORD dwHash = | |
324 FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), FALSE); | |
325 FX_IMAGEDIB_AND_DPI* imageDIBDpi = nullptr; | |
326 if (m_mapNamedImages.Lookup((void*)(uintptr_t)dwHash, (void*&)imageDIBDpi)) { | |
327 iImageXDpi = imageDIBDpi->iImageXDpi; | |
328 iImageYDpi = imageDIBDpi->iImageYDpi; | |
329 return static_cast<CFX_DIBitmap*>(imageDIBDpi->pDibSource); | |
330 } | |
331 | |
332 CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot(); | |
333 if (!pRoot) | |
334 return nullptr; | |
335 | |
336 CPDF_Dictionary* pNames = pRoot->GetDictBy("Names"); | |
337 if (!pNames) | |
338 return nullptr; | |
339 | |
340 CPDF_Dictionary* pXFAImages = pNames->GetDictBy("XFAImages"); | |
341 if (!pXFAImages) | |
342 return nullptr; | |
343 | |
344 CPDF_NameTree nametree(pXFAImages); | |
345 CFX_ByteString bsName = PDF_EncodeText(wsName.GetPtr(), wsName.GetLength()); | |
346 CPDF_Object* pObject = nametree.LookupValue(bsName); | |
347 if (!pObject) { | |
348 int32_t iCount = nametree.GetCount(); | |
349 for (int32_t i = 0; i < iCount; i++) { | |
350 CFX_ByteString bsTemp; | |
351 CPDF_Object* pTempObject = nametree.LookupValue(i, bsTemp); | |
352 if (bsTemp == bsName) { | |
353 pObject = pTempObject; | |
354 break; | |
355 } | |
356 } | |
357 } | |
358 | |
359 if (!pObject || !pObject->IsStream()) | |
360 return nullptr; | |
361 | |
362 if (!imageDIBDpi) { | |
363 imageDIBDpi = FX_Alloc(FX_IMAGEDIB_AND_DPI, 1); | |
364 imageDIBDpi->pDibSource = nullptr; | |
365 imageDIBDpi->iImageXDpi = 0; | |
366 imageDIBDpi->iImageYDpi = 0; | |
367 CPDF_StreamAcc streamAcc; | |
368 streamAcc.LoadAllData((CPDF_Stream*)pObject); | |
369 IFX_FileRead* pImageFileRead = FX_CreateMemoryStream( | |
370 (uint8_t*)streamAcc.GetData(), streamAcc.GetSize()); | |
371 imageDIBDpi->pDibSource = XFA_LoadImageFromBuffer( | |
372 pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi); | |
373 imageDIBDpi->iImageXDpi = iImageXDpi; | |
374 imageDIBDpi->iImageYDpi = iImageYDpi; | |
375 pImageFileRead->Release(); | |
376 } | |
377 m_mapNamedImages.SetAt((void*)(uintptr_t)dwHash, imageDIBDpi); | |
378 return (CFX_DIBitmap*)imageDIBDpi->pDibSource; | |
379 } | |
380 | |
381 IFDE_XMLElement* CXFA_FFDoc::GetPackageData(const CFX_WideStringC& wsPackage) { | |
382 FX_DWORD packetHash = | |
383 FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength()); | |
384 CXFA_Node* pNode = ToNode(m_pDocument->GetXFAObject(packetHash)); | |
385 if (!pNode) { | |
386 return NULL; | |
387 } | |
388 IFDE_XMLNode* pXMLNode = pNode->GetXMLMappingNode(); | |
389 return (pXMLNode && pXMLNode->GetType() == FDE_XMLNODE_Element) | |
390 ? (IFDE_XMLElement*)pXMLNode | |
391 : NULL; | |
392 } | |
393 FX_BOOL CXFA_FFDoc::SavePackage(const CFX_WideStringC& wsPackage, | |
394 IFX_FileWrite* pFile, | |
395 IXFA_ChecksumContext* pCSContext) { | |
396 IXFA_PacketExport* pExport = IXFA_PacketExport::Create(m_pDocument); | |
397 if (!pExport) { | |
398 return FALSE; | |
399 } | |
400 FX_DWORD packetHash = | |
401 FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength()); | |
402 CXFA_Node* pNode = NULL; | |
403 if (packetHash == XFA_HASHCODE_Xfa) { | |
404 pNode = m_pDocument->GetRoot(); | |
405 } else { | |
406 pNode = ToNode(m_pDocument->GetXFAObject(packetHash)); | |
407 } | |
408 FX_BOOL bFlags = FALSE; | |
409 if (pNode) { | |
410 CFX_ByteString bsChecksum; | |
411 if (pCSContext) { | |
412 pCSContext->GetChecksum(bsChecksum); | |
413 } | |
414 bFlags = pExport->Export(pFile, pNode, 0, bsChecksum.GetLength() | |
415 ? (const FX_CHAR*)bsChecksum | |
416 : NULL); | |
417 } else { | |
418 bFlags = pExport->Export(pFile); | |
419 } | |
420 pExport->Release(); | |
421 return bFlags; | |
422 } | |
423 FX_BOOL CXFA_FFDoc::ImportData(IFX_FileRead* pStream, FX_BOOL bXDP) { | |
424 FX_BOOL bRet = FALSE; | |
425 IXFA_PacketImport* pImport = IXFA_PacketImport::Create(m_pDocument); | |
426 if (pImport) { | |
427 bRet = pImport->ImportData(pStream); | |
428 pImport->Release(); | |
429 } | |
430 return bRet; | |
431 } | |
OLD | NEW |