blob: d3899156a203c9a8c7c4000c43edbd1cf2802134 [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"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07008#include "../include/fsdk_define.h"
Bo Xufdc00a72014-10-28 23:03:33 -07009#include "../include/fpdfxfa/fpdfxfa_doc.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
62 CPDF_Dictionary* pNewPages =
63 (CPDF_Dictionary*)(pNewRoot->GetElement("Pages")
64 ? pNewRoot->GetElement("Pages")->GetDirect()
65 : NULL);
66 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();
189 if (!pType || pType->GetType() != PDFOBJ_NAME)
190 return NULL;
191
192 if (pType->GetString().Compare("Page"))
193 return NULL;
194
195 if (!pDict->KeyExist("Parent"))
196 return NULL;
197 CPDF_Object* pParent = pDict->GetElement("Parent")->GetDirect();
198 if (!pParent || pParent->GetType() != PDFOBJ_DICTIONARY)
199 return NULL;
200
201 CPDF_Dictionary* pp = (CPDF_Dictionary*)pParent;
202
203 if (pDict->KeyExist((const char*)nSrctag))
204 return pDict->GetElement((const char*)nSrctag);
205 while (pp) {
206 if (pp->KeyExist((const char*)nSrctag))
207 return pp->GetElement((const char*)nSrctag);
208 if (pp->KeyExist("Parent")) {
209 pp = (CPDF_Dictionary*)pp->GetElement("Parent")->GetDirect();
210 if (pp->GetType() == PDFOBJ_NULL)
211 break;
212 } else
213 break;
214 }
215
216 return NULL;
217}
218
219FX_BOOL CPDF_PageOrganizer::UpdateReference(CPDF_Object* pObj,
220 CPDF_Document* pDoc,
221 CFX_MapPtrToPtr* pMapPtrToPtr) {
222 switch (pObj->GetType()) {
223 case PDFOBJ_REFERENCE: {
224 CPDF_Reference* pReference = (CPDF_Reference*)pObj;
225 int newobjnum = GetNewObjId(pDoc, pMapPtrToPtr, pReference);
226 if (newobjnum == 0)
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700227 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700228 pReference->SetRef(pDoc, newobjnum); //, 0);
229 break;
230 }
231 case PDFOBJ_DICTIONARY: {
232 CPDF_Dictionary* pDict = (CPDF_Dictionary*)pObj;
233
234 FX_POSITION pos = pDict->GetStartPos();
235 while (pos) {
236 CFX_ByteString key("");
237 CPDF_Object* pNextObj = pDict->GetNextElement(pos, key);
238 if (!FXSYS_strcmp(key, "Parent") || !FXSYS_strcmp(key, "Prev") ||
239 !FXSYS_strcmp(key, "First"))
240 continue;
241 if (pNextObj) {
242 if (!UpdateReference(pNextObj, pDoc, pMapPtrToPtr))
243 pDict->RemoveAt(key);
244 } else
245 return FALSE;
246 }
247 break;
248 }
249 case PDFOBJ_ARRAY: {
250 CPDF_Array* pArray = (CPDF_Array*)pObj;
251 FX_DWORD count = pArray->GetCount();
252 for (FX_DWORD i = 0; i < count; i++) {
253 CPDF_Object* pNextObj = pArray->GetElement(i);
254 if (pNextObj) {
255 if (!UpdateReference(pNextObj, pDoc, pMapPtrToPtr))
256 return FALSE;
257 } else
258 return FALSE;
259 }
260 break;
261 }
262 case PDFOBJ_STREAM: {
263 CPDF_Stream* pStream = (CPDF_Stream*)pObj;
264 CPDF_Dictionary* pDict = pStream->GetDict();
265 if (pDict) {
266 if (!UpdateReference(pDict, pDoc, pMapPtrToPtr))
267 return FALSE;
268 } else
269 return FALSE;
270 break;
271 }
272 default:
273 break;
274 }
275
276 return TRUE;
277}
278
279int CPDF_PageOrganizer::GetNewObjId(CPDF_Document* pDoc,
280 CFX_MapPtrToPtr* pMapPtrToPtr,
281 CPDF_Reference* pRef) {
282 if (!pRef)
283 return 0;
284
285 size_t dwObjnum = pRef->GetRefObjNum();
286 size_t dwNewObjNum = 0;
287
288 pMapPtrToPtr->Lookup((void*)dwObjnum, (void*&)dwNewObjNum);
289 if (dwNewObjNum) {
290 return (int)dwNewObjNum;
291 }
292
293 CPDF_Object* pDirect = pRef->GetDirect();
294 if (!pDirect) {
295 return 0;
296 }
297
298 CPDF_Object* pClone = pDirect->Clone();
299 if (!pClone) {
300 return 0;
301 }
302
303 if (pClone->GetType() == PDFOBJ_DICTIONARY) {
304 CPDF_Dictionary* pDictClone = (CPDF_Dictionary*)pClone;
305 if (pDictClone->KeyExist("Type")) {
306 CFX_ByteString strType = pDictClone->GetString("Type");
307 if (!FXSYS_stricmp(strType, "Pages")) {
308 pDictClone->Release();
309 return 4;
310 } else if (!FXSYS_stricmp(strType, "Page")) {
311 pDictClone->Release();
312 return 0;
313 }
314 }
315 }
316
317 dwNewObjNum = pDoc->AddIndirectObject(pClone);
318 pMapPtrToPtr->SetAt((void*)dwObjnum, (void*)dwNewObjNum);
319 if (!UpdateReference(pClone, pDoc, pMapPtrToPtr)) {
320 pClone->Release();
321 return 0;
322 }
323
324 return (int)dwNewObjNum;
325}
326
327FPDF_BOOL ParserPageRangeString(CFX_ByteString rangstring,
328 CFX_WordArray* pageArray,
329 int nCount) {
330 if (rangstring.GetLength() != 0) {
331 rangstring.Remove(' ');
332 int nLength = rangstring.GetLength();
333 CFX_ByteString cbCompareString("0123456789-,");
334 for (int i = 0; i < nLength; i++) {
335 if (cbCompareString.Find(rangstring[i]) == -1)
336 return FALSE;
337 }
338 CFX_ByteString cbMidRange;
339 int nStringFrom = 0;
340 int nStringTo = 0;
341 while (nStringTo < nLength) {
342 nStringTo = rangstring.Find(',', nStringFrom);
343 if (nStringTo == -1) {
344 nStringTo = nLength;
345 }
346 cbMidRange = rangstring.Mid(nStringFrom, nStringTo - nStringFrom);
347
348 int nMid = cbMidRange.Find('-');
349 if (nMid == -1) {
350 long lPageNum = atol(cbMidRange);
351 if (lPageNum <= 0 || lPageNum > nCount)
352 return FALSE;
353
354 pageArray->Add((FX_WORD)lPageNum);
355 } else {
356 int nStartPageNum = atol(cbMidRange.Mid(0, nMid));
357 if (nStartPageNum == 0)
358 return FALSE;
359
360 nMid = nMid + 1;
361 int nEnd = cbMidRange.GetLength() - nMid;
362 if (nEnd == 0)
363 return FALSE;
364
365 int nEndPageNum = atol(cbMidRange.Mid(nMid, nEnd));
366 if (nStartPageNum < 0 || nStartPageNum > nEndPageNum ||
367 nEndPageNum > nCount)
368 return FALSE;
369
370 for (int nIndex = nStartPageNum; nIndex <= nEndPageNum; ++nIndex)
371 pageArray->Add(nIndex);
372 }
373 nStringFrom = nStringTo + 1;
374 }
375 }
376 return TRUE;
377}
378
379DLLEXPORT FPDF_BOOL STDCALL FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
380 FPDF_DOCUMENT src_doc,
381 FPDF_BYTESTRING pagerange,
382 int index) {
383 if (dest_doc == NULL || src_doc == NULL)
384 return FALSE;
385 CFX_WordArray pageArray;
386 CPDFXFA_Document* pSrcDoc = (CPDFXFA_Document*)src_doc;
387 CPDF_Document* pSrcPDFDoc = pSrcDoc->GetPDFDoc();
388 int nCount = pSrcPDFDoc->GetPageCount();
389 if (pagerange) {
390 if (ParserPageRangeString(pagerange, &pageArray, nCount) == FALSE)
391 return FALSE;
392 } else {
393 for (int i = 1; i <= nCount; i++) {
394 pageArray.Add(i);
395 }
396 }
397
398 CPDFXFA_Document* pDestDoc = (CPDFXFA_Document*)dest_doc;
399 CPDF_Document* pDestPDFDoc = pDestDoc->GetPDFDoc();
400 CPDF_PageOrganizer pageOrg;
401
402 pageOrg.PDFDocInit(pDestPDFDoc, pSrcPDFDoc);
403
404 if (pageOrg.ExportPage(pSrcPDFDoc, &pageArray, pDestPDFDoc, index))
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700405 return TRUE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700406 return FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700407}
408
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700409DLLEXPORT FPDF_BOOL STDCALL FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc,
410 FPDF_DOCUMENT src_doc) {
411 if (src_doc == NULL || dest_doc == NULL)
412 return false;
413 CPDFXFA_Document* pSrcDoc = (CPDFXFA_Document*)src_doc;
414 CPDF_Document* pSrcPDFDoc = pSrcDoc->GetPDFDoc();
415 CPDF_Dictionary* pSrcDict = pSrcPDFDoc->GetRoot();
416 pSrcDict = pSrcDict->GetDict(FX_BSTRC("ViewerPreferences"));
417 if (!pSrcDict)
418 return FALSE;
419 CPDFXFA_Document* pDstDoc = (CPDFXFA_Document*)dest_doc;
420 CPDF_Document* pDstPDFDoc = pDstDoc->GetPDFDoc();
421 CPDF_Dictionary* pDstDict = pDstPDFDoc->GetRoot();
422 if (!pDstDict)
423 return FALSE;
424 pDstDict->SetAt(FX_BSTRC("ViewerPreferences"), pSrcDict->Clone(TRUE));
425 return TRUE;
426}