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