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: 34 ~CFX_IFileWrite() override {} 35 36 FPDF_FILEWRITE* m_pFileWriteStruct; 37 }; 38 39 CFX_IFileWrite::CFX_IFileWrite() { 40 m_pFileWriteStruct = NULL; 41 } 42 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 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 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 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 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 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 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 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 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