blob: e2ef406b0580a75dac18008e36790b725e3e69c7 [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// 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.
Lei Zhanga6d9f0e2015-06-13 00:48:38 -07004
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07005// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
Lei Zhangb4e7f302015-11-06 15:52:32 -08007#include "public/fpdf_ppo.h"
8
Dan Sinclair3ebd1212016-03-09 09:59:23 -05009#include <map>
Lei Zhangaa8bf7e2015-12-24 19:13:32 -080010#include <memory>
tsepez0e606b52016-11-18 16:22:41 -080011#include <utility>
Dan Sinclair3ebd1212016-03-09 09:59:23 -050012#include <vector>
Lei Zhangaa8bf7e2015-12-24 19:13:32 -080013
dsinclair488b7ad2016-10-04 11:55:50 -070014#include "core/fpdfapi/parser/cpdf_array.h"
15#include "core/fpdfapi/parser/cpdf_document.h"
16#include "core/fpdfapi/parser/cpdf_name.h"
17#include "core/fpdfapi/parser/cpdf_number.h"
18#include "core/fpdfapi/parser/cpdf_reference.h"
19#include "core/fpdfapi/parser/cpdf_stream.h"
20#include "core/fpdfapi/parser/cpdf_string.h"
dsinclair114e46a2016-09-29 17:18:21 -070021#include "fpdfsdk/fsdk_define.h"
thestig88d87c12016-11-14 14:06:20 -080022#include "third_party/base/ptr_util.h"
Tom Sepez11d93552016-02-09 09:55:54 -080023#include "third_party/base/stl_util.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070024
thestig88d87c12016-11-14 14:06:20 -080025namespace {
Lei Zhanga6d9f0e2015-06-13 00:48:38 -070026
thestig88d87c12016-11-14 14:06:20 -080027CPDF_Object* PageDictGetInheritableTag(CPDF_Dictionary* pDict,
28 const CFX_ByteString& bsSrcTag) {
tsepez71a452f2016-05-13 17:51:27 -070029 if (!pDict || bsSrcTag.IsEmpty())
Tom Sepezc7e4c4f2015-11-20 09:45:24 -080030 return nullptr;
31 if (!pDict->KeyExist("Parent") || !pDict->KeyExist("Type"))
32 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070033
dsinclair38fd8442016-09-15 10:15:32 -070034 CPDF_Object* pType = pDict->GetObjectFor("Type")->GetDirect();
Dan Sinclair710c9092015-10-21 15:46:10 -040035 if (!ToName(pType))
36 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070037 if (pType->GetString().Compare("Page"))
Tom Sepezc7e4c4f2015-11-20 09:45:24 -080038 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070039
dsinclair38fd8442016-09-15 10:15:32 -070040 CPDF_Dictionary* pp =
41 ToDictionary(pDict->GetObjectFor("Parent")->GetDirect());
Dan Sinclairf1251c12015-10-20 16:24:45 -040042 if (!pp)
43 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070044
tsepez71a452f2016-05-13 17:51:27 -070045 if (pDict->KeyExist(bsSrcTag))
dsinclair38fd8442016-09-15 10:15:32 -070046 return pDict->GetObjectFor(bsSrcTag);
Dan Sinclairf1251c12015-10-20 16:24:45 -040047
Nico Weber9d8ec5a2015-08-04 13:00:21 -070048 while (pp) {
tsepez71a452f2016-05-13 17:51:27 -070049 if (pp->KeyExist(bsSrcTag))
dsinclair38fd8442016-09-15 10:15:32 -070050 return pp->GetObjectFor(bsSrcTag);
Tom Sepezc7e4c4f2015-11-20 09:45:24 -080051 if (!pp->KeyExist("Parent"))
Nico Weber9d8ec5a2015-08-04 13:00:21 -070052 break;
dsinclair38fd8442016-09-15 10:15:32 -070053 pp = ToDictionary(pp->GetObjectFor("Parent")->GetDirect());
Nico Weber9d8ec5a2015-08-04 13:00:21 -070054 }
Dan Sinclairf1251c12015-10-20 16:24:45 -040055 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070056}
57
thestig88d87c12016-11-14 14:06:20 -080058bool CopyInheritable(CPDF_Dictionary* pCurPageDict,
59 CPDF_Dictionary* pSrcPageDict,
60 const CFX_ByteString& key) {
61 if (pCurPageDict->KeyExist(key))
62 return true;
63
64 CPDF_Object* pInheritable = PageDictGetInheritableTag(pSrcPageDict, key);
65 if (!pInheritable)
66 return false;
67
tsepez0e606b52016-11-18 16:22:41 -080068 pCurPageDict->SetFor(key, pInheritable->Clone());
thestig88d87c12016-11-14 14:06:20 -080069 return true;
70}
71
72bool ParserPageRangeString(CFX_ByteString rangstring,
73 std::vector<uint16_t>* pageArray,
74 int nCount) {
75 if (rangstring.IsEmpty())
76 return true;
77
78 rangstring.Remove(' ');
79 int nLength = rangstring.GetLength();
80 CFX_ByteString cbCompareString("0123456789-,");
81 for (int i = 0; i < nLength; ++i) {
82 if (cbCompareString.Find(rangstring[i]) == -1)
83 return false;
84 }
85
86 CFX_ByteString cbMidRange;
87 int nStringFrom = 0;
88 int nStringTo = 0;
89 while (nStringTo < nLength) {
90 nStringTo = rangstring.Find(',', nStringFrom);
91 if (nStringTo == -1)
92 nStringTo = nLength;
93 cbMidRange = rangstring.Mid(nStringFrom, nStringTo - nStringFrom);
94 int nMid = cbMidRange.Find('-');
95 if (nMid == -1) {
96 long lPageNum = atol(cbMidRange.c_str());
97 if (lPageNum <= 0 || lPageNum > nCount)
98 return false;
99 pageArray->push_back((uint16_t)lPageNum);
100 } else {
101 int nStartPageNum = atol(cbMidRange.Mid(0, nMid).c_str());
102 if (nStartPageNum == 0)
103 return false;
104
105 ++nMid;
106 int nEnd = cbMidRange.GetLength() - nMid;
107 if (nEnd == 0)
108 return false;
109
110 int nEndPageNum = atol(cbMidRange.Mid(nMid, nEnd).c_str());
111 if (nStartPageNum < 0 || nStartPageNum > nEndPageNum ||
112 nEndPageNum > nCount) {
113 return false;
114 }
115 for (int i = nStartPageNum; i <= nEndPageNum; ++i) {
116 pageArray->push_back(i);
117 }
118 }
119 nStringFrom = nStringTo + 1;
120 }
121 return true;
122}
123
124} // namespace
125
126class CPDF_PageOrganizer {
127 public:
128 CPDF_PageOrganizer(CPDF_Document* pDestPDFDoc, CPDF_Document* pSrcPDFDoc);
129 ~CPDF_PageOrganizer();
130
131 bool PDFDocInit();
132 bool ExportPage(const std::vector<uint16_t>& pageNums, int nIndex);
133
134 private:
135 using ObjectNumberMap = std::map<uint32_t, uint32_t>;
136
137 bool UpdateReference(CPDF_Object* pObj, ObjectNumberMap* pObjNumberMap);
138 uint32_t GetNewObjId(ObjectNumberMap* pObjNumberMap, CPDF_Reference* pRef);
139
140 CPDF_Document* m_pDestPDFDoc;
141 CPDF_Document* m_pSrcPDFDoc;
142};
143
144CPDF_PageOrganizer::CPDF_PageOrganizer(CPDF_Document* pDestPDFDoc,
145 CPDF_Document* pSrcPDFDoc)
146 : m_pDestPDFDoc(pDestPDFDoc), m_pSrcPDFDoc(pSrcPDFDoc) {}
147
148CPDF_PageOrganizer::~CPDF_PageOrganizer() {}
149
150bool CPDF_PageOrganizer::PDFDocInit() {
151 ASSERT(m_pDestPDFDoc);
152 ASSERT(m_pSrcPDFDoc);
153
154 CPDF_Dictionary* pNewRoot = m_pDestPDFDoc->GetRoot();
155 if (!pNewRoot)
156 return false;
157
158 CPDF_Dictionary* pDocInfoDict = m_pDestPDFDoc->GetInfo();
159 if (!pDocInfoDict)
160 return false;
161
tsepez0e606b52016-11-18 16:22:41 -0800162 pDocInfoDict->SetNewFor<CPDF_String>("Producer", "PDFium", false);
thestig88d87c12016-11-14 14:06:20 -0800163
164 CFX_ByteString cbRootType = pNewRoot->GetStringFor("Type", "");
165 if (cbRootType.IsEmpty())
tsepez0e606b52016-11-18 16:22:41 -0800166 pNewRoot->SetNewFor<CPDF_Name>("Type", "Catalog");
thestig88d87c12016-11-14 14:06:20 -0800167
168 CPDF_Object* pElement = pNewRoot->GetObjectFor("Pages");
169 CPDF_Dictionary* pNewPages =
170 pElement ? ToDictionary(pElement->GetDirect()) : nullptr;
171 if (!pNewPages) {
tsepez5913a6c2016-11-16 17:31:18 -0800172 pNewPages = m_pDestPDFDoc->NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800173 pNewRoot->SetNewFor<CPDF_Reference>("Pages", m_pDestPDFDoc,
174 pNewPages->GetObjNum());
thestig88d87c12016-11-14 14:06:20 -0800175 }
176
177 CFX_ByteString cbPageType = pNewPages->GetStringFor("Type", "");
178 if (cbPageType.IsEmpty())
tsepez0e606b52016-11-18 16:22:41 -0800179 pNewPages->SetNewFor<CPDF_Name>("Type", "Pages");
thestig88d87c12016-11-14 14:06:20 -0800180
181 if (!pNewPages->GetArrayFor("Kids")) {
tsepez0e606b52016-11-18 16:22:41 -0800182 pNewPages->SetNewFor<CPDF_Number>("Count", 0);
183 pNewPages->SetNewFor<CPDF_Reference>(
184 "Kids", m_pDestPDFDoc,
185 m_pDestPDFDoc->NewIndirect<CPDF_Array>()->GetObjNum());
thestig88d87c12016-11-14 14:06:20 -0800186 }
187
188 return true;
189}
190
191bool CPDF_PageOrganizer::ExportPage(const std::vector<uint16_t>& pageNums,
192 int nIndex) {
193 int curpage = nIndex;
194 auto pObjNumberMap = pdfium::MakeUnique<ObjectNumberMap>();
195 int nSize = pdfium::CollectionSize<int>(pageNums);
196 for (int i = 0; i < nSize; ++i) {
197 CPDF_Dictionary* pCurPageDict = m_pDestPDFDoc->CreateNewPage(curpage);
198 CPDF_Dictionary* pSrcPageDict = m_pSrcPDFDoc->GetPage(pageNums[i] - 1);
199 if (!pSrcPageDict || !pCurPageDict)
200 return false;
201
202 // Clone the page dictionary
203 for (const auto& it : *pSrcPageDict) {
204 const CFX_ByteString& cbSrcKeyStr = it.first;
thestig88d87c12016-11-14 14:06:20 -0800205 if (cbSrcKeyStr == "Type" || cbSrcKeyStr == "Parent")
206 continue;
207
tsepez0e606b52016-11-18 16:22:41 -0800208 CPDF_Object* pObj = it.second.get();
209 pCurPageDict->SetFor(cbSrcKeyStr, pObj->Clone());
thestig88d87c12016-11-14 14:06:20 -0800210 }
211
212 // inheritable item
rbpotterd5d8f602017-03-29 16:10:45 -0700213 // Even though some entries are required by the PDF spec, there exist
214 // PDFs that omit them. Set some defaults in this case.
thestig88d87c12016-11-14 14:06:20 -0800215 // 1 MediaBox - required
216 if (!CopyInheritable(pCurPageDict, pSrcPageDict, "MediaBox")) {
rbpotterd5d8f602017-03-29 16:10:45 -0700217 // Search for "CropBox" in the source page dictionary.
218 // If it does not exist, use the default letter size.
thestig88d87c12016-11-14 14:06:20 -0800219 CPDF_Object* pInheritable =
220 PageDictGetInheritableTag(pSrcPageDict, "CropBox");
221 if (pInheritable) {
tsepez0e606b52016-11-18 16:22:41 -0800222 pCurPageDict->SetFor("MediaBox", pInheritable->Clone());
thestig88d87c12016-11-14 14:06:20 -0800223 } else {
rbpotterd5d8f602017-03-29 16:10:45 -0700224 // Make the default size letter size (8.5"x11")
tsepez0e606b52016-11-18 16:22:41 -0800225 CPDF_Array* pArray = pCurPageDict->SetNewFor<CPDF_Array>("MediaBox");
tsepez8a3aa452016-11-16 12:26:06 -0800226 pArray->AddNew<CPDF_Number>(0);
227 pArray->AddNew<CPDF_Number>(0);
228 pArray->AddNew<CPDF_Number>(612);
229 pArray->AddNew<CPDF_Number>(792);
thestig88d87c12016-11-14 14:06:20 -0800230 }
231 }
232
233 // 2 Resources - required
rbpotterd5d8f602017-03-29 16:10:45 -0700234 if (!CopyInheritable(pCurPageDict, pSrcPageDict, "Resources")) {
235 // Use a default empty resources if it does not exist.
236 pCurPageDict->SetNewFor<CPDF_Dictionary>("Resources");
237 }
thestig88d87c12016-11-14 14:06:20 -0800238
239 // 3 CropBox - optional
240 CopyInheritable(pCurPageDict, pSrcPageDict, "CropBox");
241 // 4 Rotate - optional
242 CopyInheritable(pCurPageDict, pSrcPageDict, "Rotate");
243
244 // Update the reference
245 uint32_t dwOldPageObj = pSrcPageDict->GetObjNum();
246 uint32_t dwNewPageObj = pCurPageDict->GetObjNum();
247 (*pObjNumberMap)[dwOldPageObj] = dwNewPageObj;
248 UpdateReference(pCurPageDict, pObjNumberMap.get());
249 ++curpage;
250 }
251
252 return true;
253}
254
tsepez4cf55152016-11-02 14:37:54 -0700255bool CPDF_PageOrganizer::UpdateReference(CPDF_Object* pObj,
tsepez4cf55152016-11-02 14:37:54 -0700256 ObjectNumberMap* pObjNumberMap) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700257 switch (pObj->GetType()) {
Tom Sepez8e5cd192016-01-26 13:20:26 -0800258 case CPDF_Object::REFERENCE: {
Dan Sinclairbf81c142015-10-26 16:54:39 -0400259 CPDF_Reference* pReference = pObj->AsReference();
thestig88d87c12016-11-14 14:06:20 -0800260 uint32_t newobjnum = GetNewObjId(pObjNumberMap, pReference);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700261 if (newobjnum == 0)
tsepez4cf55152016-11-02 14:37:54 -0700262 return false;
thestig88d87c12016-11-14 14:06:20 -0800263 pReference->SetRef(m_pDestPDFDoc, newobjnum);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700264 break;
265 }
Tom Sepez8e5cd192016-01-26 13:20:26 -0800266 case CPDF_Object::DICTIONARY: {
Dan Sinclairf1251c12015-10-20 16:24:45 -0400267 CPDF_Dictionary* pDict = pObj->AsDictionary();
Oliver Changbd292ae2016-01-13 18:46:09 -0800268 auto it = pDict->begin();
269 while (it != pDict->end()) {
270 const CFX_ByteString& key = it->first;
tsepez0e606b52016-11-18 16:22:41 -0800271 CPDF_Object* pNextObj = it->second.get();
Oliver Changbd292ae2016-01-13 18:46:09 -0800272 ++it;
tsepezf86ca382016-09-13 12:23:30 -0700273 if (key == "Parent" || key == "Prev" || key == "First")
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700274 continue;
tsepezf86ca382016-09-13 12:23:30 -0700275 if (!pNextObj)
tsepez4cf55152016-11-02 14:37:54 -0700276 return false;
thestig88d87c12016-11-14 14:06:20 -0800277 if (!UpdateReference(pNextObj, pObjNumberMap))
dsinclair38fd8442016-09-15 10:15:32 -0700278 pDict->RemoveFor(key);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700279 }
280 break;
281 }
Tom Sepez8e5cd192016-01-26 13:20:26 -0800282 case CPDF_Object::ARRAY: {
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400283 CPDF_Array* pArray = pObj->AsArray();
Wei Lie1aebd42016-04-11 10:02:09 -0700284 for (size_t i = 0; i < pArray->GetCount(); ++i) {
tsepezbd567552016-03-29 14:51:50 -0700285 CPDF_Object* pNextObj = pArray->GetObjectAt(i);
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800286 if (!pNextObj)
tsepez4cf55152016-11-02 14:37:54 -0700287 return false;
thestig88d87c12016-11-14 14:06:20 -0800288 if (!UpdateReference(pNextObj, pObjNumberMap))
tsepez4cf55152016-11-02 14:37:54 -0700289 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700290 }
291 break;
292 }
Tom Sepez8e5cd192016-01-26 13:20:26 -0800293 case CPDF_Object::STREAM: {
Dan Sinclairaa435ba2015-10-22 16:45:48 -0400294 CPDF_Stream* pStream = pObj->AsStream();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700295 CPDF_Dictionary* pDict = pStream->GetDict();
thestig88d87c12016-11-14 14:06:20 -0800296 if (!pDict)
tsepez4cf55152016-11-02 14:37:54 -0700297 return false;
thestig88d87c12016-11-14 14:06:20 -0800298 if (!UpdateReference(pDict, pObjNumberMap))
299 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700300 break;
301 }
302 default:
303 break;
304 }
305
tsepez4cf55152016-11-02 14:37:54 -0700306 return true;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700307}
308
thestig88d87c12016-11-14 14:06:20 -0800309uint32_t CPDF_PageOrganizer::GetNewObjId(ObjectNumberMap* pObjNumberMap,
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800310 CPDF_Reference* pRef) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700311 if (!pRef)
312 return 0;
313
tsepezc3255f52016-03-25 14:52:27 -0700314 uint32_t dwObjnum = pRef->GetRefObjNum();
315 uint32_t dwNewObjNum = 0;
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800316 const auto it = pObjNumberMap->find(dwObjnum);
317 if (it != pObjNumberMap->end())
318 dwNewObjNum = it->second;
319 if (dwNewObjNum)
320 return dwNewObjNum;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700321
322 CPDF_Object* pDirect = pRef->GetDirect();
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800323 if (!pDirect)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700324 return 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700325
tsepez335cf092016-11-09 13:28:26 -0800326 std::unique_ptr<CPDF_Object> pClone = pDirect->Clone();
Dan Sinclairf1251c12015-10-20 16:24:45 -0400327 if (CPDF_Dictionary* pDictClone = pClone->AsDictionary()) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700328 if (pDictClone->KeyExist("Type")) {
dsinclair38fd8442016-09-15 10:15:32 -0700329 CFX_ByteString strType = pDictClone->GetStringFor("Type");
tsepez335cf092016-11-09 13:28:26 -0800330 if (!FXSYS_stricmp(strType.c_str(), "Pages"))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700331 return 4;
tsepez335cf092016-11-09 13:28:26 -0800332 if (!FXSYS_stricmp(strType.c_str(), "Page"))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700333 return 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700334 }
335 }
tsepez70c4afd2016-11-15 11:33:44 -0800336 CPDF_Object* pUnownedClone =
337 m_pDestPDFDoc->AddIndirectObject(std::move(pClone));
338 dwNewObjNum = pUnownedClone->GetObjNum();
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800339 (*pObjNumberMap)[dwObjnum] = dwNewObjNum;
thestig88d87c12016-11-14 14:06:20 -0800340 if (!UpdateReference(pUnownedClone, pObjNumberMap))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700341 return 0;
tsepez335cf092016-11-09 13:28:26 -0800342
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800343 return dwNewObjNum;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700344}
345
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700346DLLEXPORT FPDF_BOOL STDCALL FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
347 FPDF_DOCUMENT src_doc,
348 FPDF_BYTESTRING pagerange,
349 int index) {
Tom Sepez471a1032015-10-15 16:17:18 -0700350 CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(dest_doc);
351 if (!dest_doc)
tsepez4cf55152016-11-02 14:37:54 -0700352 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700353
354 CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
355 if (!pSrcDoc)
tsepez4cf55152016-11-02 14:37:54 -0700356 return false;
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800357
Tom Sepez62a70f92016-03-21 15:00:20 -0700358 std::vector<uint16_t> pageArray;
Tom Sepez471a1032015-10-15 16:17:18 -0700359 int nCount = pSrcDoc->GetPageCount();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700360 if (pagerange) {
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800361 if (!ParserPageRangeString(pagerange, &pageArray, nCount))
tsepez4cf55152016-11-02 14:37:54 -0700362 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700363 } else {
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800364 for (int i = 1; i <= nCount; ++i) {
Tom Sepez11d93552016-02-09 09:55:54 -0800365 pageArray.push_back(i);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700366 }
367 }
368
thestig88d87c12016-11-14 14:06:20 -0800369 CPDF_PageOrganizer pageOrg(pDestDoc, pSrcDoc);
370 return pageOrg.PDFDocInit() && pageOrg.ExportPage(pageArray, index);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700371}
372
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700373DLLEXPORT FPDF_BOOL STDCALL FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc,
374 FPDF_DOCUMENT src_doc) {
Tom Sepez471a1032015-10-15 16:17:18 -0700375 CPDF_Document* pDstDoc = CPDFDocumentFromFPDFDocument(dest_doc);
376 if (!pDstDoc)
tsepez4cf55152016-11-02 14:37:54 -0700377 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700378
379 CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
380 if (!pSrcDoc)
tsepez4cf55152016-11-02 14:37:54 -0700381 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700382
383 CPDF_Dictionary* pSrcDict = pSrcDoc->GetRoot();
dsinclair38fd8442016-09-15 10:15:32 -0700384 pSrcDict = pSrcDict->GetDictFor("ViewerPreferences");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700385 if (!pSrcDict)
tsepez4cf55152016-11-02 14:37:54 -0700386 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700387
388 CPDF_Dictionary* pDstDict = pDstDoc->GetRoot();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700389 if (!pDstDict)
tsepez4cf55152016-11-02 14:37:54 -0700390 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700391
tsepez0e606b52016-11-18 16:22:41 -0800392 pDstDict->SetFor("ViewerPreferences", pSrcDict->CloneDirectObject());
tsepez4cf55152016-11-02 14:37:54 -0700393 return true;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700394}