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