Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
fpdf_save.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
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 <utility>
10#include <vector>
11
12#include "build/build_config.h"
13#include "core/fpdfapi/edit/cpdf_creator.h"
14#include "core/fpdfapi/parser/cpdf_array.h"
15#include "core/fpdfapi/parser/cpdf_dictionary.h"
16#include "core/fpdfapi/parser/cpdf_document.h"
17#include "core/fpdfapi/parser/cpdf_reference.h"
18#include "core/fpdfapi/parser/cpdf_stream_acc.h"
19#include "core/fpdfapi/parser/cpdf_string.h"
20#include "core/fxcrt/fx_extension.h"
21#include "core/fxcrt/stl_util.h"
22#include "fpdfsdk/cpdfsdk_filewriteadapter.h"
23#include "fpdfsdk/cpdfsdk_helpers.h"
24#include "public/fpdf_edit.h"
25#include "third_party/abseil-cpp/absl/types/optional.h"
26
27#ifdef PDF_ENABLE_XFA
28#include "core/fpdfapi/parser/cpdf_stream.h"
29#include "core/fxcrt/cfx_memorystream.h"
30#include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
31#include "public/fpdf_formfill.h"
32#endif
33
34namespace {
35
36#ifdef PDF_ENABLE_XFA
37bool SaveXFADocumentData(CPDFXFA_Context* pContext,
38 std::vector<RetainPtr<IFX_SeekableStream>>* fileList) {
39 if (!pContext)
40 return false;
41
42 if (!pContext->ContainsExtensionForm())
43 return true;
44
45 CPDF_Document* pPDFDocument = pContext->GetPDFDoc();
46 if (!pPDFDocument)
47 return false;
48
49 RetainPtr<CPDF_Dictionary> pRoot = pPDFDocument->GetMutableRoot();
50 if (!pRoot)
51 return false;
52
53 RetainPtr<CPDF_Dictionary> pAcroForm = pRoot->GetMutableDictFor("AcroForm");
54 if (!pAcroForm)
55 return false;
56
57 RetainPtr<CPDF_Object> pXFA = pAcroForm->GetMutableObjectFor("XFA");
58 if (!pXFA)
59 return true;
60
61 CPDF_Array* pArray = pXFA->AsMutableArray();
62 if (!pArray)
63 return false;
64
65 int size = fxcrt::CollectionSize<int>(*pArray);
66 int iFormIndex = -1;
67 int iDataSetsIndex = -1;
68 for (int i = 0; i < size - 1; i++) {
69 RetainPtr<const CPDF_Object> pPDFObj = pArray->GetObjectAt(i);
70 if (!pPDFObj->IsString())
71 continue;
72 if (pPDFObj->GetString() == "form")
73 iFormIndex = i + 1;
74 else if (pPDFObj->GetString() == "datasets")
75 iDataSetsIndex = i + 1;
76 }
77
78 RetainPtr<CPDF_Stream> pFormStream;
79 if (iFormIndex != -1) {
80 // Get form CPDF_Stream
81 RetainPtr<CPDF_Object> pFormPDFObj = pArray->GetMutableObjectAt(iFormIndex);
82 if (pFormPDFObj->IsReference()) {
83 RetainPtr<CPDF_Object> pFormDirectObj = pFormPDFObj->GetMutableDirect();
84 if (pFormDirectObj && pFormDirectObj->IsStream()) {
85 pFormStream.Reset(pFormDirectObj->AsMutableStream());
86 }
87 } else if (pFormPDFObj->IsStream()) {
88 pFormStream.Reset(pFormPDFObj->AsMutableStream());
89 }
90 }
91
92 RetainPtr<CPDF_Stream> pDataSetsStream;
93 if (iDataSetsIndex != -1) {
94 // Get datasets CPDF_Stream
95 RetainPtr<CPDF_Object> pDataSetsPDFObj =
96 pArray->GetMutableObjectAt(iDataSetsIndex);
97 if (pDataSetsPDFObj->IsReference()) {
98 CPDF_Reference* pDataSetsRefObj = pDataSetsPDFObj->AsMutableReference();
99 RetainPtr<CPDF_Object> pDataSetsDirectObj =
100 pDataSetsRefObj->GetMutableDirect();
101 if (pDataSetsDirectObj && pDataSetsDirectObj->IsStream()) {
102 pDataSetsStream.Reset(pDataSetsDirectObj->AsMutableStream());
103 }
104 } else if (pDataSetsPDFObj->IsStream()) {
105 pDataSetsStream.Reset(pDataSetsPDFObj->AsMutableStream());
106 }
107 }
108 // L"datasets"
109 {
110 RetainPtr<IFX_SeekableStream> pFileWrite =
111 pdfium::MakeRetain<CFX_MemoryStream>();
112 if (pContext->SaveDatasetsPackage(pFileWrite) &&
113 pFileWrite->GetSize() > 0) {
114 auto pDataDict = pPDFDocument->New<CPDF_Dictionary>();
115 if (iDataSetsIndex != -1) {
116 if (pDataSetsStream) {
117 pDataSetsStream->InitStreamFromFile(pFileWrite, std::move(pDataDict));
118 }
119 } else {
120 auto pData = pPDFDocument->NewIndirect<CPDF_Stream>();
121 pData->InitStreamFromFile(pFileWrite, std::move(pDataDict));
122 int iLast = fxcrt::CollectionSize<int>(*pArray) - 2;
123 pArray->InsertNewAt<CPDF_String>(iLast, "datasets", false);
124 pArray->InsertNewAt<CPDF_Reference>(iLast + 1, pPDFDocument,
125 pData->GetObjNum());
126 }
127 fileList->push_back(std::move(pFileWrite));
128 }
129 }
130 // L"form"
131 {
132 RetainPtr<IFX_SeekableStream> pFileWrite =
133 pdfium::MakeRetain<CFX_MemoryStream>();
134 if (pContext->SaveFormPackage(pFileWrite) && pFileWrite->GetSize() > 0) {
135 auto pDataDict = pPDFDocument->New<CPDF_Dictionary>();
136 if (iFormIndex != -1) {
137 if (pFormStream)
138 pFormStream->InitStreamFromFile(pFileWrite, std::move(pDataDict));
139 } else {
140 auto pData = pPDFDocument->NewIndirect<CPDF_Stream>();
141 pData->InitStreamFromFile(pFileWrite, std::move(pDataDict));
142 int iLast = fxcrt::CollectionSize<int>(*pArray) - 2;
143 pArray->InsertNewAt<CPDF_String>(iLast, "form", false);
144 pArray->InsertNewAt<CPDF_Reference>(iLast + 1, pPDFDocument,
145 pData->GetObjNum());
146 }
147 fileList->push_back(std::move(pFileWrite));
148 }
149 }
150 return true;
151}
152#endif // PDF_ENABLE_XFA
153
154bool DoDocSave(FPDF_DOCUMENT document,
155 FPDF_FILEWRITE* pFileWrite,
156 FPDF_DWORD flags,
157 absl::optional<int> version) {
159 if (!pPDFDoc)
160 return false;
161
162#ifdef PDF_ENABLE_XFA
163 auto* pContext = static_cast<CPDFXFA_Context*>(pPDFDoc->GetExtension());
164 if (pContext) {
165 std::vector<RetainPtr<IFX_SeekableStream>> fileList;
166 pContext->SendPreSaveToXFADoc(&fileList);
167 SaveXFADocumentData(pContext, &fileList);
168 }
169#endif // PDF_ENABLE_XFA
170
171 if (flags < FPDF_INCREMENTAL || flags > FPDF_REMOVE_SECURITY)
172 flags = 0;
173
174 CPDF_Creator fileMaker(
175 pPDFDoc, pdfium::MakeRetain<CPDFSDK_FileWriteAdapter>(pFileWrite));
176 if (version.has_value())
177 fileMaker.SetFileVersion(version.value());
178 if (flags == FPDF_REMOVE_SECURITY) {
179 flags = 0;
180 fileMaker.RemoveSecurity();
181 }
182
183 bool bRet = fileMaker.Create(static_cast<uint32_t>(flags));
184
185#ifdef PDF_ENABLE_XFA
186 if (pContext)
187 pContext->SendPostSaveToXFADoc();
188#endif // PDF_ENABLE_XFA
189
190 return bRet;
191}
192
193} // namespace
194
195FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document,
196 FPDF_FILEWRITE* pFileWrite,
197 FPDF_DWORD flags) {
198 return DoDocSave(document, pFileWrite, flags, {});
199}
200
202FPDF_SaveWithVersion(FPDF_DOCUMENT document,
203 FPDF_FILEWRITE* pFileWrite,
204 FPDF_DWORD flags,
205 int fileVersion) {
206 return DoDocSave(document, pFileWrite, flags, fileVersion);
207}
bool SetFileVersion(int32_t fileVersion)
void RemoveSecurity()
bool Create(uint32_t flags)
CPDF_Document * CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc)
#define FPDF_INCREMENTAL
Definition fpdf_save.h:45
#define FPDF_REMOVE_SECURITY
Definition fpdf_save.h:47
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document, FPDF_FILEWRITE *pFileWrite, FPDF_DWORD flags)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveWithVersion(FPDF_DOCUMENT document, FPDF_FILEWRITE *pFileWrite, FPDF_DWORD flags, int fileVersion)
#define FPDF_CALLCONV
Definition fpdfview.h:227
#define FPDF_EXPORT
Definition fpdfview.h:221