Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[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 FX_INT32 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     FX_INT32 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, FX_INT32& 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(FX_BYTE, 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 FX_INT32 CXFA_FFDoc::DoLoad(IFX_Pause *pPause )\r
102 {\r
103     FX_INT32 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         FX_INT32 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((FX_LPCWSTR)L"href", wsHref);\r
128             if (!wsHref.IsEmpty()) {\r
129                 pXFAReader = GetDocProvider()->OpenLinkedFile((XFA_HDOC)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(reinterpret_cast<XFA_HDOC>(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((XFA_HDOC)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)(FX_UINTPTR)dwView);\r
187     if (!pDocView) {\r
188         pDocView = FX_NEW CXFA_FFDocView(this);\r
189         m_mapTypeToDocView.SetAt((FX_LPVOID)(FX_UINTPTR)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->GetElement(FX_BSTRC("XFA"));\r
237     if (pElementXFA == NULL) {\r
238         return FALSE;\r
239     }\r
240     FX_INT32 iObjType = pElementXFA->GetType();\r
241     if (iObjType == PDFOBJ_REFERENCE) {\r
242         pElementXFA = pElementXFA->GetDirect();\r
243         iObjType = pElementXFA->GetType();\r
244     }\r
245     CFX_ArrayTemplate<CPDF_Stream*> xfaStreams;\r
246     if (iObjType == PDFOBJ_ARRAY) {\r
247         CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA;\r
248         FX_DWORD count = pXFAArray->GetCount() / 2;\r
249         for (FX_DWORD i = 0; i < count; i++) {\r
250             CPDF_Stream* pStream = pXFAArray->GetStream(i * 2 + 1);\r
251             if (pStream != NULL) {\r
252                 xfaStreams.Add(pStream);\r
253             }\r
254         }\r
255     } else if (iObjType == PDFOBJ_STREAM) {\r
256         xfaStreams.Add((CPDF_Stream*)pElementXFA);\r
257     }\r
258     if (xfaStreams.GetSize() < 1) {\r
259         return FALSE;\r
260     }\r
261     IFX_FileRead* pFileRead = FX_NEW CXFA_FileRead2(xfaStreams);\r
262     if (!pFileRead) {\r
263         return FALSE;\r
264     }\r
265     m_pPDFDoc = pPDFDoc;\r
266     if (m_pStream) {\r
267         m_pStream->Release();\r
268         m_pStream = NULL;\r
269     }\r
270     m_pStream = pFileRead;\r
271     m_bOwnStream = TRUE;\r
272     return TRUE;\r
273 }\r
274 FX_BOOL CXFA_FFDoc::CloseDoc()\r
275 {\r
276     FX_POSITION psClose = m_mapTypeToDocView.GetStartPosition();\r
277     while (psClose) {\r
278         FX_LPVOID pType;\r
279         CXFA_FFDocView* pDocView;\r
280         m_mapTypeToDocView.GetNextAssoc(psClose, pType, (void*&)pDocView);\r
281         pDocView->RunDocClose();\r
282     }\r
283     if (m_pDocument) {\r
284         m_pDocument->ClearLayoutData();\r
285     }\r
286     FX_POSITION ps = m_mapTypeToDocView.GetStartPosition();\r
287     while (ps) {\r
288         FX_LPVOID pType;\r
289         CXFA_FFDocView* pDocView;\r
290         m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView);\r
291         delete pDocView;\r
292     }\r
293     m_mapTypeToDocView.RemoveAll();\r
294     if (m_pDocument) {\r
295         IXFA_Parser* pParser = m_pDocument->GetParser();\r
296         pParser->Release();\r
297         m_pDocument = NULL;\r
298     }\r
299     if (m_pNotify) {\r
300         delete m_pNotify;\r
301         m_pNotify = NULL;\r
302     }\r
303     m_pApp->GetXFAFontMgr()->ReleaseDocFonts((XFA_HDOC)this);\r
304     if (m_dwDocType != XFA_DOCTYPE_XDP && m_pStream && m_bOwnStream) {\r
305         m_pStream->Release();\r
306         m_pStream = NULL;\r
307     }\r
308     ps = m_mapNamedImages.GetStartPosition();\r
309     while (ps) {\r
310         FX_LPVOID pName;\r
311         FX_IMAGEDIB_AND_DPI* pImage = NULL;\r
312         m_mapNamedImages.GetNextAssoc(ps, pName, (void*&)pImage);\r
313         if (pImage) {\r
314             delete pImage->pDibSource;\r
315             pImage->pDibSource = NULL;\r
316             FX_Free(pImage);\r
317             pImage = NULL;\r
318         }\r
319     }\r
320     m_mapNamedImages.RemoveAll();\r
321     IFWL_NoteDriver *pNoteDriver = FWL_GetApp()->GetNoteDriver();\r
322     pNoteDriver->ClearEventTargets(FALSE);\r
323     return TRUE;\r
324 }\r
325 void CXFA_FFDoc::SetDocType(FX_DWORD dwType)\r
326 {\r
327     m_dwDocType = dwType;\r
328 }\r
329 CPDF_Document* CXFA_FFDoc::GetPDFDoc()\r
330 {\r
331     return m_pPDFDoc;\r
332 }\r
333 #define _FXLIB_NEW_VERSION_\r
334 CFX_DIBitmap* CXFA_FFDoc::GetPDFNamedImage(FX_WSTR wsName, FX_INT32 &iImageXDpi, FX_INT32 &iImageYDpi)\r
335 {\r
336     if (!m_pPDFDoc) {\r
337         return NULL;\r
338     }\r
339     FX_DWORD dwHash = FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), FALSE);\r
340     FX_IMAGEDIB_AND_DPI *imageDIBDpi = NULL;\r
341     if (m_mapNamedImages.Lookup((void*)(FX_UINTPTR)dwHash, (void*&)imageDIBDpi)) {\r
342         iImageXDpi = imageDIBDpi->iImageXDpi;\r
343         iImageYDpi = imageDIBDpi->iImageYDpi;\r
344         return (CFX_DIBitmap*)imageDIBDpi->pDibSource;\r
345     }\r
346     CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot();\r
347     if (pRoot == NULL) {\r
348         return NULL;\r
349     }\r
350     CPDF_Dictionary* pNames = pRoot->GetDict("Names");\r
351     if (!pNames) {\r
352         return NULL;\r
353     }\r
354     CPDF_Dictionary* pXFAImages = pNames->GetDict("XFAImages");\r
355     if (!pXFAImages) {\r
356         return NULL;\r
357     }\r
358     CPDF_NameTree nametree(pXFAImages);\r
359 #ifdef _FXLIB_NEW_VERSION_\r
360     CFX_ByteString bsName = PDF_EncodeText(wsName.GetPtr(), wsName.GetLength());\r
361     CPDF_Object* pObject = nametree.LookupValue(bsName);\r
362     if (!pObject) {\r
363         FX_INT32 iCount = nametree.GetCount();\r
364         for (FX_INT32 i = 0; i < iCount; i++) {\r
365             CFX_ByteString bsTemp;\r
366             CPDF_Object* pTempObject = nametree.LookupValue(i, bsTemp);\r
367             if (bsTemp == bsName) {\r
368                 pObject = pTempObject;\r
369                 break;\r
370             }\r
371         }\r
372     }\r
373 #else\r
374     CPDF_Object* pObject = nametree.LookupValue(wsName);\r
375     if (!pObject) {\r
376         FX_INT32 iCount = nametree.GetCount();\r
377         for (FX_INT32 i = 0; i < iCount; i++) {\r
378             CFX_WideString wsTemp;\r
379             CPDF_Object* pTempObject = nametree.LookupValue(i, wsTemp);\r
380             if (wsTemp == wsName) {\r
381                 pObject = pTempObject;\r
382                 break;\r
383             }\r
384         }\r
385     }\r
386 #endif\r
387     if (!pObject || pObject->GetType() != PDFOBJ_STREAM) {\r
388         return NULL;\r
389     }\r
390     if (!imageDIBDpi) {\r
391         imageDIBDpi = FX_Alloc(FX_IMAGEDIB_AND_DPI, 1);\r
392         imageDIBDpi->pDibSource = NULL;\r
393         imageDIBDpi->iImageXDpi = 0;\r
394         imageDIBDpi->iImageYDpi = 0;\r
395         CPDF_StreamAcc streamAcc;\r
396         streamAcc.LoadAllData((CPDF_Stream*)pObject);\r
397         IFX_FileRead* pImageFileRead = FX_CreateMemoryStream((FX_LPBYTE)streamAcc.GetData(), streamAcc.GetSize());\r
398         imageDIBDpi->pDibSource = XFA_LoadImageFromBuffer(pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi);\r
399         imageDIBDpi->iImageXDpi = iImageXDpi;\r
400         imageDIBDpi->iImageYDpi = iImageYDpi;\r
401         pImageFileRead->Release();\r
402     }\r
403     m_mapNamedImages.SetAt((void*)(FX_UINTPTR)dwHash, imageDIBDpi);\r
404     return (CFX_DIBitmap*)imageDIBDpi->pDibSource;\r
405 }\r
406 IFDE_XMLElement* CXFA_FFDoc::GetPackageData(FX_WSTR wsPackage)\r
407 {\r
408     FX_DWORD packetHash = FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength());\r
409     CXFA_Object* pObject = m_pDocument->GetXFANode(packetHash);\r
410     CXFA_Node *pNode = (pObject && pObject->IsNode()) ? (CXFA_Node*)pObject : NULL;\r
411     if (!pNode) {\r
412         return NULL;\r
413     }\r
414     IFDE_XMLNode *pXMLNode = pNode->GetXMLMappingNode();\r
415     return (pXMLNode && pXMLNode->GetType() == FDE_XMLNODE_Element) ? (IFDE_XMLElement *)pXMLNode : NULL;\r
416 }\r
417 FX_BOOL CXFA_FFDoc::SavePackage(FX_WSTR wsPackage, IFX_FileWrite* pFile, IXFA_ChecksumContext *pCSContext )\r
418 {\r
419     IXFA_PacketExport *pExport = IXFA_PacketExport::Create(m_pDocument);\r
420     if (!pExport) {\r
421         return FALSE;\r
422     }\r
423     FX_DWORD packetHash = FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength());\r
424     CXFA_Node *pNode = NULL;\r
425     if (packetHash == XFA_HASHCODE_Xfa) {\r
426         pNode = m_pDocument->GetRoot();\r
427     } else {\r
428         CXFA_Object *pObject = m_pDocument->GetXFANode(packetHash);\r
429         pNode = (pObject && pObject->IsNode()) ? (CXFA_Node*)pObject : NULL;\r
430     }\r
431     FX_BOOL bFlags = FALSE;\r
432     if (pNode) {\r
433         CFX_ByteString bsChecksum;\r
434         if (pCSContext) {\r
435             pCSContext->GetChecksum(bsChecksum);\r
436         }\r
437         bFlags = pExport->Export(pFile, pNode, 0, bsChecksum.GetLength() ? (FX_LPCSTR)bsChecksum : NULL);\r
438     } else {\r
439         bFlags = pExport->Export(pFile);\r
440     }\r
441     pExport->Release();\r
442     return bFlags;\r
443 }\r
444 FX_BOOL CXFA_FFDoc::ImportData(IFX_FileRead* pStream, FX_BOOL bXDP )\r
445 {\r
446     FX_BOOL bRet = FALSE;\r
447     IXFA_PacketImport *pImport = IXFA_PacketImport::Create(m_pDocument);\r
448     if (pImport) {\r
449         bRet = pImport->ImportData(pStream);\r
450         pImport->Release();\r
451     }\r
452     return bRet;\r
453 }\r