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