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/foxitlib.h"
8#include "xfa/src/fxfa/src/common/xfa_common.h"
9#include "xfa_ffapp.h"
10#include "xfa_ffdoc.h"
11#include "xfa_ffdocview.h"
12#include "xfa_ffwidget.h"
13#include "xfa_ffnotify.h"
14#include "xfa_fontmgr.h"
15CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocProvider* pDocProvider)
16    : m_pDocProvider(pDocProvider),
17      m_pDocument(nullptr),
18      m_pStream(nullptr),
19      m_pApp(pApp),
20      m_pNotify(nullptr),
21      m_pPDFDoc(nullptr),
22      m_dwDocType(XFA_DOCTYPE_Static),
23      m_bOwnStream(TRUE) {
24}
25CXFA_FFDoc::~CXFA_FFDoc() {
26  CloseDoc();
27}
28FX_DWORD CXFA_FFDoc::GetDocType() {
29  return m_dwDocType;
30}
31int32_t CXFA_FFDoc::StartLoad() {
32  m_pNotify = new CXFA_FFNotify(this);
33  IXFA_DocParser* pDocParser = IXFA_DocParser::Create(m_pNotify);
34  int32_t iStatus = pDocParser->StartParse(m_pStream);
35  m_pDocument = pDocParser->GetDocument();
36  return iStatus;
37}
38FX_BOOL XFA_GetPDFContentsFromPDFXML(IFDE_XMLNode* pPDFElement,
39                                     uint8_t*& pByteBuffer,
40                                     int32_t& iBufferSize) {
41  IFDE_XMLElement* pDocumentElement = NULL;
42  for (IFDE_XMLNode* pXMLNode =
43           pPDFElement->GetNodeItem(IFDE_XMLNode::FirstChild);
44       pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) {
45    if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
46      CFX_WideString wsTagName;
47      IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode;
48      pXMLElement->GetTagName(wsTagName);
49      if (wsTagName.Equal(FX_WSTRC(L"document"))) {
50        pDocumentElement = pXMLElement;
51        break;
52      }
53    }
54  }
55  if (!pDocumentElement) {
56    return FALSE;
57  }
58  IFDE_XMLElement* pChunkElement = NULL;
59  for (IFDE_XMLNode* pXMLNode =
60           pDocumentElement->GetNodeItem(IFDE_XMLNode::FirstChild);
61       pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) {
62    if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
63      CFX_WideString wsTagName;
64      IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode;
65      pXMLElement->GetTagName(wsTagName);
66      if (wsTagName.Equal(FX_WSTRC(L"chunk"))) {
67        pChunkElement = pXMLElement;
68        break;
69      }
70    }
71  }
72  if (!pChunkElement) {
73    return FALSE;
74  }
75  CFX_WideString wsPDFContent;
76  pChunkElement->GetTextData(wsPDFContent);
77  iBufferSize = FX_Base64DecodeW(wsPDFContent, wsPDFContent.GetLength(), NULL);
78  pByteBuffer = FX_Alloc(uint8_t, iBufferSize + 1);
79  pByteBuffer[iBufferSize] = '0';  // FIXME: I bet this is wrong.
80  FX_Base64DecodeW(wsPDFContent, wsPDFContent.GetLength(), pByteBuffer);
81  return TRUE;
82}
83void XFA_XPDPacket_MergeRootNode(CXFA_Node* pOriginRoot, CXFA_Node* pNewRoot) {
84  CXFA_Node* pChildNode = pNewRoot->GetNodeItem(XFA_NODEITEM_FirstChild);
85  while (pChildNode) {
86    CXFA_Node* pOriginChild =
87        pOriginRoot->GetFirstChildByName(pChildNode->GetNameHash());
88    if (pOriginChild) {
89      pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
90    } else {
91      CXFA_Node* pNextSibling =
92          pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
93      pNewRoot->RemoveChild(pChildNode);
94      pOriginRoot->InsertChild(pChildNode);
95      pChildNode = pNextSibling;
96      pNextSibling = NULL;
97    }
98  }
99}
100int32_t CXFA_FFDoc::DoLoad(IFX_Pause* pPause) {
101  int32_t iStatus = m_pDocument->GetParser()->DoParse(pPause);
102  if (iStatus == XFA_PARSESTATUS_Done && !m_pPDFDoc) {
103    CXFA_Node* pPDFNode = (CXFA_Node*)m_pDocument->GetXFANode(XFA_HASHCODE_Pdf);
104    if (!pPDFNode) {
105      return XFA_PARSESTATUS_SyntaxErr;
106    }
107    IFDE_XMLNode* pPDFXML = pPDFNode->GetXMLMappingNode();
108    if (pPDFXML->GetType() != FDE_XMLNODE_Element) {
109      return XFA_PARSESTATUS_SyntaxErr;
110    }
111    int32_t iBufferSize = 0;
112    uint8_t* pByteBuffer = NULL;
113    IFX_FileRead* pXFAReader = NULL;
114    if (XFA_GetPDFContentsFromPDFXML(pPDFXML, pByteBuffer, iBufferSize)) {
115      pXFAReader = FX_CreateMemoryStream(pByteBuffer, iBufferSize, TRUE);
116      if (!pXFAReader) {
117        if (pByteBuffer) {
118          FX_Free(pByteBuffer);
119          pByteBuffer = NULL;
120        }
121        return XFA_PARSESTATUS_SyntaxErr;
122      }
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}
159void CXFA_FFDoc::StopLoad() {
160  m_pApp->GetXFAFontMgr()->LoadDocFonts(this);
161  m_dwDocType = XFA_DOCTYPE_Static;
162  CXFA_Node* pConfig = (CXFA_Node*)m_pDocument->GetXFANode(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}
184IXFA_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}
193CXFA_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}
205CXFA_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}
215FX_BOOL CXFA_FFDoc::OpenDoc(IFX_FileRead* pStream, FX_BOOL bTakeOverFile) {
216  m_bOwnStream = bTakeOverFile;
217  m_pStream = pStream;
218  return TRUE;
219}
220FX_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->GetDict("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  int32_t iObjType = pElementXFA->GetType();
237  CFX_ArrayTemplate<CPDF_Stream*> xfaStreams;
238  if (iObjType == PDFOBJ_ARRAY) {
239    CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA;
240    FX_DWORD count = pXFAArray->GetCount() / 2;
241    for (FX_DWORD i = 0; i < count; i++) {
242      CPDF_Stream* pStream = pXFAArray->GetStream(i * 2 + 1);
243      if (pStream != NULL) {
244        xfaStreams.Add(pStream);
245      }
246    }
247  } else if (iObjType == PDFOBJ_STREAM) {
248    xfaStreams.Add((CPDF_Stream*)pElementXFA);
249  }
250  if (xfaStreams.GetSize() < 1) {
251    return FALSE;
252  }
253  IFX_FileRead* pFileRead = new CXFA_FileRead(xfaStreams);
254  m_pPDFDoc = pPDFDoc;
255  if (m_pStream) {
256    m_pStream->Release();
257    m_pStream = NULL;
258  }
259  m_pStream = pFileRead;
260  m_bOwnStream = TRUE;
261  return TRUE;
262}
263FX_BOOL CXFA_FFDoc::CloseDoc() {
264  FX_POSITION psClose = m_mapTypeToDocView.GetStartPosition();
265  while (psClose) {
266    void* pType;
267    CXFA_FFDocView* pDocView;
268    m_mapTypeToDocView.GetNextAssoc(psClose, pType, (void*&)pDocView);
269    pDocView->RunDocClose();
270  }
271  if (m_pDocument) {
272    m_pDocument->ClearLayoutData();
273  }
274  FX_POSITION ps = m_mapTypeToDocView.GetStartPosition();
275  while (ps) {
276    void* pType;
277    CXFA_FFDocView* pDocView;
278    m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView);
279    delete pDocView;
280  }
281  m_mapTypeToDocView.RemoveAll();
282  if (m_pDocument) {
283    IXFA_Parser* pParser = m_pDocument->GetParser();
284    pParser->Release();
285    m_pDocument = NULL;
286  }
287  if (m_pNotify) {
288    delete m_pNotify;
289    m_pNotify = NULL;
290  }
291  m_pApp->GetXFAFontMgr()->ReleaseDocFonts(this);
292  if (m_dwDocType != XFA_DOCTYPE_XDP && m_pStream && m_bOwnStream) {
293    m_pStream->Release();
294    m_pStream = NULL;
295  }
296  ps = m_mapNamedImages.GetStartPosition();
297  while (ps) {
298    void* pName;
299    FX_IMAGEDIB_AND_DPI* pImage = NULL;
300    m_mapNamedImages.GetNextAssoc(ps, pName, (void*&)pImage);
301    if (pImage) {
302      delete pImage->pDibSource;
303      pImage->pDibSource = NULL;
304      FX_Free(pImage);
305      pImage = NULL;
306    }
307  }
308  m_mapNamedImages.RemoveAll();
309  IFWL_NoteDriver* pNoteDriver = FWL_GetApp()->GetNoteDriver();
310  pNoteDriver->ClearEventTargets(FALSE);
311  return TRUE;
312}
313void CXFA_FFDoc::SetDocType(FX_DWORD dwType) {
314  m_dwDocType = dwType;
315}
316CPDF_Document* CXFA_FFDoc::GetPDFDoc() {
317  return m_pPDFDoc;
318}
319#define _FXLIB_NEW_VERSION_
320CFX_DIBitmap* CXFA_FFDoc::GetPDFNamedImage(const CFX_WideStringC& wsName,
321                                           int32_t& iImageXDpi,
322                                           int32_t& iImageYDpi) {
323  if (!m_pPDFDoc) {
324    return NULL;
325  }
326  FX_DWORD dwHash =
327      FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), FALSE);
328  FX_IMAGEDIB_AND_DPI* imageDIBDpi = NULL;
329  if (m_mapNamedImages.Lookup((void*)(uintptr_t)dwHash, (void*&)imageDIBDpi)) {
330    iImageXDpi = imageDIBDpi->iImageXDpi;
331    iImageYDpi = imageDIBDpi->iImageYDpi;
332    return (CFX_DIBitmap*)imageDIBDpi->pDibSource;
333  }
334  CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot();
335  if (pRoot == NULL) {
336    return NULL;
337  }
338  CPDF_Dictionary* pNames = pRoot->GetDict("Names");
339  if (!pNames) {
340    return NULL;
341  }
342  CPDF_Dictionary* pXFAImages = pNames->GetDict("XFAImages");
343  if (!pXFAImages) {
344    return NULL;
345  }
346  CPDF_NameTree nametree(pXFAImages);
347#ifdef _FXLIB_NEW_VERSION_
348  CFX_ByteString bsName = PDF_EncodeText(wsName.GetPtr(), wsName.GetLength());
349  CPDF_Object* pObject = nametree.LookupValue(bsName);
350  if (!pObject) {
351    int32_t iCount = nametree.GetCount();
352    for (int32_t i = 0; i < iCount; i++) {
353      CFX_ByteString bsTemp;
354      CPDF_Object* pTempObject = nametree.LookupValue(i, bsTemp);
355      if (bsTemp == bsName) {
356        pObject = pTempObject;
357        break;
358      }
359    }
360  }
361#else
362  CPDF_Object* pObject = nametree.LookupValue(wsName);
363  if (!pObject) {
364    int32_t iCount = nametree.GetCount();
365    for (int32_t i = 0; i < iCount; i++) {
366      CFX_WideString wsTemp;
367      CPDF_Object* pTempObject = nametree.LookupValue(i, wsTemp);
368      if (wsTemp == wsName) {
369        pObject = pTempObject;
370        break;
371      }
372    }
373  }
374#endif
375  if (!pObject || pObject->GetType() != PDFOBJ_STREAM) {
376    return NULL;
377  }
378  if (!imageDIBDpi) {
379    imageDIBDpi = FX_Alloc(FX_IMAGEDIB_AND_DPI, 1);
380    imageDIBDpi->pDibSource = NULL;
381    imageDIBDpi->iImageXDpi = 0;
382    imageDIBDpi->iImageYDpi = 0;
383    CPDF_StreamAcc streamAcc;
384    streamAcc.LoadAllData((CPDF_Stream*)pObject);
385    IFX_FileRead* pImageFileRead = FX_CreateMemoryStream(
386        (uint8_t*)streamAcc.GetData(), streamAcc.GetSize());
387    imageDIBDpi->pDibSource = XFA_LoadImageFromBuffer(
388        pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi);
389    imageDIBDpi->iImageXDpi = iImageXDpi;
390    imageDIBDpi->iImageYDpi = iImageYDpi;
391    pImageFileRead->Release();
392  }
393  m_mapNamedImages.SetAt((void*)(uintptr_t)dwHash, imageDIBDpi);
394  return (CFX_DIBitmap*)imageDIBDpi->pDibSource;
395}
396IFDE_XMLElement* CXFA_FFDoc::GetPackageData(const CFX_WideStringC& wsPackage) {
397  FX_DWORD packetHash =
398      FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength());
399  CXFA_Object* pObject = m_pDocument->GetXFANode(packetHash);
400  CXFA_Node* pNode =
401      (pObject && pObject->IsNode()) ? (CXFA_Node*)pObject : NULL;
402  if (!pNode) {
403    return NULL;
404  }
405  IFDE_XMLNode* pXMLNode = pNode->GetXMLMappingNode();
406  return (pXMLNode && pXMLNode->GetType() == FDE_XMLNODE_Element)
407             ? (IFDE_XMLElement*)pXMLNode
408             : NULL;
409}
410FX_BOOL CXFA_FFDoc::SavePackage(const CFX_WideStringC& wsPackage,
411                                IFX_FileWrite* pFile,
412                                IXFA_ChecksumContext* pCSContext) {
413  IXFA_PacketExport* pExport = IXFA_PacketExport::Create(m_pDocument);
414  if (!pExport) {
415    return FALSE;
416  }
417  FX_DWORD packetHash =
418      FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength());
419  CXFA_Node* pNode = NULL;
420  if (packetHash == XFA_HASHCODE_Xfa) {
421    pNode = m_pDocument->GetRoot();
422  } else {
423    CXFA_Object* pObject = m_pDocument->GetXFANode(packetHash);
424    pNode = (pObject && pObject->IsNode()) ? (CXFA_Node*)pObject : NULL;
425  }
426  FX_BOOL bFlags = FALSE;
427  if (pNode) {
428    CFX_ByteString bsChecksum;
429    if (pCSContext) {
430      pCSContext->GetChecksum(bsChecksum);
431    }
432    bFlags = pExport->Export(pFile, pNode, 0, bsChecksum.GetLength()
433                                                  ? (const FX_CHAR*)bsChecksum
434                                                  : NULL);
435  } else {
436    bFlags = pExport->Export(pFile);
437  }
438  pExport->Release();
439  return bFlags;
440}
441FX_BOOL CXFA_FFDoc::ImportData(IFX_FileRead* pStream, FX_BOOL bXDP) {
442  FX_BOOL bRet = FALSE;
443  IXFA_PacketImport* pImport = IXFA_PacketImport::Create(m_pDocument);
444  if (pImport) {
445    bRet = pImport->ImportData(pStream);
446    pImport->Release();
447  }
448  return bRet;
449}
450