• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "public/fpdf_save.h"
8 
9 #include "core/include/fpdfapi/fpdf_serial.h"
10 #include "fpdfsdk/include/fsdk_define.h"
11 #include "public/fpdf_edit.h"
12 
13 #ifdef PDF_ENABLE_XFA
14 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_app.h"
15 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h"
16 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_util.h"
17 #include "public/fpdf_formfill.h"
18 #endif
19 
20 #if _FX_OS_ == _FX_ANDROID_
21 #include "time.h"
22 #else
23 #include <ctime>
24 #endif
25 
26 class CFX_IFileWrite final : public IFX_StreamWrite {
27  public:
28   CFX_IFileWrite();
29   FX_BOOL Init(FPDF_FILEWRITE* pFileWriteStruct);
30   FX_BOOL WriteBlock(const void* pData, size_t size) override;
31   void Release() override;
32 
33  protected:
~CFX_IFileWrite()34   ~CFX_IFileWrite() override {}
35 
36   FPDF_FILEWRITE* m_pFileWriteStruct;
37 };
38 
CFX_IFileWrite()39 CFX_IFileWrite::CFX_IFileWrite() {
40   m_pFileWriteStruct = NULL;
41 }
42 
Init(FPDF_FILEWRITE * pFileWriteStruct)43 FX_BOOL CFX_IFileWrite::Init(FPDF_FILEWRITE* pFileWriteStruct) {
44   if (!pFileWriteStruct)
45     return FALSE;
46 
47   m_pFileWriteStruct = pFileWriteStruct;
48   return TRUE;
49 }
50 
WriteBlock(const void * pData,size_t size)51 FX_BOOL CFX_IFileWrite::WriteBlock(const void* pData, size_t size) {
52   if (!m_pFileWriteStruct)
53     return FALSE;
54 
55   m_pFileWriteStruct->WriteBlock(m_pFileWriteStruct, pData, size);
56   return TRUE;
57 }
58 
Release()59 void CFX_IFileWrite::Release() {
60   delete this;
61 }
62 
63 #ifdef PDF_ENABLE_XFA
64 #define XFA_DATASETS 0
65 #define XFA_FORMS 1
66 
_SaveXFADocumentData(CPDFXFA_Document * pDocument,CFX_PtrArray & fileList)67 FX_BOOL _SaveXFADocumentData(CPDFXFA_Document* pDocument,
68                              CFX_PtrArray& fileList) {
69   if (!pDocument)
70     return FALSE;
71   if (pDocument->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
72       pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
73     return TRUE;
74   if (!CPDFXFA_App::GetInstance()->GetXFAApp())
75     return TRUE;
76 
77   IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
78   if (NULL == pXFADocView)
79     return TRUE;
80 
81   IXFA_DocHandler* pXFADocHandler =
82       CPDFXFA_App::GetInstance()->GetXFAApp()->GetDocHandler();
83   CPDF_Document* pPDFDocument = pDocument->GetPDFDoc();
84   if (pDocument == NULL)
85     return FALSE;
86 
87   CPDF_Dictionary* pRoot = pPDFDocument->GetRoot();
88   if (pRoot == NULL)
89     return FALSE;
90   CPDF_Dictionary* pAcroForm = pRoot->GetDict("AcroForm");
91   if (NULL == pAcroForm)
92     return FALSE;
93   CPDF_Object* pXFA = pAcroForm->GetElement("XFA");
94   if (pXFA == NULL)
95     return TRUE;
96   if (pXFA->GetType() != PDFOBJ_ARRAY)
97     return FALSE;
98   CPDF_Array* pArray = pXFA->GetArray();
99   if (NULL == pArray)
100     return FALSE;
101   int size = pArray->GetCount();
102   int iFormIndex = -1;
103   int iDataSetsIndex = -1;
104   int iTemplate = -1;
105   int iLast = size - 2;
106   for (int i = 0; i < size - 1; i++) {
107     CPDF_Object* pPDFObj = pArray->GetElement(i);
108     if (pPDFObj->GetType() != PDFOBJ_STRING)
109       continue;
110     if (pPDFObj->GetString() == "form")
111       iFormIndex = i + 1;
112     else if (pPDFObj->GetString() == "datasets")
113       iDataSetsIndex = i + 1;
114     else if (pPDFObj->GetString() == "template")
115       iTemplate = i + 1;
116   }
117   IXFA_ChecksumContext* pContext = NULL;
118   // Checksum
119   pContext = XFA_Checksum_Create();
120   FXSYS_assert(pContext);
121   pContext->StartChecksum();
122 
123   // template
124   if (iTemplate > -1) {
125     CPDF_Stream* pTemplateStream = pArray->GetStream(iTemplate);
126     CPDF_StreamAcc streamAcc;
127     streamAcc.LoadAllData(pTemplateStream);
128     uint8_t* pData = (uint8_t*)streamAcc.GetData();
129     FX_DWORD dwSize2 = streamAcc.GetSize();
130     IFX_FileStream* pTemplate = FX_CreateMemoryStream(pData, dwSize2);
131     pContext->UpdateChecksum((IFX_FileRead*)pTemplate);
132     pTemplate->Release();
133   }
134   CPDF_Stream* pFormStream = NULL;
135   CPDF_Stream* pDataSetsStream = NULL;
136   if (iFormIndex != -1) {
137     // Get form CPDF_Stream
138     CPDF_Object* pFormPDFObj = pArray->GetElement(iFormIndex);
139     if (pFormPDFObj->GetType() == PDFOBJ_REFERENCE) {
140       CPDF_Object* pFormDircetObj = pFormPDFObj->GetDirect();
141       if (NULL != pFormDircetObj &&
142           pFormDircetObj->GetType() == PDFOBJ_STREAM) {
143         pFormStream = (CPDF_Stream*)pFormDircetObj;
144       }
145     } else if (pFormPDFObj->GetType() == PDFOBJ_STREAM) {
146       pFormStream = (CPDF_Stream*)pFormPDFObj;
147     }
148   }
149 
150   if (iDataSetsIndex != -1) {
151     // Get datasets CPDF_Stream
152     CPDF_Object* pDataSetsPDFObj = pArray->GetElement(iDataSetsIndex);
153     if (pDataSetsPDFObj->GetType() == PDFOBJ_REFERENCE) {
154       CPDF_Reference* pDataSetsRefObj = (CPDF_Reference*)pDataSetsPDFObj;
155       CPDF_Object* pDataSetsDircetObj = pDataSetsRefObj->GetDirect();
156       if (NULL != pDataSetsDircetObj &&
157           pDataSetsDircetObj->GetType() == PDFOBJ_STREAM) {
158         pDataSetsStream = (CPDF_Stream*)pDataSetsDircetObj;
159       }
160     } else if (pDataSetsPDFObj->GetType() == PDFOBJ_STREAM) {
161       pDataSetsStream = (CPDF_Stream*)pDataSetsPDFObj;
162     }
163   }
164   // end
165   // L"datasets"
166   {
167     IFX_FileStream* pDsfileWrite = FX_CreateMemoryStream();
168     if (NULL == pDsfileWrite) {
169       pContext->Release();
170       pDsfileWrite->Release();
171       return FALSE;
172     }
173     if (pXFADocHandler->SavePackage(pXFADocView->GetDoc(),
174                                     CFX_WideStringC(L"datasets"),
175                                     pDsfileWrite) &&
176         pDsfileWrite->GetSize() > 0) {
177       // Datasets
178       pContext->UpdateChecksum((IFX_FileRead*)pDsfileWrite);
179       pContext->FinishChecksum();
180       CPDF_Dictionary* pDataDict = new CPDF_Dictionary;
181       if (iDataSetsIndex != -1) {
182         if (pDataSetsStream)
183           pDataSetsStream->InitStreamFromFile(pDsfileWrite, pDataDict);
184       } else {
185         CPDF_Stream* pData = new CPDF_Stream(NULL, 0, NULL);
186         pData->InitStreamFromFile(pDsfileWrite, pDataDict);
187         pPDFDocument->AddIndirectObject(pData);
188         iLast = pArray->GetCount() - 2;
189         pArray->InsertAt(iLast, new CPDF_String("datasets", FALSE));
190         pArray->InsertAt(iLast + 1, pData, pPDFDocument);
191       }
192       fileList.Add(pDsfileWrite);
193     }
194   }
195 
196   // L"form"
197   {
198     IFX_FileStream* pfileWrite = FX_CreateMemoryStream();
199     if (NULL == pfileWrite) {
200       pContext->Release();
201       return FALSE;
202     }
203     if (pXFADocHandler->SavePackage(pXFADocView->GetDoc(),
204                                     CFX_WideStringC(L"form"), pfileWrite,
205                                     pContext) &&
206         pfileWrite > 0) {
207       CPDF_Dictionary* pDataDict = new CPDF_Dictionary;
208       if (iFormIndex != -1) {
209         if (pFormStream)
210           pFormStream->InitStreamFromFile(pfileWrite, pDataDict);
211       } else {
212         CPDF_Stream* pData = new CPDF_Stream(NULL, 0, NULL);
213         pData->InitStreamFromFile(pfileWrite, pDataDict);
214         pPDFDocument->AddIndirectObject(pData);
215         iLast = pArray->GetCount() - 2;
216         pArray->InsertAt(iLast, new CPDF_String("form", FALSE));
217         pArray->InsertAt(iLast + 1, pData, pPDFDocument);
218       }
219       fileList.Add(pfileWrite);
220     }
221   }
222   pContext->Release();
223   return TRUE;
224 }
225 
_SendPostSaveToXFADoc(CPDFXFA_Document * pDocument)226 FX_BOOL _SendPostSaveToXFADoc(CPDFXFA_Document* pDocument) {
227   if (!pDocument)
228     return FALSE;
229 
230   if (pDocument->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
231       pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
232     return TRUE;
233 
234   IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
235   if (NULL == pXFADocView)
236     return FALSE;
237   IXFA_WidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
238 
239   CXFA_WidgetAcc* pWidgetAcc = NULL;
240   IXFA_WidgetAccIterator* pWidgetAccIterator =
241       pXFADocView->CreateWidgetAccIterator();
242   pWidgetAcc = pWidgetAccIterator->MoveToNext();
243   while (pWidgetAcc) {
244     CXFA_EventParam preParam;
245     preParam.m_eType = XFA_EVENT_PostSave;
246     pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
247     pWidgetAcc = pWidgetAccIterator->MoveToNext();
248   }
249   pWidgetAccIterator->Release();
250   pXFADocView->UpdateDocView();
251   pDocument->_ClearChangeMark();
252   return TRUE;
253 }
254 
_SendPreSaveToXFADoc(CPDFXFA_Document * pDocument,CFX_PtrArray & fileList)255 FX_BOOL _SendPreSaveToXFADoc(CPDFXFA_Document* pDocument,
256                              CFX_PtrArray& fileList) {
257   if (pDocument->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
258       pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
259     return TRUE;
260   IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
261   if (NULL == pXFADocView)
262     return TRUE;
263   IXFA_WidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
264   CXFA_WidgetAcc* pWidgetAcc = NULL;
265   IXFA_WidgetAccIterator* pWidgetAccIterator =
266       pXFADocView->CreateWidgetAccIterator();
267   pWidgetAcc = pWidgetAccIterator->MoveToNext();
268   while (pWidgetAcc) {
269     CXFA_EventParam preParam;
270     preParam.m_eType = XFA_EVENT_PreSave;
271     pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
272     pWidgetAcc = pWidgetAccIterator->MoveToNext();
273   }
274   pWidgetAccIterator->Release();
275   pXFADocView->UpdateDocView();
276   return _SaveXFADocumentData(pDocument, fileList);
277 }
278 #endif  // PDF_ENABLE_XFA
279 
_FPDF_Doc_Save(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags,FPDF_BOOL bSetVersion,int fileVerion)280 FPDF_BOOL _FPDF_Doc_Save(FPDF_DOCUMENT document,
281                          FPDF_FILEWRITE* pFileWrite,
282                          FPDF_DWORD flags,
283                          FPDF_BOOL bSetVersion,
284                          int fileVerion) {
285   CPDF_Document* pPDFDoc = CPDFDocumentFromFPDFDocument(document);
286   if (!pPDFDoc)
287     return 0;
288 
289 #ifdef PDF_ENABLE_XFA
290   CPDFXFA_Document* pDoc = (CPDFXFA_Document*)document;
291   CFX_PtrArray fileList;
292   _SendPreSaveToXFADoc(pDoc, fileList);
293 #endif  // PDF_ENABLE_XFA
294 
295   if (flags < FPDF_INCREMENTAL || flags > FPDF_REMOVE_SECURITY) {
296     flags = 0;
297   }
298 
299   CPDF_Creator FileMaker(pPDFDoc);
300   if (bSetVersion)
301     FileMaker.SetFileVersion(fileVerion);
302   if (flags == FPDF_REMOVE_SECURITY) {
303     flags = 0;
304     FileMaker.RemoveSecurity();
305   }
306 
307   CFX_IFileWrite* pStreamWrite = NULL;
308   FX_BOOL bRet;
309   pStreamWrite = new CFX_IFileWrite;
310   pStreamWrite->Init(pFileWrite);
311   bRet = FileMaker.Create(pStreamWrite, flags);
312 #ifdef PDF_ENABLE_XFA
313   _SendPostSaveToXFADoc(pDoc);
314   for (int i = 0; i < fileList.GetSize(); i++) {
315     IFX_FileStream* pFile = (IFX_FileStream*)fileList.GetAt(i);
316     pFile->Release();
317   }
318   fileList.RemoveAll();
319 #endif  // PDF_ENABLE_XFA
320   pStreamWrite->Release();
321   return bRet;
322 }
323 
FPDF_SaveAsCopy(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags)324 DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveAsCopy(FPDF_DOCUMENT document,
325                                             FPDF_FILEWRITE* pFileWrite,
326                                             FPDF_DWORD flags) {
327   return _FPDF_Doc_Save(document, pFileWrite, flags, FALSE, 0);
328 }
329 
FPDF_SaveWithVersion(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags,int fileVersion)330 DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveWithVersion(FPDF_DOCUMENT document,
331                                                  FPDF_FILEWRITE* pFileWrite,
332                                                  FPDF_DWORD flags,
333                                                  int fileVersion) {
334   return _FPDF_Doc_Save(document, pFileWrite, flags, TRUE, fileVersion);
335 }
336