summaryrefslogtreecommitdiff
path: root/fpdfsdk/fpdfsave.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fpdfsdk/fpdfsave.cpp')
-rw-r--r--fpdfsdk/fpdfsave.cpp328
1 files changed, 328 insertions, 0 deletions
diff --git a/fpdfsdk/fpdfsave.cpp b/fpdfsdk/fpdfsave.cpp
new file mode 100644
index 0000000000..81defbf0a7
--- /dev/null
+++ b/fpdfsdk/fpdfsave.cpp
@@ -0,0 +1,328 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "public/fpdf_save.h"
+
+#include <vector>
+
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/cpdf_reference.h"
+#include "core/include/fpdfapi/cpdf_string.h"
+#include "core/include/fpdfapi/fpdf_serial.h"
+#include "core/include/fxcrt/fx_ext.h"
+#include "fpdfsdk/include/fsdk_define.h"
+#include "public/fpdf_edit.h"
+
+#ifdef PDF_ENABLE_XFA
+#include "fpdfsdk/include/fpdfxfa/fpdfxfa_app.h"
+#include "fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h"
+#include "fpdfsdk/include/fpdfxfa/fpdfxfa_util.h"
+#include "public/fpdf_formfill.h"
+#endif
+
+#if _FX_OS_ == _FX_ANDROID_
+#include "time.h"
+#else
+#include <ctime>
+#endif
+
+class CFX_IFileWrite final : public IFX_StreamWrite {
+ public:
+ CFX_IFileWrite();
+ FX_BOOL Init(FPDF_FILEWRITE* pFileWriteStruct);
+ FX_BOOL WriteBlock(const void* pData, size_t size) override;
+ void Release() override;
+
+ protected:
+ ~CFX_IFileWrite() override {}
+
+ FPDF_FILEWRITE* m_pFileWriteStruct;
+};
+
+CFX_IFileWrite::CFX_IFileWrite() {
+ m_pFileWriteStruct = NULL;
+}
+
+FX_BOOL CFX_IFileWrite::Init(FPDF_FILEWRITE* pFileWriteStruct) {
+ if (!pFileWriteStruct)
+ return FALSE;
+
+ m_pFileWriteStruct = pFileWriteStruct;
+ return TRUE;
+}
+
+FX_BOOL CFX_IFileWrite::WriteBlock(const void* pData, size_t size) {
+ if (!m_pFileWriteStruct)
+ return FALSE;
+
+ m_pFileWriteStruct->WriteBlock(m_pFileWriteStruct, pData, size);
+ return TRUE;
+}
+
+void CFX_IFileWrite::Release() {
+ delete this;
+}
+
+namespace {
+
+#ifdef PDF_ENABLE_XFA
+bool SaveXFADocumentData(CPDFXFA_Document* pDocument,
+ std::vector<ScopedFileStream>* fileList) {
+ if (!pDocument)
+ return false;
+
+ if (pDocument->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
+ pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
+ return true;
+
+ if (!CPDFXFA_App::GetInstance()->GetXFAApp())
+ return true;
+
+ IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
+ if (!pXFADocView)
+ return true;
+
+ IXFA_DocHandler* pXFADocHandler =
+ CPDFXFA_App::GetInstance()->GetXFAApp()->GetDocHandler();
+ CPDF_Document* pPDFDocument = pDocument->GetPDFDoc();
+ if (!pDocument)
+ return false;
+
+ CPDF_Dictionary* pRoot = pPDFDocument->GetRoot();
+ if (!pRoot)
+ return false;
+
+ CPDF_Dictionary* pAcroForm = pRoot->GetDictBy("AcroForm");
+ if (!pAcroForm)
+ return false;
+
+ CPDF_Object* pXFA = pAcroForm->GetElement("XFA");
+ if (!pXFA)
+ return true;
+
+ if (!pXFA->IsArray())
+ return false;
+
+ CPDF_Array* pArray = pXFA->GetArray();
+ if (!pArray)
+ return false;
+
+ int size = pArray->GetCount();
+ int iFormIndex = -1;
+ int iDataSetsIndex = -1;
+ int iTemplate = -1;
+ int iLast = size - 2;
+ for (int i = 0; i < size - 1; i++) {
+ CPDF_Object* pPDFObj = pArray->GetElement(i);
+ if (!pPDFObj->IsString())
+ continue;
+ if (pPDFObj->GetString() == "form")
+ iFormIndex = i + 1;
+ else if (pPDFObj->GetString() == "datasets")
+ iDataSetsIndex = i + 1;
+ else if (pPDFObj->GetString() == "template")
+ iTemplate = i + 1;
+ }
+ std::unique_ptr<IXFA_ChecksumContext, ReleaseDeleter<IXFA_ChecksumContext>>
+ pContext(XFA_Checksum_Create());
+ pContext->StartChecksum();
+
+ // template
+ if (iTemplate > -1) {
+ CPDF_Stream* pTemplateStream = pArray->GetStreamAt(iTemplate);
+ CPDF_StreamAcc streamAcc;
+ streamAcc.LoadAllData(pTemplateStream);
+ uint8_t* pData = (uint8_t*)streamAcc.GetData();
+ FX_DWORD dwSize2 = streamAcc.GetSize();
+ ScopedFileStream pTemplate(FX_CreateMemoryStream(pData, dwSize2));
+ pContext->UpdateChecksum(pTemplate.get());
+ }
+ CPDF_Stream* pFormStream = NULL;
+ CPDF_Stream* pDataSetsStream = NULL;
+ if (iFormIndex != -1) {
+ // Get form CPDF_Stream
+ CPDF_Object* pFormPDFObj = pArray->GetElement(iFormIndex);
+ if (pFormPDFObj->IsReference()) {
+ CPDF_Object* pFormDirectObj = pFormPDFObj->GetDirect();
+ if (pFormDirectObj && pFormDirectObj->IsStream()) {
+ pFormStream = (CPDF_Stream*)pFormDirectObj;
+ }
+ } else if (pFormPDFObj->IsStream()) {
+ pFormStream = (CPDF_Stream*)pFormPDFObj;
+ }
+ }
+
+ if (iDataSetsIndex != -1) {
+ // Get datasets CPDF_Stream
+ CPDF_Object* pDataSetsPDFObj = pArray->GetElement(iDataSetsIndex);
+ if (pDataSetsPDFObj->IsReference()) {
+ CPDF_Reference* pDataSetsRefObj = (CPDF_Reference*)pDataSetsPDFObj;
+ CPDF_Object* pDataSetsDirectObj = pDataSetsRefObj->GetDirect();
+ if (pDataSetsDirectObj && pDataSetsDirectObj->IsStream()) {
+ pDataSetsStream = (CPDF_Stream*)pDataSetsDirectObj;
+ }
+ } else if (pDataSetsPDFObj->IsStream()) {
+ pDataSetsStream = (CPDF_Stream*)pDataSetsPDFObj;
+ }
+ }
+ // L"datasets"
+ {
+ ScopedFileStream pDsfileWrite(FX_CreateMemoryStream());
+ if (pXFADocHandler->SavePackage(pXFADocView->GetDoc(),
+ CFX_WideStringC(L"datasets"),
+ pDsfileWrite.get()) &&
+ pDsfileWrite->GetSize() > 0) {
+ // Datasets
+ pContext->UpdateChecksum(pDsfileWrite.get());
+ pContext->FinishChecksum();
+ CPDF_Dictionary* pDataDict = new CPDF_Dictionary;
+ if (iDataSetsIndex != -1) {
+ if (pDataSetsStream)
+ pDataSetsStream->InitStreamFromFile(pDsfileWrite.get(), pDataDict);
+ } else {
+ CPDF_Stream* pData = new CPDF_Stream(NULL, 0, NULL);
+ pData->InitStreamFromFile(pDsfileWrite.get(), pDataDict);
+ pPDFDocument->AddIndirectObject(pData);
+ iLast = pArray->GetCount() - 2;
+ pArray->InsertAt(iLast, new CPDF_String("datasets", FALSE));
+ pArray->InsertAt(iLast + 1, pData, pPDFDocument);
+ }
+ fileList->push_back(std::move(pDsfileWrite));
+ }
+ }
+ // L"form"
+ {
+ ScopedFileStream pfileWrite(FX_CreateMemoryStream());
+ if (pXFADocHandler->SavePackage(pXFADocView->GetDoc(),
+ CFX_WideStringC(L"form"), pfileWrite.get(),
+ pContext.get()) &&
+ pfileWrite->GetSize() > 0) {
+ CPDF_Dictionary* pDataDict = new CPDF_Dictionary;
+ if (iFormIndex != -1) {
+ if (pFormStream)
+ pFormStream->InitStreamFromFile(pfileWrite.get(), pDataDict);
+ } else {
+ CPDF_Stream* pData = new CPDF_Stream(NULL, 0, NULL);
+ pData->InitStreamFromFile(pfileWrite.get(), pDataDict);
+ pPDFDocument->AddIndirectObject(pData);
+ iLast = pArray->GetCount() - 2;
+ pArray->InsertAt(iLast, new CPDF_String("form", FALSE));
+ pArray->InsertAt(iLast + 1, pData, pPDFDocument);
+ }
+ fileList->push_back(std::move(pfileWrite));
+ }
+ }
+ return true;
+}
+
+bool SendPostSaveToXFADoc(CPDFXFA_Document* pDocument) {
+ if (!pDocument)
+ return false;
+
+ if (pDocument->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
+ pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
+ return true;
+
+ IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
+ if (!pXFADocView)
+ return false;
+
+ IXFA_WidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
+ CXFA_WidgetAcc* pWidgetAcc = NULL;
+ IXFA_WidgetAccIterator* pWidgetAccIterator =
+ pXFADocView->CreateWidgetAccIterator();
+ pWidgetAcc = pWidgetAccIterator->MoveToNext();
+ while (pWidgetAcc) {
+ CXFA_EventParam preParam;
+ preParam.m_eType = XFA_EVENT_PostSave;
+ pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
+ pWidgetAcc = pWidgetAccIterator->MoveToNext();
+ }
+ pWidgetAccIterator->Release();
+ pXFADocView->UpdateDocView();
+ pDocument->_ClearChangeMark();
+ return true;
+}
+
+bool SendPreSaveToXFADoc(CPDFXFA_Document* pDocument,
+ std::vector<ScopedFileStream>* fileList) {
+ if (pDocument->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
+ pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
+ return true;
+
+ IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
+ if (!pXFADocView)
+ return true;
+
+ IXFA_WidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
+ CXFA_WidgetAcc* pWidgetAcc = NULL;
+ IXFA_WidgetAccIterator* pWidgetAccIterator =
+ pXFADocView->CreateWidgetAccIterator();
+ pWidgetAcc = pWidgetAccIterator->MoveToNext();
+ while (pWidgetAcc) {
+ CXFA_EventParam preParam;
+ preParam.m_eType = XFA_EVENT_PreSave;
+ pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
+ pWidgetAcc = pWidgetAccIterator->MoveToNext();
+ }
+ pWidgetAccIterator->Release();
+ pXFADocView->UpdateDocView();
+ return SaveXFADocumentData(pDocument, fileList);
+}
+#endif // PDF_ENABLE_XFA
+
+bool FPDF_Doc_Save(FPDF_DOCUMENT document,
+ FPDF_FILEWRITE* pFileWrite,
+ FPDF_DWORD flags,
+ FPDF_BOOL bSetVersion,
+ int fileVerion) {
+ CPDF_Document* pPDFDoc = CPDFDocumentFromFPDFDocument(document);
+ if (!pPDFDoc)
+ return 0;
+
+#ifdef PDF_ENABLE_XFA
+ CPDFXFA_Document* pDoc = static_cast<CPDFXFA_Document*>(document);
+ std::vector<ScopedFileStream> fileList;
+ SendPreSaveToXFADoc(pDoc, &fileList);
+#endif // PDF_ENABLE_XFA
+
+ if (flags < FPDF_INCREMENTAL || flags > FPDF_REMOVE_SECURITY)
+ flags = 0;
+
+ CPDF_Creator FileMaker(pPDFDoc);
+ if (bSetVersion)
+ FileMaker.SetFileVersion(fileVerion);
+ if (flags == FPDF_REMOVE_SECURITY) {
+ flags = 0;
+ FileMaker.RemoveSecurity();
+ }
+
+ CFX_IFileWrite* pStreamWrite = NULL;
+ pStreamWrite = new CFX_IFileWrite;
+ pStreamWrite->Init(pFileWrite);
+ bool bRet = FileMaker.Create(pStreamWrite, flags);
+#ifdef PDF_ENABLE_XFA
+ SendPostSaveToXFADoc(pDoc);
+#endif // PDF_ENABLE_XFA
+ pStreamWrite->Release();
+ return bRet;
+}
+
+} // namespace
+
+DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveAsCopy(FPDF_DOCUMENT document,
+ FPDF_FILEWRITE* pFileWrite,
+ FPDF_DWORD flags) {
+ return FPDF_Doc_Save(document, pFileWrite, flags, FALSE, 0);
+}
+
+DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveWithVersion(FPDF_DOCUMENT document,
+ FPDF_FILEWRITE* pFileWrite,
+ FPDF_DWORD flags,
+ int fileVersion) {
+ return FPDF_Doc_Save(document, pFileWrite, flags, TRUE, fileVersion);
+}