Home | History | Annotate | Download | only in src
      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