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 <memory>
10 #include <utility>
11 #include <vector>
12
13 #include "core/fpdfapi/edit/cpdf_creator.h"
14 #include "core/fpdfapi/parser/cpdf_array.h"
15 #include "core/fpdfapi/parser/cpdf_document.h"
16 #include "core/fpdfapi/parser/cpdf_reference.h"
17 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
18 #include "core/fpdfapi/parser/cpdf_string.h"
19 #include "core/fxcrt/fx_ext.h"
20 #include "fpdfsdk/fsdk_define.h"
21 #include "public/fpdf_edit.h"
22
23 #ifdef PDF_ENABLE_XFA
24 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
25 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
26 #include "public/fpdf_formfill.h"
27 #include "xfa/fxfa/cxfa_eventparam.h"
28 #include "xfa/fxfa/xfa_checksum.h"
29 #include "xfa/fxfa/xfa_ffapp.h"
30 #include "xfa/fxfa/xfa_ffdocview.h"
31 #include "xfa/fxfa/xfa_ffwidgethandler.h"
32 #endif
33
34 #if _FX_OS_ == _FX_ANDROID_
35 #include <time.h>
36 #else
37 #include <ctime>
38 #endif
39
40 class CFX_IFileWrite final : public IFX_WriteStream {
41 public:
42 static CFX_RetainPtr<CFX_IFileWrite> Create();
43 bool Init(FPDF_FILEWRITE* pFileWriteStruct);
44 bool WriteBlock(const void* pData, size_t size) override;
45
46 protected:
47 CFX_IFileWrite();
~CFX_IFileWrite()48 ~CFX_IFileWrite() override {}
49
50 FPDF_FILEWRITE* m_pFileWriteStruct;
51 };
52
Create()53 CFX_RetainPtr<CFX_IFileWrite> CFX_IFileWrite::Create() {
54 return CFX_RetainPtr<CFX_IFileWrite>(new CFX_IFileWrite());
55 }
56
CFX_IFileWrite()57 CFX_IFileWrite::CFX_IFileWrite() : m_pFileWriteStruct(nullptr) {}
58
Init(FPDF_FILEWRITE * pFileWriteStruct)59 bool CFX_IFileWrite::Init(FPDF_FILEWRITE* pFileWriteStruct) {
60 if (!pFileWriteStruct)
61 return false;
62
63 m_pFileWriteStruct = pFileWriteStruct;
64 return true;
65 }
66
WriteBlock(const void * pData,size_t size)67 bool CFX_IFileWrite::WriteBlock(const void* pData, size_t size) {
68 if (!m_pFileWriteStruct)
69 return false;
70
71 m_pFileWriteStruct->WriteBlock(m_pFileWriteStruct, pData, size);
72 return true;
73 }
74
75 namespace {
76
77 #ifdef PDF_ENABLE_XFA
SaveXFADocumentData(CPDFXFA_Context * pContext,std::vector<CFX_RetainPtr<IFX_SeekableStream>> * fileList)78 bool SaveXFADocumentData(
79 CPDFXFA_Context* pContext,
80 std::vector<CFX_RetainPtr<IFX_SeekableStream>>* fileList) {
81 if (!pContext)
82 return false;
83
84 if (pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
85 pContext->GetDocType() != DOCTYPE_STATIC_XFA)
86 return true;
87
88 CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
89 if (!pXFADocView)
90 return true;
91
92 CPDF_Document* pPDFDocument = pContext->GetPDFDoc();
93 if (!pPDFDocument)
94 return false;
95
96 CPDF_Dictionary* pRoot = pPDFDocument->GetRoot();
97 if (!pRoot)
98 return false;
99
100 CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
101 if (!pAcroForm)
102 return false;
103
104 CPDF_Object* pXFA = pAcroForm->GetObjectFor("XFA");
105 if (!pXFA)
106 return true;
107
108 CPDF_Array* pArray = pXFA->AsArray();
109 if (!pArray)
110 return false;
111
112 int size = pArray->GetCount();
113 int iFormIndex = -1;
114 int iDataSetsIndex = -1;
115 int iTemplate = -1;
116 int iLast = size - 2;
117 for (int i = 0; i < size - 1; i++) {
118 CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
119 if (!pPDFObj->IsString())
120 continue;
121 if (pPDFObj->GetString() == "form")
122 iFormIndex = i + 1;
123 else if (pPDFObj->GetString() == "datasets")
124 iDataSetsIndex = i + 1;
125 else if (pPDFObj->GetString() == "template")
126 iTemplate = i + 1;
127 }
128 std::unique_ptr<CXFA_ChecksumContext> pChecksum(new CXFA_ChecksumContext);
129 pChecksum->StartChecksum();
130
131 // template
132 if (iTemplate > -1) {
133 CPDF_Stream* pTemplateStream = pArray->GetStreamAt(iTemplate);
134 CPDF_StreamAcc streamAcc;
135 streamAcc.LoadAllData(pTemplateStream);
136 uint8_t* pData = (uint8_t*)streamAcc.GetData();
137 uint32_t dwSize2 = streamAcc.GetSize();
138 CFX_RetainPtr<IFX_SeekableStream> pTemplate =
139 IFX_MemoryStream::Create(pData, dwSize2);
140 pChecksum->UpdateChecksum(pTemplate);
141 }
142 CPDF_Stream* pFormStream = nullptr;
143 CPDF_Stream* pDataSetsStream = nullptr;
144 if (iFormIndex != -1) {
145 // Get form CPDF_Stream
146 CPDF_Object* pFormPDFObj = pArray->GetObjectAt(iFormIndex);
147 if (pFormPDFObj->IsReference()) {
148 CPDF_Object* pFormDirectObj = pFormPDFObj->GetDirect();
149 if (pFormDirectObj && pFormDirectObj->IsStream()) {
150 pFormStream = (CPDF_Stream*)pFormDirectObj;
151 }
152 } else if (pFormPDFObj->IsStream()) {
153 pFormStream = (CPDF_Stream*)pFormPDFObj;
154 }
155 }
156
157 if (iDataSetsIndex != -1) {
158 // Get datasets CPDF_Stream
159 CPDF_Object* pDataSetsPDFObj = pArray->GetObjectAt(iDataSetsIndex);
160 if (pDataSetsPDFObj->IsReference()) {
161 CPDF_Reference* pDataSetsRefObj = (CPDF_Reference*)pDataSetsPDFObj;
162 CPDF_Object* pDataSetsDirectObj = pDataSetsRefObj->GetDirect();
163 if (pDataSetsDirectObj && pDataSetsDirectObj->IsStream()) {
164 pDataSetsStream = (CPDF_Stream*)pDataSetsDirectObj;
165 }
166 } else if (pDataSetsPDFObj->IsStream()) {
167 pDataSetsStream = (CPDF_Stream*)pDataSetsPDFObj;
168 }
169 }
170 // L"datasets"
171 {
172 CFX_RetainPtr<IFX_SeekableStream> pDsfileWrite = IFX_MemoryStream::Create();
173 if (pXFADocView->GetDoc()->SavePackage(XFA_HASHCODE_Datasets, pDsfileWrite,
174 nullptr) &&
175 pDsfileWrite->GetSize() > 0) {
176 // Datasets
177 pChecksum->UpdateChecksum(pDsfileWrite);
178 pChecksum->FinishChecksum();
179 auto pDataDict = pdfium::MakeUnique<CPDF_Dictionary>(
180 pPDFDocument->GetByteStringPool());
181 if (iDataSetsIndex != -1) {
182 if (pDataSetsStream) {
183 pDataSetsStream->InitStreamFromFile(pDsfileWrite,
184 std::move(pDataDict));
185 }
186 } else {
187 CPDF_Stream* pData = pPDFDocument->NewIndirect<CPDF_Stream>();
188 pData->InitStreamFromFile(pDsfileWrite, std::move(pDataDict));
189 iLast = pArray->GetCount() - 2;
190 pArray->InsertNewAt<CPDF_String>(iLast, "datasets", false);
191 pArray->InsertNewAt<CPDF_Reference>(iLast + 1, pPDFDocument,
192 pData->GetObjNum());
193 }
194 fileList->push_back(std::move(pDsfileWrite));
195 }
196 }
197 // L"form"
198 {
199 CFX_RetainPtr<IFX_SeekableStream> pfileWrite = IFX_MemoryStream::Create();
200 if (pXFADocView->GetDoc()->SavePackage(XFA_HASHCODE_Form, pfileWrite,
201 pChecksum.get()) &&
202 pfileWrite->GetSize() > 0) {
203 auto pDataDict = pdfium::MakeUnique<CPDF_Dictionary>(
204 pPDFDocument->GetByteStringPool());
205 if (iFormIndex != -1) {
206 if (pFormStream)
207 pFormStream->InitStreamFromFile(pfileWrite, std::move(pDataDict));
208 } else {
209 CPDF_Stream* pData = pPDFDocument->NewIndirect<CPDF_Stream>();
210 pData->InitStreamFromFile(pfileWrite, std::move(pDataDict));
211 iLast = pArray->GetCount() - 2;
212 pArray->InsertNewAt<CPDF_String>(iLast, "form", false);
213 pArray->InsertNewAt<CPDF_Reference>(iLast + 1, pPDFDocument,
214 pData->GetObjNum());
215 }
216 fileList->push_back(std::move(pfileWrite));
217 }
218 }
219 return true;
220 }
221
SendPostSaveToXFADoc(CPDFXFA_Context * pContext)222 bool SendPostSaveToXFADoc(CPDFXFA_Context* pContext) {
223 if (!pContext)
224 return false;
225
226 if (pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
227 pContext->GetDocType() != DOCTYPE_STATIC_XFA)
228 return true;
229
230 CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
231 if (!pXFADocView)
232 return false;
233
234 CXFA_FFWidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
235 std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator(
236 pXFADocView->CreateWidgetAccIterator());
237 while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext()) {
238 CXFA_EventParam preParam;
239 preParam.m_eType = XFA_EVENT_PostSave;
240 pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
241 }
242 pXFADocView->UpdateDocView();
243 pContext->ClearChangeMark();
244 return true;
245 }
246
SendPreSaveToXFADoc(CPDFXFA_Context * pContext,std::vector<CFX_RetainPtr<IFX_SeekableStream>> * fileList)247 bool SendPreSaveToXFADoc(
248 CPDFXFA_Context* pContext,
249 std::vector<CFX_RetainPtr<IFX_SeekableStream>>* fileList) {
250 if (pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
251 pContext->GetDocType() != DOCTYPE_STATIC_XFA)
252 return true;
253
254 CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
255 if (!pXFADocView)
256 return true;
257
258 CXFA_FFWidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
259 std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator(
260 pXFADocView->CreateWidgetAccIterator());
261 while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext()) {
262 CXFA_EventParam preParam;
263 preParam.m_eType = XFA_EVENT_PreSave;
264 pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
265 }
266 pXFADocView->UpdateDocView();
267 return SaveXFADocumentData(pContext, fileList);
268 }
269 #endif // PDF_ENABLE_XFA
270
FPDF_Doc_Save(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags,FPDF_BOOL bSetVersion,int fileVerion)271 bool FPDF_Doc_Save(FPDF_DOCUMENT document,
272 FPDF_FILEWRITE* pFileWrite,
273 FPDF_DWORD flags,
274 FPDF_BOOL bSetVersion,
275 int fileVerion) {
276 CPDF_Document* pPDFDoc = CPDFDocumentFromFPDFDocument(document);
277 if (!pPDFDoc)
278 return 0;
279
280 #ifdef PDF_ENABLE_XFA
281 CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
282 std::vector<CFX_RetainPtr<IFX_SeekableStream>> fileList;
283 SendPreSaveToXFADoc(pContext, &fileList);
284 #endif // PDF_ENABLE_XFA
285
286 if (flags < FPDF_INCREMENTAL || flags > FPDF_REMOVE_SECURITY)
287 flags = 0;
288
289 CPDF_Creator FileMaker(pPDFDoc);
290 if (bSetVersion)
291 FileMaker.SetFileVersion(fileVerion);
292 if (flags == FPDF_REMOVE_SECURITY) {
293 flags = 0;
294 FileMaker.RemoveSecurity();
295 }
296
297 CFX_RetainPtr<CFX_IFileWrite> pStreamWrite = CFX_IFileWrite::Create();
298 pStreamWrite->Init(pFileWrite);
299 bool bRet = FileMaker.Create(pStreamWrite, flags);
300 #ifdef PDF_ENABLE_XFA
301 SendPostSaveToXFADoc(pContext);
302 #endif // PDF_ENABLE_XFA
303 return bRet;
304 }
305
306 } // namespace
307
FPDF_SaveAsCopy(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags)308 DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveAsCopy(FPDF_DOCUMENT document,
309 FPDF_FILEWRITE* pFileWrite,
310 FPDF_DWORD flags) {
311 return FPDF_Doc_Save(document, pFileWrite, flags, false, 0);
312 }
313
FPDF_SaveWithVersion(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags,int fileVersion)314 DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveWithVersion(FPDF_DOCUMENT document,
315 FPDF_FILEWRITE* pFileWrite,
316 FPDF_DWORD flags,
317 int fileVersion) {
318 return FPDF_Doc_Save(document, pFileWrite, flags, true, fileVersion);
319 }
320