blob: 861b15c2598573b404599e569fdbc04d1a71cc44 [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"
Tom Sepezdc8a2b72017-05-24 13:45:11 -070021#include "core/fxcrt/cfx_unowned_ptr.h"
dsinclair114e46a2016-09-29 17:18:21 -070022#include "fpdfsdk/fsdk_define.h"
thestig88d87c12016-11-14 14:06:20 -080023#include "third_party/base/ptr_util.h"
Tom Sepez11d93552016-02-09 09:55:54 -080024#include "third_party/base/stl_util.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070025
thestig88d87c12016-11-14 14:06:20 -080026namespace {
Lei Zhanga6d9f0e2015-06-13 00:48:38 -070027
thestig88d87c12016-11-14 14:06:20 -080028CPDF_Object* PageDictGetInheritableTag(CPDF_Dictionary* pDict,
29 const CFX_ByteString& bsSrcTag) {
tsepez71a452f2016-05-13 17:51:27 -070030 if (!pDict || bsSrcTag.IsEmpty())
Tom Sepezc7e4c4f2015-11-20 09:45:24 -080031 return nullptr;
32 if (!pDict->KeyExist("Parent") || !pDict->KeyExist("Type"))
33 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070034
dsinclair38fd8442016-09-15 10:15:32 -070035 CPDF_Object* pType = pDict->GetObjectFor("Type")->GetDirect();
Dan Sinclair710c9092015-10-21 15:46:10 -040036 if (!ToName(pType))
37 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070038 if (pType->GetString().Compare("Page"))
Tom Sepezc7e4c4f2015-11-20 09:45:24 -080039 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070040
dsinclair38fd8442016-09-15 10:15:32 -070041 CPDF_Dictionary* pp =
42 ToDictionary(pDict->GetObjectFor("Parent")->GetDirect());
Dan Sinclairf1251c12015-10-20 16:24:45 -040043 if (!pp)
44 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070045
tsepez71a452f2016-05-13 17:51:27 -070046 if (pDict->KeyExist(bsSrcTag))
dsinclair38fd8442016-09-15 10:15:32 -070047 return pDict->GetObjectFor(bsSrcTag);
Dan Sinclairf1251c12015-10-20 16:24:45 -040048
Nico Weber9d8ec5a2015-08-04 13:00:21 -070049 while (pp) {
tsepez71a452f2016-05-13 17:51:27 -070050 if (pp->KeyExist(bsSrcTag))
dsinclair38fd8442016-09-15 10:15:32 -070051 return pp->GetObjectFor(bsSrcTag);
Tom Sepezc7e4c4f2015-11-20 09:45:24 -080052 if (!pp->KeyExist("Parent"))
Nico Weber9d8ec5a2015-08-04 13:00:21 -070053 break;
dsinclair38fd8442016-09-15 10:15:32 -070054 pp = ToDictionary(pp->GetObjectFor("Parent")->GetDirect());
Nico Weber9d8ec5a2015-08-04 13:00:21 -070055 }
Dan Sinclairf1251c12015-10-20 16:24:45 -040056 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070057}
58
thestig88d87c12016-11-14 14:06:20 -080059bool CopyInheritable(CPDF_Dictionary* pCurPageDict,
60 CPDF_Dictionary* pSrcPageDict,
61 const CFX_ByteString& key) {
62 if (pCurPageDict->KeyExist(key))
63 return true;
64
65 CPDF_Object* pInheritable = PageDictGetInheritableTag(pSrcPageDict, key);
66 if (!pInheritable)
67 return false;
68
tsepez0e606b52016-11-18 16:22:41 -080069 pCurPageDict->SetFor(key, pInheritable->Clone());
thestig88d87c12016-11-14 14:06:20 -080070 return true;
71}
72
73bool ParserPageRangeString(CFX_ByteString rangstring,
74 std::vector<uint16_t>* pageArray,
75 int nCount) {
76 if (rangstring.IsEmpty())
77 return true;
78
79 rangstring.Remove(' ');
80 int nLength = rangstring.GetLength();
81 CFX_ByteString cbCompareString("0123456789-,");
82 for (int i = 0; i < nLength; ++i) {
Ryan Harrison12db7512017-08-23 10:39:35 -040083 if (!cbCompareString.Contains(rangstring[i]))
thestig88d87c12016-11-14 14:06:20 -080084 return false;
85 }
86
87 CFX_ByteString cbMidRange;
Ryan Harrisonda129ab2017-08-01 15:16:59 -040088 FX_STRSIZE nStringFrom = 0;
Ryan Harrison12db7512017-08-23 10:39:35 -040089 pdfium::Optional<FX_STRSIZE> nStringTo = 0;
thestig88d87c12016-11-14 14:06:20 -080090 while (nStringTo < nLength) {
91 nStringTo = rangstring.Find(',', nStringFrom);
Ryan Harrison12db7512017-08-23 10:39:35 -040092 if (!nStringTo.has_value())
thestig88d87c12016-11-14 14:06:20 -080093 nStringTo = nLength;
Ryan Harrison12db7512017-08-23 10:39:35 -040094 cbMidRange = rangstring.Mid(nStringFrom, nStringTo.value() - nStringFrom);
95 auto nMid = cbMidRange.Find('-');
96 if (!nMid.has_value()) {
thestig88d87c12016-11-14 14:06:20 -080097 long lPageNum = atol(cbMidRange.c_str());
98 if (lPageNum <= 0 || lPageNum > nCount)
99 return false;
100 pageArray->push_back((uint16_t)lPageNum);
101 } else {
Ryan Harrison12db7512017-08-23 10:39:35 -0400102 int nStartPageNum = atol(cbMidRange.Left(nMid.value()).c_str());
thestig88d87c12016-11-14 14:06:20 -0800103 if (nStartPageNum == 0)
104 return false;
105
Ryan Harrison12db7512017-08-23 10:39:35 -0400106 nMid = nMid.value() + 1;
107 int nEnd = cbMidRange.GetLength() - nMid.value();
thestig88d87c12016-11-14 14:06:20 -0800108 if (nEnd == 0)
109 return false;
110
Ryan Harrison12db7512017-08-23 10:39:35 -0400111 int nEndPageNum = atol(cbMidRange.Mid(nMid.value(), nEnd).c_str());
thestig88d87c12016-11-14 14:06:20 -0800112 if (nStartPageNum < 0 || nStartPageNum > nEndPageNum ||
113 nEndPageNum > nCount) {
114 return false;
115 }
116 for (int i = nStartPageNum; i <= nEndPageNum; ++i) {
117 pageArray->push_back(i);
118 }
119 }
Ryan Harrison12db7512017-08-23 10:39:35 -0400120 nStringFrom = nStringTo.value() + 1;
thestig88d87c12016-11-14 14:06:20 -0800121 }
122 return true;
123}
124
125} // namespace
126
127class CPDF_PageOrganizer {
128 public:
129 CPDF_PageOrganizer(CPDF_Document* pDestPDFDoc, CPDF_Document* pSrcPDFDoc);
130 ~CPDF_PageOrganizer();
131
132 bool PDFDocInit();
133 bool ExportPage(const std::vector<uint16_t>& pageNums, int nIndex);
134
135 private:
136 using ObjectNumberMap = std::map<uint32_t, uint32_t>;
137
138 bool UpdateReference(CPDF_Object* pObj, ObjectNumberMap* pObjNumberMap);
139 uint32_t GetNewObjId(ObjectNumberMap* pObjNumberMap, CPDF_Reference* pRef);
140
Tom Sepezdc8a2b72017-05-24 13:45:11 -0700141 CFX_UnownedPtr<CPDF_Document> m_pDestPDFDoc;
142 CFX_UnownedPtr<CPDF_Document> m_pSrcPDFDoc;
thestig88d87c12016-11-14 14:06:20 -0800143};
144
145CPDF_PageOrganizer::CPDF_PageOrganizer(CPDF_Document* pDestPDFDoc,
146 CPDF_Document* pSrcPDFDoc)
147 : m_pDestPDFDoc(pDestPDFDoc), m_pSrcPDFDoc(pSrcPDFDoc) {}
148
149CPDF_PageOrganizer::~CPDF_PageOrganizer() {}
150
151bool CPDF_PageOrganizer::PDFDocInit() {
152 ASSERT(m_pDestPDFDoc);
153 ASSERT(m_pSrcPDFDoc);
154
155 CPDF_Dictionary* pNewRoot = m_pDestPDFDoc->GetRoot();
156 if (!pNewRoot)
157 return false;
158
159 CPDF_Dictionary* pDocInfoDict = m_pDestPDFDoc->GetInfo();
160 if (!pDocInfoDict)
161 return false;
162
tsepez0e606b52016-11-18 16:22:41 -0800163 pDocInfoDict->SetNewFor<CPDF_String>("Producer", "PDFium", false);
thestig88d87c12016-11-14 14:06:20 -0800164
165 CFX_ByteString cbRootType = pNewRoot->GetStringFor("Type", "");
166 if (cbRootType.IsEmpty())
tsepez0e606b52016-11-18 16:22:41 -0800167 pNewRoot->SetNewFor<CPDF_Name>("Type", "Catalog");
thestig88d87c12016-11-14 14:06:20 -0800168
169 CPDF_Object* pElement = pNewRoot->GetObjectFor("Pages");
170 CPDF_Dictionary* pNewPages =
171 pElement ? ToDictionary(pElement->GetDirect()) : nullptr;
172 if (!pNewPages) {
tsepez5913a6c2016-11-16 17:31:18 -0800173 pNewPages = m_pDestPDFDoc->NewIndirect<CPDF_Dictionary>();
Tom Sepezdc8a2b72017-05-24 13:45:11 -0700174 pNewRoot->SetNewFor<CPDF_Reference>("Pages", m_pDestPDFDoc.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800175 pNewPages->GetObjNum());
thestig88d87c12016-11-14 14:06:20 -0800176 }
177
178 CFX_ByteString cbPageType = pNewPages->GetStringFor("Type", "");
179 if (cbPageType.IsEmpty())
tsepez0e606b52016-11-18 16:22:41 -0800180 pNewPages->SetNewFor<CPDF_Name>("Type", "Pages");
thestig88d87c12016-11-14 14:06:20 -0800181
182 if (!pNewPages->GetArrayFor("Kids")) {
tsepez0e606b52016-11-18 16:22:41 -0800183 pNewPages->SetNewFor<CPDF_Number>("Count", 0);
184 pNewPages->SetNewFor<CPDF_Reference>(
Tom Sepezdc8a2b72017-05-24 13:45:11 -0700185 "Kids", m_pDestPDFDoc.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800186 m_pDestPDFDoc->NewIndirect<CPDF_Array>()->GetObjNum());
thestig88d87c12016-11-14 14:06:20 -0800187 }
188
189 return true;
190}
191
192bool CPDF_PageOrganizer::ExportPage(const std::vector<uint16_t>& pageNums,
193 int nIndex) {
194 int curpage = nIndex;
195 auto pObjNumberMap = pdfium::MakeUnique<ObjectNumberMap>();
196 int nSize = pdfium::CollectionSize<int>(pageNums);
197 for (int i = 0; i < nSize; ++i) {
198 CPDF_Dictionary* pCurPageDict = m_pDestPDFDoc->CreateNewPage(curpage);
199 CPDF_Dictionary* pSrcPageDict = m_pSrcPDFDoc->GetPage(pageNums[i] - 1);
200 if (!pSrcPageDict || !pCurPageDict)
201 return false;
202
203 // Clone the page dictionary
204 for (const auto& it : *pSrcPageDict) {
205 const CFX_ByteString& cbSrcKeyStr = it.first;
thestig88d87c12016-11-14 14:06:20 -0800206 if (cbSrcKeyStr == "Type" || cbSrcKeyStr == "Parent")
207 continue;
208
tsepez0e606b52016-11-18 16:22:41 -0800209 CPDF_Object* pObj = it.second.get();
210 pCurPageDict->SetFor(cbSrcKeyStr, pObj->Clone());
thestig88d87c12016-11-14 14:06:20 -0800211 }
212
213 // inheritable item
rbpotterd5d8f602017-03-29 16:10:45 -0700214 // Even though some entries are required by the PDF spec, there exist
215 // PDFs that omit them. Set some defaults in this case.
thestig88d87c12016-11-14 14:06:20 -0800216 // 1 MediaBox - required
217 if (!CopyInheritable(pCurPageDict, pSrcPageDict, "MediaBox")) {
rbpotterd5d8f602017-03-29 16:10:45 -0700218 // Search for "CropBox" in the source page dictionary.
219 // If it does not exist, use the default letter size.
thestig88d87c12016-11-14 14:06:20 -0800220 CPDF_Object* pInheritable =
221 PageDictGetInheritableTag(pSrcPageDict, "CropBox");
222 if (pInheritable) {
tsepez0e606b52016-11-18 16:22:41 -0800223 pCurPageDict->SetFor("MediaBox", pInheritable->Clone());
thestig88d87c12016-11-14 14:06:20 -0800224 } else {
rbpotterd5d8f602017-03-29 16:10:45 -0700225 // Make the default size letter size (8.5"x11")
tsepez0e606b52016-11-18 16:22:41 -0800226 CPDF_Array* pArray = pCurPageDict->SetNewFor<CPDF_Array>("MediaBox");
tsepez8a3aa452016-11-16 12:26:06 -0800227 pArray->AddNew<CPDF_Number>(0);
228 pArray->AddNew<CPDF_Number>(0);
229 pArray->AddNew<CPDF_Number>(612);
230 pArray->AddNew<CPDF_Number>(792);
thestig88d87c12016-11-14 14:06:20 -0800231 }
232 }
233
234 // 2 Resources - required
rbpotterd5d8f602017-03-29 16:10:45 -0700235 if (!CopyInheritable(pCurPageDict, pSrcPageDict, "Resources")) {
236 // Use a default empty resources if it does not exist.
237 pCurPageDict->SetNewFor<CPDF_Dictionary>("Resources");
238 }
thestig88d87c12016-11-14 14:06:20 -0800239
240 // 3 CropBox - optional
241 CopyInheritable(pCurPageDict, pSrcPageDict, "CropBox");
242 // 4 Rotate - optional
243 CopyInheritable(pCurPageDict, pSrcPageDict, "Rotate");
244
245 // Update the reference
246 uint32_t dwOldPageObj = pSrcPageDict->GetObjNum();
247 uint32_t dwNewPageObj = pCurPageDict->GetObjNum();
248 (*pObjNumberMap)[dwOldPageObj] = dwNewPageObj;
249 UpdateReference(pCurPageDict, pObjNumberMap.get());
250 ++curpage;
251 }
252
253 return true;
254}
255
tsepez4cf55152016-11-02 14:37:54 -0700256bool CPDF_PageOrganizer::UpdateReference(CPDF_Object* pObj,
tsepez4cf55152016-11-02 14:37:54 -0700257 ObjectNumberMap* pObjNumberMap) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700258 switch (pObj->GetType()) {
Tom Sepez8e5cd192016-01-26 13:20:26 -0800259 case CPDF_Object::REFERENCE: {
Dan Sinclairbf81c142015-10-26 16:54:39 -0400260 CPDF_Reference* pReference = pObj->AsReference();
thestig88d87c12016-11-14 14:06:20 -0800261 uint32_t newobjnum = GetNewObjId(pObjNumberMap, pReference);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700262 if (newobjnum == 0)
tsepez4cf55152016-11-02 14:37:54 -0700263 return false;
Tom Sepezdc8a2b72017-05-24 13:45:11 -0700264 pReference->SetRef(m_pDestPDFDoc.Get(), newobjnum);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700265 break;
266 }
Tom Sepez8e5cd192016-01-26 13:20:26 -0800267 case CPDF_Object::DICTIONARY: {
Dan Sinclairf1251c12015-10-20 16:24:45 -0400268 CPDF_Dictionary* pDict = pObj->AsDictionary();
Oliver Changbd292ae2016-01-13 18:46:09 -0800269 auto it = pDict->begin();
270 while (it != pDict->end()) {
271 const CFX_ByteString& key = it->first;
tsepez0e606b52016-11-18 16:22:41 -0800272 CPDF_Object* pNextObj = it->second.get();
Oliver Changbd292ae2016-01-13 18:46:09 -0800273 ++it;
tsepezf86ca382016-09-13 12:23:30 -0700274 if (key == "Parent" || key == "Prev" || key == "First")
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700275 continue;
tsepezf86ca382016-09-13 12:23:30 -0700276 if (!pNextObj)
tsepez4cf55152016-11-02 14:37:54 -0700277 return false;
thestig88d87c12016-11-14 14:06:20 -0800278 if (!UpdateReference(pNextObj, pObjNumberMap))
dsinclair38fd8442016-09-15 10:15:32 -0700279 pDict->RemoveFor(key);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700280 }
281 break;
282 }
Tom Sepez8e5cd192016-01-26 13:20:26 -0800283 case CPDF_Object::ARRAY: {
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400284 CPDF_Array* pArray = pObj->AsArray();
Wei Lie1aebd42016-04-11 10:02:09 -0700285 for (size_t i = 0; i < pArray->GetCount(); ++i) {
tsepezbd567552016-03-29 14:51:50 -0700286 CPDF_Object* pNextObj = pArray->GetObjectAt(i);
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800287 if (!pNextObj)
tsepez4cf55152016-11-02 14:37:54 -0700288 return false;
thestig88d87c12016-11-14 14:06:20 -0800289 if (!UpdateReference(pNextObj, pObjNumberMap))
tsepez4cf55152016-11-02 14:37:54 -0700290 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700291 }
292 break;
293 }
Tom Sepez8e5cd192016-01-26 13:20:26 -0800294 case CPDF_Object::STREAM: {
Dan Sinclairaa435ba2015-10-22 16:45:48 -0400295 CPDF_Stream* pStream = pObj->AsStream();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700296 CPDF_Dictionary* pDict = pStream->GetDict();
thestig88d87c12016-11-14 14:06:20 -0800297 if (!pDict)
tsepez4cf55152016-11-02 14:37:54 -0700298 return false;
thestig88d87c12016-11-14 14:06:20 -0800299 if (!UpdateReference(pDict, pObjNumberMap))
300 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700301 break;
302 }
303 default:
304 break;
305 }
306
tsepez4cf55152016-11-02 14:37:54 -0700307 return true;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700308}
309
thestig88d87c12016-11-14 14:06:20 -0800310uint32_t CPDF_PageOrganizer::GetNewObjId(ObjectNumberMap* pObjNumberMap,
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800311 CPDF_Reference* pRef) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700312 if (!pRef)
313 return 0;
314
tsepezc3255f52016-03-25 14:52:27 -0700315 uint32_t dwObjnum = pRef->GetRefObjNum();
316 uint32_t dwNewObjNum = 0;
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800317 const auto it = pObjNumberMap->find(dwObjnum);
318 if (it != pObjNumberMap->end())
319 dwNewObjNum = it->second;
320 if (dwNewObjNum)
321 return dwNewObjNum;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700322
323 CPDF_Object* pDirect = pRef->GetDirect();
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800324 if (!pDirect)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700325 return 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700326
tsepez335cf092016-11-09 13:28:26 -0800327 std::unique_ptr<CPDF_Object> pClone = pDirect->Clone();
Dan Sinclairf1251c12015-10-20 16:24:45 -0400328 if (CPDF_Dictionary* pDictClone = pClone->AsDictionary()) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700329 if (pDictClone->KeyExist("Type")) {
dsinclair38fd8442016-09-15 10:15:32 -0700330 CFX_ByteString strType = pDictClone->GetStringFor("Type");
tsepez335cf092016-11-09 13:28:26 -0800331 if (!FXSYS_stricmp(strType.c_str(), "Pages"))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700332 return 4;
tsepez335cf092016-11-09 13:28:26 -0800333 if (!FXSYS_stricmp(strType.c_str(), "Page"))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700334 return 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700335 }
336 }
tsepez70c4afd2016-11-15 11:33:44 -0800337 CPDF_Object* pUnownedClone =
338 m_pDestPDFDoc->AddIndirectObject(std::move(pClone));
339 dwNewObjNum = pUnownedClone->GetObjNum();
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800340 (*pObjNumberMap)[dwObjnum] = dwNewObjNum;
thestig88d87c12016-11-14 14:06:20 -0800341 if (!UpdateReference(pUnownedClone, pObjNumberMap))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700342 return 0;
tsepez335cf092016-11-09 13:28:26 -0800343
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800344 return dwNewObjNum;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700345}
346
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400347FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
348 FPDF_DOCUMENT src_doc,
349 FPDF_BYTESTRING pagerange,
350 int index) {
Tom Sepez471a1032015-10-15 16:17:18 -0700351 CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(dest_doc);
352 if (!dest_doc)
tsepez4cf55152016-11-02 14:37:54 -0700353 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700354
355 CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
356 if (!pSrcDoc)
tsepez4cf55152016-11-02 14:37:54 -0700357 return false;
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800358
Tom Sepez62a70f92016-03-21 15:00:20 -0700359 std::vector<uint16_t> pageArray;
Tom Sepez471a1032015-10-15 16:17:18 -0700360 int nCount = pSrcDoc->GetPageCount();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700361 if (pagerange) {
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800362 if (!ParserPageRangeString(pagerange, &pageArray, nCount))
tsepez4cf55152016-11-02 14:37:54 -0700363 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700364 } else {
Tom Sepezc7e4c4f2015-11-20 09:45:24 -0800365 for (int i = 1; i <= nCount; ++i) {
Tom Sepez11d93552016-02-09 09:55:54 -0800366 pageArray.push_back(i);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700367 }
368 }
369
thestig88d87c12016-11-14 14:06:20 -0800370 CPDF_PageOrganizer pageOrg(pDestDoc, pSrcDoc);
371 return pageOrg.PDFDocInit() && pageOrg.ExportPage(pageArray, index);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700372}
373
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400374FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
375FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc) {
Tom Sepez471a1032015-10-15 16:17:18 -0700376 CPDF_Document* pDstDoc = CPDFDocumentFromFPDFDocument(dest_doc);
377 if (!pDstDoc)
tsepez4cf55152016-11-02 14:37:54 -0700378 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700379
380 CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
381 if (!pSrcDoc)
tsepez4cf55152016-11-02 14:37:54 -0700382 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700383
384 CPDF_Dictionary* pSrcDict = pSrcDoc->GetRoot();
dsinclair38fd8442016-09-15 10:15:32 -0700385 pSrcDict = pSrcDict->GetDictFor("ViewerPreferences");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700386 if (!pSrcDict)
tsepez4cf55152016-11-02 14:37:54 -0700387 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700388
389 CPDF_Dictionary* pDstDict = pDstDoc->GetRoot();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700390 if (!pDstDict)
tsepez4cf55152016-11-02 14:37:54 -0700391 return false;
Tom Sepez471a1032015-10-15 16:17:18 -0700392
tsepez0e606b52016-11-18 16:22:41 -0800393 pDstDict->SetFor("ViewerPreferences", pSrcDict->CloneDirectObject());
tsepez4cf55152016-11-02 14:37:54 -0700394 return true;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700395}