blob: 0623e7ee85c3ca33b26afe2c3a8675067d3a135e [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
Tom Sepez1ed8a212015-05-11 15:25:39 -07007#include "../../public/fpdf_ppo.h"
Bo Xufdc00a72014-10-28 23:03:33 -07008#include "../include/fpdfxfa/fpdfxfa_doc.h"
Lei Zhang8241df72015-11-06 14:38:48 -08009#include "../include/fsdk_define.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070010
Nico Weber9d8ec5a2015-08-04 13:00:21 -070011class CPDF_PageOrganizer {
12 public:
13 CPDF_PageOrganizer();
14 ~CPDF_PageOrganizer();
Lei Zhanga6d9f0e2015-06-13 00:48:38 -070015
Nico Weber9d8ec5a2015-08-04 13:00:21 -070016 public:
17 FX_BOOL PDFDocInit(CPDF_Document* pDestPDFDoc, CPDF_Document* pSrcPDFDoc);
18 FX_BOOL ExportPage(CPDF_Document* pSrcPDFDoc,
19 CFX_WordArray* nPageNum,
20 CPDF_Document* pDestPDFDoc,
21 int nIndex);
22 CPDF_Object* PageDictGetInheritableTag(CPDF_Dictionary* pDict,
23 CFX_ByteString nSrctag);
24 FX_BOOL UpdateReference(CPDF_Object* pObj,
25 CPDF_Document* pDoc,
26 CFX_MapPtrToPtr* pMapPtrToPtr);
27 int GetNewObjId(CPDF_Document* pDoc,
28 CFX_MapPtrToPtr* pMapPtrToPtr,
29 CPDF_Reference* pRef);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070030};
31
Nico Weber9d8ec5a2015-08-04 13:00:21 -070032CPDF_PageOrganizer::CPDF_PageOrganizer() {}
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070033
Nico Weber9d8ec5a2015-08-04 13:00:21 -070034CPDF_PageOrganizer::~CPDF_PageOrganizer() {}
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070035
Nico Weber9d8ec5a2015-08-04 13:00:21 -070036FX_BOOL CPDF_PageOrganizer::PDFDocInit(CPDF_Document* pDestPDFDoc,
37 CPDF_Document* pSrcPDFDoc) {
38 if (!pDestPDFDoc || !pSrcPDFDoc)
39 return false;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070040
Nico Weber9d8ec5a2015-08-04 13:00:21 -070041 CPDF_Dictionary* pNewRoot = pDestPDFDoc->GetRoot();
42 if (!pNewRoot)
Tom Sepez2f2ffec2015-07-23 14:42:09 -070043 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070044
45 // Set the document information////////////////////////////////////////////
46
47 CPDF_Dictionary* DInfoDict = pDestPDFDoc->GetInfo();
48
49 if (!DInfoDict)
50 return FALSE;
51
52 CFX_ByteString producerstr;
53 producerstr.Format("PDFium");
54 DInfoDict->SetAt("Producer", new CPDF_String(producerstr));
55
56 // Set type////////////////////////////////////////////////////////////////
57 CFX_ByteString cbRootType = pNewRoot->GetString("Type", "");
58 if (cbRootType.Equal("")) {
59 pNewRoot->SetAt("Type", new CPDF_Name("Catalog"));
60 }
61
Dan Sinclairf1251c12015-10-20 16:24:45 -040062 CPDF_Dictionary* pNewPages = ToDictionary(
63 pNewRoot->GetElement("Pages") ? pNewRoot->GetElement("Pages")->GetDirect()
64 : nullptr);
65
Nico Weber9d8ec5a2015-08-04 13:00:21 -070066 if (!pNewPages) {
67 pNewPages = new CPDF_Dictionary;
68 FX_DWORD NewPagesON = pDestPDFDoc->AddIndirectObject(pNewPages);
69 pNewRoot->SetAt("Pages", new CPDF_Reference(pDestPDFDoc, NewPagesON));
70 }
71
72 CFX_ByteString cbPageType = pNewPages->GetString("Type", "");
73 if (cbPageType.Equal("")) {
74 pNewPages->SetAt("Type", new CPDF_Name("Pages"));
75 }
76
77 CPDF_Array* pKeysArray = pNewPages->GetArray("Kids");
78 if (pKeysArray == NULL) {
79 CPDF_Array* pNewKids = new CPDF_Array;
80 FX_DWORD Kidsobjnum = -1;
81 Kidsobjnum =
82 pDestPDFDoc->AddIndirectObject(pNewKids); //, Kidsobjnum, Kidsgennum);
83
84 pNewPages->SetAt(
85 "Kids", new CPDF_Reference(pDestPDFDoc, Kidsobjnum)); //, Kidsgennum));
86 pNewPages->SetAt("Count", new CPDF_Number(0));
87 }
88
89 return true;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070090}
91
Nico Weber9d8ec5a2015-08-04 13:00:21 -070092FX_BOOL CPDF_PageOrganizer::ExportPage(CPDF_Document* pSrcPDFDoc,
93 CFX_WordArray* nPageNum,
94 CPDF_Document* pDestPDFDoc,
95 int nIndex) {
96 int curpage = nIndex;
97
98 CFX_MapPtrToPtr* pMapPtrToPtr = new CFX_MapPtrToPtr;
99 pMapPtrToPtr->InitHashTable(1001);
100
101 for (int i = 0; i < nPageNum->GetSize(); i++) {
102 CPDF_Dictionary* pCurPageDict = pDestPDFDoc->CreateNewPage(curpage);
103 CPDF_Dictionary* pSrcPageDict = pSrcPDFDoc->GetPage(nPageNum->GetAt(i) - 1);
104 if (!pSrcPageDict || !pCurPageDict) {
105 delete pMapPtrToPtr;
106 return FALSE;
107 }
108
109 // Clone the page dictionary///////////
110 FX_POSITION SrcPos = pSrcPageDict->GetStartPos();
111 while (SrcPos) {
112 CFX_ByteString cbSrcKeyStr;
113 CPDF_Object* pObj = pSrcPageDict->GetNextElement(SrcPos, cbSrcKeyStr);
114 if (cbSrcKeyStr.Compare(("Type")) && cbSrcKeyStr.Compare(("Parent"))) {
115 if (pCurPageDict->KeyExist(cbSrcKeyStr))
116 pCurPageDict->RemoveAt(cbSrcKeyStr);
117 pCurPageDict->SetAt(cbSrcKeyStr, pObj->Clone());
118 }
119 }
120
121 // inheritable item///////////////////////
122 CPDF_Object* pInheritable = NULL;
123 // 1 MediaBox //required
124 if (!pCurPageDict->KeyExist("MediaBox")) {
125 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "MediaBox");
126 if (!pInheritable) {
127 // Search the "CropBox" from source page dictionary, if not exists,we
128 // take the letter size.
129 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "CropBox");
130 if (pInheritable)
131 pCurPageDict->SetAt("MediaBox", pInheritable->Clone());
132 else {
133 // Make the default size to be letter size (8.5'x11')
134 CPDF_Array* pArray = new CPDF_Array;
135 pArray->AddNumber(0);
136 pArray->AddNumber(0);
137 pArray->AddNumber(612);
138 pArray->AddNumber(792);
139 pCurPageDict->SetAt("MediaBox", pArray);
140 }
141 } else
142 pCurPageDict->SetAt("MediaBox", pInheritable->Clone());
143 }
144 // 2 Resources //required
145 if (!pCurPageDict->KeyExist("Resources")) {
146 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "Resources");
147 if (!pInheritable) {
148 delete pMapPtrToPtr;
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700149 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700150 }
151 pCurPageDict->SetAt("Resources", pInheritable->Clone());
152 }
153 // 3 CropBox //Optional
154 if (!pCurPageDict->KeyExist("CropBox")) {
155 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "CropBox");
156 if (pInheritable)
157 pCurPageDict->SetAt("CropBox", pInheritable->Clone());
158 }
159 // 4 Rotate //Optional
160 if (!pCurPageDict->KeyExist("Rotate")) {
161 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "Rotate");
162 if (pInheritable)
163 pCurPageDict->SetAt("Rotate", pInheritable->Clone());
164 }
165
166 /////////////////////////////////////////////
167 // Update the reference
168 FX_DWORD dwOldPageObj = pSrcPageDict->GetObjNum();
169 FX_DWORD dwNewPageObj = pCurPageDict->GetObjNum();
170
171 pMapPtrToPtr->SetAt((void*)(uintptr_t)dwOldPageObj,
172 (void*)(uintptr_t)dwNewPageObj);
173
174 UpdateReference(pCurPageDict, pDestPDFDoc, pMapPtrToPtr);
175 curpage++;
176 }
177
178 delete pMapPtrToPtr;
179 return TRUE;
180}
181
182CPDF_Object* CPDF_PageOrganizer::PageDictGetInheritableTag(
183 CPDF_Dictionary* pDict,
184 CFX_ByteString nSrctag) {
185 if (!pDict || !pDict->KeyExist("Type") || nSrctag.IsEmpty())
186 return NULL;
187
188 CPDF_Object* pType = pDict->GetElement("Type")->GetDirect();
Dan Sinclair710c9092015-10-21 15:46:10 -0400189 if (!ToName(pType))
190 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700191 if (pType->GetString().Compare("Page"))
192 return NULL;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700193 if (!pDict->KeyExist("Parent"))
194 return NULL;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700195
Dan Sinclairf1251c12015-10-20 16:24:45 -0400196 CPDF_Dictionary* pp = ToDictionary(pDict->GetElement("Parent")->GetDirect());
197 if (!pp)
198 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700199
200 if (pDict->KeyExist((const char*)nSrctag))
201 return pDict->GetElement((const char*)nSrctag);
Dan Sinclairf1251c12015-10-20 16:24:45 -0400202
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700203 while (pp) {
204 if (pp->KeyExist((const char*)nSrctag))
205 return pp->GetElement((const char*)nSrctag);
Dan Sinclairf1251c12015-10-20 16:24:45 -0400206 if (!pp->KeyExist("Parent")) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700207 break;
Dan Sinclairf1251c12015-10-20 16:24:45 -0400208 }
209 pp = ToDictionary(pp->GetElement("Parent")->GetDirect());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700210 }
Dan Sinclairf1251c12015-10-20 16:24:45 -0400211 return nullptr;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700212}
213
214FX_BOOL CPDF_PageOrganizer::UpdateReference(CPDF_Object* pObj,
215 CPDF_Document* pDoc,
216 CFX_MapPtrToPtr* pMapPtrToPtr) {
217 switch (pObj->GetType()) {
218 case PDFOBJ_REFERENCE: {
Dan Sinclairbf81c142015-10-26 16:54:39 -0400219 CPDF_Reference* pReference = pObj->AsReference();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700220 int newobjnum = GetNewObjId(pDoc, pMapPtrToPtr, pReference);
221 if (newobjnum == 0)
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700222 return FALSE;
Dan Sinclairbf81c142015-10-26 16:54:39 -0400223 pReference->SetRef(pDoc, newobjnum);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700224 break;
225 }
226 case PDFOBJ_DICTIONARY: {
Dan Sinclairf1251c12015-10-20 16:24:45 -0400227 CPDF_Dictionary* pDict = pObj->AsDictionary();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700228
229 FX_POSITION pos = pDict->GetStartPos();
230 while (pos) {
231 CFX_ByteString key("");
232 CPDF_Object* pNextObj = pDict->GetNextElement(pos, key);
233 if (!FXSYS_strcmp(key, "Parent") || !FXSYS_strcmp(key, "Prev") ||
234 !FXSYS_strcmp(key, "First"))
235 continue;
236 if (pNextObj) {
237 if (!UpdateReference(pNextObj, pDoc, pMapPtrToPtr))
238 pDict->RemoveAt(key);
239 } else
240 return FALSE;
241 }
242 break;
243 }
244 case PDFOBJ_ARRAY: {
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400245 CPDF_Array* pArray = pObj->AsArray();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700246 FX_DWORD count = pArray->GetCount();
247 for (FX_DWORD i = 0; i < count; i++) {
248 CPDF_Object* pNextObj = pArray->GetElement(i);
249 if (pNextObj) {
250 if (!UpdateReference(pNextObj, pDoc, pMapPtrToPtr))
251 return FALSE;
252 } else
253 return FALSE;
254 }
255 break;
256 }
257 case PDFOBJ_STREAM: {
Dan Sinclairaa435ba2015-10-22 16:45:48 -0400258 CPDF_Stream* pStream = pObj->AsStream();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700259 CPDF_Dictionary* pDict = pStream->GetDict();
260 if (pDict) {
261 if (!UpdateReference(pDict, pDoc, pMapPtrToPtr))
262 return FALSE;
263 } else
264 return FALSE;
265 break;
266 }
267 default:
268 break;
269 }
270
271 return TRUE;
272}
273
274int CPDF_PageOrganizer::GetNewObjId(CPDF_Document* pDoc,
275 CFX_MapPtrToPtr* pMapPtrToPtr,
276 CPDF_Reference* pRef) {
277 if (!pRef)
278 return 0;
279
280 size_t dwObjnum = pRef->GetRefObjNum();
281 size_t dwNewObjNum = 0;
282
283 pMapPtrToPtr->Lookup((void*)dwObjnum, (void*&)dwNewObjNum);
284 if (dwNewObjNum) {
285 return (int)dwNewObjNum;
286 }
287
288 CPDF_Object* pDirect = pRef->GetDirect();
289 if (!pDirect) {
290 return 0;
291 }
292
293 CPDF_Object* pClone = pDirect->Clone();
294 if (!pClone) {
295 return 0;
296 }
297
Dan Sinclairf1251c12015-10-20 16:24:45 -0400298 if (CPDF_Dictionary* pDictClone = pClone->AsDictionary()) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700299 if (pDictClone->KeyExist("Type")) {
300 CFX_ByteString strType = pDictClone->GetString("Type");
301 if (!FXSYS_stricmp(strType, "Pages")) {
302 pDictClone->Release();
303 return 4;
304 } else if (!FXSYS_stricmp(strType, "Page")) {
305 pDictClone->Release();
306 return 0;
307 }
308 }
309 }
310
311 dwNewObjNum = pDoc->AddIndirectObject(pClone);
312 pMapPtrToPtr->SetAt((void*)dwObjnum, (void*)dwNewObjNum);
313 if (!UpdateReference(pClone, pDoc, pMapPtrToPtr)) {
314 pClone->Release();
315 return 0;
316 }
317
318 return (int)dwNewObjNum;
319}
320
321FPDF_BOOL ParserPageRangeString(CFX_ByteString rangstring,
322 CFX_WordArray* pageArray,
323 int nCount) {
324 if (rangstring.GetLength() != 0) {
325 rangstring.Remove(' ');
326 int nLength = rangstring.GetLength();
327 CFX_ByteString cbCompareString("0123456789-,");
328 for (int i = 0; i < nLength; i++) {
329 if (cbCompareString.Find(rangstring[i]) == -1)
330 return FALSE;
331 }
332 CFX_ByteString cbMidRange;
333 int nStringFrom = 0;
334 int nStringTo = 0;
335 while (nStringTo < nLength) {
336 nStringTo = rangstring.Find(',', nStringFrom);
337 if (nStringTo == -1) {
338 nStringTo = nLength;
339 }
340 cbMidRange = rangstring.Mid(nStringFrom, nStringTo - nStringFrom);
341
342 int nMid = cbMidRange.Find('-');
343 if (nMid == -1) {
344 long lPageNum = atol(cbMidRange);
345 if (lPageNum <= 0 || lPageNum > nCount)
346 return FALSE;
347
348 pageArray->Add((FX_WORD)lPageNum);
349 } else {
350 int nStartPageNum = atol(cbMidRange.Mid(0, nMid));
351 if (nStartPageNum == 0)
352 return FALSE;
353
354 nMid = nMid + 1;
355 int nEnd = cbMidRange.GetLength() - nMid;
356 if (nEnd == 0)
357 return FALSE;
358
359 int nEndPageNum = atol(cbMidRange.Mid(nMid, nEnd));
360 if (nStartPageNum < 0 || nStartPageNum > nEndPageNum ||
361 nEndPageNum > nCount)
362 return FALSE;
363
364 for (int nIndex = nStartPageNum; nIndex <= nEndPageNum; ++nIndex)
365 pageArray->Add(nIndex);
366 }
367 nStringFrom = nStringTo + 1;
368 }
369 }
370 return TRUE;
371}
372
373DLLEXPORT FPDF_BOOL STDCALL FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
374 FPDF_DOCUMENT src_doc,
375 FPDF_BYTESTRING pagerange,
376 int index) {
Tom Sepez471a1032015-10-15 16:17:18 -0700377 CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(dest_doc);
378 if (!dest_doc)
379 return FALSE;
380
381 CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
382 if (!pSrcDoc)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700383 return FALSE;
384 CFX_WordArray pageArray;
Tom Sepez471a1032015-10-15 16:17:18 -0700385 int nCount = pSrcDoc->GetPageCount();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700386 if (pagerange) {
387 if (ParserPageRangeString(pagerange, &pageArray, nCount) == FALSE)
388 return FALSE;
389 } else {
390 for (int i = 1; i <= nCount; i++) {
391 pageArray.Add(i);
392 }
393 }
394
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700395 CPDF_PageOrganizer pageOrg;
Tom Sepez471a1032015-10-15 16:17:18 -0700396 pageOrg.PDFDocInit(pDestDoc, pSrcDoc);
397 return pageOrg.ExportPage(pSrcDoc, &pageArray, pDestDoc, index);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700398}
399
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700400DLLEXPORT FPDF_BOOL STDCALL FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc,
401 FPDF_DOCUMENT src_doc) {
Tom Sepez471a1032015-10-15 16:17:18 -0700402 CPDF_Document* pDstDoc = CPDFDocumentFromFPDFDocument(dest_doc);
403 if (!pDstDoc)
404 return FALSE;
405
406 CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
407 if (!pSrcDoc)
408 return FALSE;
409
410 CPDF_Dictionary* pSrcDict = pSrcDoc->GetRoot();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700411 pSrcDict = pSrcDict->GetDict(FX_BSTRC("ViewerPreferences"));
412 if (!pSrcDict)
413 return FALSE;
Tom Sepez471a1032015-10-15 16:17:18 -0700414
415 CPDF_Dictionary* pDstDict = pDstDoc->GetRoot();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700416 if (!pDstDict)
417 return FALSE;
Tom Sepez471a1032015-10-15 16:17:18 -0700418
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700419 pDstDict->SetAt(FX_BSTRC("ViewerPreferences"), pSrcDict->Clone(TRUE));
420 return TRUE;
421}