Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / fpdfsdk / src / fpdfsave.cpp
index 45dfbf7..229e580 100644 (file)
@@ -7,6 +7,9 @@
 #include "../include/fsdk_define.h"
 #include "../include/fpdfsave.h"
 #include "../include/fpdfedit.h"
+#include "../include/fpdfxfa/fpdfxfa_doc.h"
+#include "../include/fpdfxfa/fpdfxfa_app.h"
+#include "../include/fpdfxfa/fpdfxfa_util.h"
 #if _FX_OS_ == _FX_ANDROID_
 #include "time.h"
 #else
@@ -53,11 +56,258 @@ FX_BOOL CFX_IFileWrite::WriteBlock(const void* pData, size_t size)
                return FALSE;
 }
 
-FPDF_BOOL _FPDF_Doc_Save(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags, FPDF_BOOL bSetVersion,
+#define  XFA_DATASETS 0
+#define  XFA_FORMS    1
+
+FX_BOOL _SaveXFADocumentData(CPDFXFA_Document* pDocument, CFX_PtrArray& fileList)
+{
+       if (!pDocument)
+               return FALSE;
+       if (pDocument->GetDocType() != DOCTYPE_DYNIMIC_XFA && pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
+               return TRUE;
+       if (!FPDFXFA_GetApp()->GetXFAApp())
+               return TRUE;
+
+       IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
+       if (NULL == pXFADocView)
+               return TRUE;
+       IXFA_DocHandler *pXFADocHandler = FPDFXFA_GetApp()->GetXFAApp()->GetDocHandler();
+       
+       CPDF_Document * pPDFDocument = pDocument->GetPDFDoc();
+       if (pDocument == NULL) 
+               return FALSE;
+       CPDF_Dictionary* pRoot = pPDFDocument->GetRoot();
+       if (pRoot == NULL)
+               return FALSE;
+       CPDF_Dictionary* pAcroForm = pRoot->GetDict("AcroForm");
+       if (NULL == pAcroForm)
+               return FALSE;
+       CPDF_Object* pXFA = pAcroForm->GetElement("XFA");
+       if (pXFA == NULL) 
+               return TRUE;
+       if(pXFA->GetType() != PDFOBJ_ARRAY)
+               return FALSE;
+       CPDF_Array* pArray = pXFA->GetArray();
+       if (NULL == 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->GetType() != PDFOBJ_STRING)
+                       continue;
+               if (pPDFObj->GetString() == "form")
+                       iFormIndex = i+1;
+               else if (pPDFObj->GetString() == "datasets")
+                       iDataSetsIndex = i+1;
+               else if (pPDFObj->GetString() == FX_BSTRC("template"))
+                       iTemplate = i + 1;
+       }
+       IXFA_ChecksumContext* pContext = NULL;
+#define XFA_USECKSUM
+#ifdef XFA_USECKSUM
+       //Checksum
+       pContext = XFA_Checksum_Create();
+       FXSYS_assert(pContext);
+       pContext->StartChecksum();
+               
+       //template
+       if (iTemplate > -1)
+       {
+               CPDF_Stream *pTemplateStream = pArray->GetStream(iTemplate);
+               CPDF_StreamAcc streamAcc;
+               streamAcc.LoadAllData(pTemplateStream);
+               FX_LPBYTE pData = (FX_LPBYTE)streamAcc.GetData();
+               FX_DWORD dwSize2 = streamAcc.GetSize();
+               IFX_FileStream *pTemplate = FX_CreateMemoryStream(pData, dwSize2);
+               pContext->UpdateChecksum((IFX_FileRead*)pTemplate);
+               pTemplate->Release();
+       }
+#endif
+       CPDF_Stream* pFormStream = NULL;
+       CPDF_Stream* pDataSetsStream = NULL;
+       if (iFormIndex != -1)
+       {       
+               //Get form CPDF_Stream
+               CPDF_Object* pFormPDFObj = pArray->GetElement(iFormIndex);
+               if (pFormPDFObj->GetType() == PDFOBJ_REFERENCE)
+               {                        
+                       CPDF_Reference* pFormRefObj = (CPDF_Reference*)pFormPDFObj;
+                       CPDF_Object* pFormDircetObj = pFormPDFObj->GetDirect();
+                       if (NULL != pFormDircetObj && pFormDircetObj->GetType() == PDFOBJ_STREAM)
+                       {
+                               pFormStream = (CPDF_Stream*)pFormDircetObj;
+                       }
+               }
+               else if (pFormPDFObj->GetType() == PDFOBJ_STREAM)
+               {
+                       pFormStream = (CPDF_Stream*)pFormPDFObj;
+               }
+       }
+       
+       if (iDataSetsIndex != -1)
+       {
+               //Get datasets CPDF_Stream
+               CPDF_Object* pDataSetsPDFObj = pArray->GetElement(iDataSetsIndex);
+               if (pDataSetsPDFObj->GetType() == PDFOBJ_REFERENCE)
+               {                        
+                       CPDF_Reference* pDataSetsRefObj = (CPDF_Reference*)pDataSetsPDFObj;
+                       CPDF_Object* pDataSetsDircetObj = pDataSetsRefObj->GetDirect();
+                       if (NULL != pDataSetsDircetObj && pDataSetsDircetObj->GetType() == PDFOBJ_STREAM)
+                       {
+                               pDataSetsStream = (CPDF_Stream*)pDataSetsDircetObj;
+                       }
+               }
+               else if (pDataSetsPDFObj->GetType() == PDFOBJ_STREAM)
+               {
+                       pDataSetsStream = (CPDF_Stream*)pDataSetsPDFObj;
+               }
+       } 
+       //end
+       //L"datasets"
+       {
+               IFX_FileStream* pDsfileWrite = FX_CreateMemoryStream();
+               if ( NULL == pDsfileWrite )
+               {
+                       pContext->Release();
+                       pDsfileWrite->Release();
+                       return FALSE;
+               }
+               if (pXFADocHandler->SavePackage(pXFADocView->GetDoc(), CFX_WideStringC(L"datasets"), pDsfileWrite) && pDsfileWrite->GetSize()>0)
+               {
+#ifdef XFA_USECKSUM
+               //Datasets
+               pContext->UpdateChecksum((IFX_FileRead*)pDsfileWrite);
+               pContext->FinishChecksum();
+#endif
+                       CPDF_Dictionary* pDataDict = FX_NEW CPDF_Dictionary;
+                       if (iDataSetsIndex != -1)
+                       {
+                               if (pDataSetsStream)
+                                       pDataSetsStream->InitStream(pDsfileWrite, pDataDict);
+                       }
+                       else
+                       {
+                               CPDF_Stream* pData = FX_NEW CPDF_Stream(NULL, 0, NULL);
+                               pData->InitStream(pDsfileWrite, pDataDict);
+                               FX_DWORD AppStreamobjnum = pPDFDocument->AddIndirectObject(pData);
+                               CPDF_Reference* pRef = (CPDF_Reference*)pPDFDocument->GetIndirectObject(AppStreamobjnum);
+                               {
+                                       iLast = pArray->GetCount() -2;
+                                       pArray->InsertAt(iLast,CPDF_String::Create("datasets"));
+                                       pArray->InsertAt(iLast+1, pData, pPDFDocument);
+                               }
+                       }
+                       fileList.Add(pDsfileWrite);
+               }
+       }
+
+       //L"form"
+       {
+       
+               IFX_FileStream* pfileWrite = FX_CreateMemoryStream();
+               if (NULL == pfileWrite)
+               {
+                       pContext->Release();
+                       return FALSE;
+               }
+               if(pXFADocHandler->SavePackage(pXFADocView->GetDoc(), CFX_WideStringC(L"form"), pfileWrite, pContext) && pfileWrite > 0)
+               {
+                       CPDF_Dictionary* pDataDict = FX_NEW CPDF_Dictionary;
+                       if (iFormIndex != -1)
+                       {
+                               if (pFormStream)
+                                       pFormStream->InitStream(pfileWrite, pDataDict);
+                       }
+                       else
+                       {
+                               CPDF_Stream* pData = FX_NEW CPDF_Stream(NULL, 0, NULL);
+                               pData->InitStream(pfileWrite, pDataDict);
+                               FX_DWORD AppStreamobjnum = pPDFDocument->AddIndirectObject(pData);
+                               CPDF_Reference* pRef = (CPDF_Reference*)pPDFDocument->GetIndirectObject(AppStreamobjnum);
+                               {
+                                       iLast = pArray->GetCount() -2;
+                                       pArray->InsertAt(iLast, CPDF_String::Create("form"));
+                                       pArray->InsertAt(iLast+1, pData, pPDFDocument);
+                               }
+                       }
+                       fileList.Add(pfileWrite);
+               }
+       }
+       pContext->Release();
+       return TRUE;
+}
+
+
+FX_BOOL _SendPostSaveToXFADoc(CPDFXFA_Document* pDocument)
+{
+       if (!pDocument)
+               return FALSE;
+
+       if (pDocument->GetDocType() != DOCTYPE_DYNIMIC_XFA && pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
+               return TRUE;
+       
+       IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
+       if (NULL == 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;
+}
+
+
+FX_BOOL _SendPreSaveToXFADoc(CPDFXFA_Document* pDocument, CFX_PtrArray& fileList)
+{
+       if (pDocument->GetDocType() != DOCTYPE_DYNIMIC_XFA && pDocument->GetDocType() != DOCTYPE_STATIC_XFA)
+               return TRUE;
+       IXFA_DocView* pXFADocView = pDocument->GetXFADocView();
+       if (NULL == 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);
+}
+
+FPDF_BOOL _FPDF_Doc_Save(FPDF_DOCUMENT document, FPDF_FILEWRITE * pFileWrite,FPDF_DWORD flags, FPDF_BOOL bSetVersion,
                                                 int fileVerion)
 {
-       CPDF_Document* pDoc = (CPDF_Document*)document;
-       if (!pDoc) 
+       CPDFXFA_Document* pDoc = (CPDFXFA_Document*)document;
+
+       CFX_PtrArray fileList;
+
+       _SendPreSaveToXFADoc(pDoc, fileList);
+
+       CPDF_Document* pPDFDoc = pDoc->GetPDFDoc();
+       if (!pPDFDoc) 
                return 0;
        
        if ( flags < FPDF_INCREMENTAL || flags > FPDF_REMOVE_SECURITY )
@@ -65,10 +315,10 @@ FPDF_BOOL _FPDF_Doc_Save(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF
                flags = 0;
        }
        
-       CPDF_Creator FileMaker(pDoc);
-       if(bSetVersion)
+       CPDF_Creator FileMaker(pPDFDoc);
+       if (bSetVersion)
                FileMaker.SetFileVersion(fileVerion);
-       if(flags == FPDF_REMOVE_SECURITY)
+       if (flags == FPDF_REMOVE_SECURITY)
        {
                flags =  0;
                FileMaker.RemoveSecurity();
@@ -78,6 +328,17 @@ FPDF_BOOL _FPDF_Doc_Save(FPDF_DOCUMENT document,FPDF_FILEWRITE * pFileWrite,FPDF
        pStreamWrite = new CFX_IFileWrite;
        pStreamWrite->Init( pFileWrite );
        bRet = FileMaker.Create(pStreamWrite, flags);
+
+       _SendPostSaveToXFADoc(pDoc);
+       //pDoc->_ClearChangeMark();
+
+       for (int i = 0; i < fileList.GetSize(); i++)
+       {
+               IFX_FileStream* pFile = (IFX_FileStream*)fileList.GetAt(i);
+               pFile->Release();
+       }
+       fileList.RemoveAll();
+
        delete pStreamWrite;
        return bRet;
 }
@@ -88,9 +349,9 @@ DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveAsCopy( FPDF_DOCUMENT document,FPDF_FILEWRI
        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);
 }
+