diff options
Diffstat (limited to 'fpdfsdk/fpdfsave.cpp')
-rw-r--r-- | fpdfsdk/fpdfsave.cpp | 328 |
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); +} |