blob: 3e8de3fe42feb608804eeead8a64593761f8f505 [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.
4
5// 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
11class CPDF_PageOrganizer
12{
13public:
14 CPDF_PageOrganizer();
15 ~CPDF_PageOrganizer();
16
17public:
18 FX_BOOL PDFDocInit(CPDF_Document *pDestPDFDoc, CPDF_Document *pSrcPDFDoc);
19 FX_BOOL ExportPage(CPDF_Document *pSrcPDFDoc, CFX_WordArray* nPageNum, CPDF_Document *pDestPDFDoc, int nIndex);
20 CPDF_Object* PageDictGetInheritableTag(CPDF_Dictionary *pDict, CFX_ByteString nSrctag);
21 FX_BOOL UpdateReference(CPDF_Object *pObj, CPDF_Document *pDoc, CFX_MapPtrToPtr* pMapPtrToPtr);
22 int GetNewObjId(CPDF_Document *pDoc, CFX_MapPtrToPtr* pMapPtrToPtr, CPDF_Reference *pRef);
23
24};
25
26
27CPDF_PageOrganizer::CPDF_PageOrganizer()
28{
29
30}
31
32CPDF_PageOrganizer::~CPDF_PageOrganizer()
33{
34
35}
36
37FX_BOOL CPDF_PageOrganizer::PDFDocInit(CPDF_Document *pDestPDFDoc, CPDF_Document *pSrcPDFDoc)
38{
39 if(!pDestPDFDoc || !pSrcPDFDoc)
40 return false;
41
42 CPDF_Dictionary* pNewRoot = pDestPDFDoc->GetRoot();
43 if(!pNewRoot) return FALSE;
44
45 //Set the document information////////////////////////////////////////////
46
47 CPDF_Dictionary* DInfoDict = pDestPDFDoc->GetInfo();
48
49 if(!DInfoDict)
50 return FALSE;
51
52 CFX_ByteString producerstr;
John Abd-El-Malek207299b2014-12-15 12:13:45 -080053 producerstr.Format("PDFium");
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070054 DInfoDict->SetAt("Producer", new CPDF_String(producerstr));
55
56 //Set type////////////////////////////////////////////////////////////////
57 CFX_ByteString cbRootType = pNewRoot->GetString("Type","");
58 if( cbRootType.Equal("") )
59 {
60 pNewRoot->SetAt("Type", new CPDF_Name("Catalog"));
61 }
62
Bo Xu287e11a2014-06-30 09:49:21 -070063 CPDF_Dictionary* pNewPages = (CPDF_Dictionary*)(pNewRoot->GetElement("Pages")? pNewRoot->GetElement("Pages")->GetDirect() : NULL);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070064 if(!pNewPages)
65 {
66 pNewPages = new CPDF_Dictionary;
67 FX_DWORD NewPagesON = pDestPDFDoc->AddIndirectObject(pNewPages);
68 pNewRoot->SetAt("Pages", new CPDF_Reference(pDestPDFDoc, NewPagesON));
69 }
70
71 CFX_ByteString cbPageType = pNewPages->GetString("Type","");
72 if(cbPageType.Equal(""))
73 {
74 pNewPages->SetAt("Type", new CPDF_Name("Pages"));
75 }
76
77 CPDF_Array* pKeysArray = pNewPages->GetArray("Kids");
78 if(pKeysArray == NULL)
79 {
80 CPDF_Array* pNewKids = new CPDF_Array;
81 FX_DWORD Kidsobjnum = -1;
82 Kidsobjnum = pDestPDFDoc->AddIndirectObject(pNewKids);//, Kidsobjnum, Kidsgennum);
83
84 pNewPages->SetAt("Kids", new CPDF_Reference(pDestPDFDoc, Kidsobjnum));//, Kidsgennum));
85 pNewPages->SetAt("Count", new CPDF_Number(0));
86 }
87
88 return true;
89}
90
91FX_BOOL CPDF_PageOrganizer::ExportPage(CPDF_Document *pSrcPDFDoc, CFX_WordArray* nPageNum,
92 CPDF_Document *pDestPDFDoc,int nIndex)
93{
94 int curpage =nIndex;
95
96 CFX_MapPtrToPtr* pMapPtrToPtr = new CFX_MapPtrToPtr;
97 pMapPtrToPtr->InitHashTable(1001);
98
99 for(int i=0; i<nPageNum->GetSize(); i++)
100 {
101
102 CPDF_Dictionary* pCurPageDict = pDestPDFDoc->CreateNewPage(curpage);
103 CPDF_Dictionary* pSrcPageDict = pSrcPDFDoc->GetPage(nPageNum->GetAt(i)-1);
104 if(!pSrcPageDict || !pCurPageDict)
105 {
106 delete pMapPtrToPtr;
107 return FALSE;
108 }
109
110 // Clone the page dictionary///////////
111 FX_POSITION SrcPos = pSrcPageDict->GetStartPos();
112 while (SrcPos)
113 {
114 CFX_ByteString cbSrcKeyStr;
115 CPDF_Object* pObj = pSrcPageDict->GetNextElement(SrcPos, cbSrcKeyStr);
116 if(cbSrcKeyStr.Compare(("Type")) && cbSrcKeyStr.Compare(("Parent")))
117 {
118 if(pCurPageDict->KeyExist(cbSrcKeyStr))
119 pCurPageDict->RemoveAt(cbSrcKeyStr);
120 pCurPageDict->SetAt(cbSrcKeyStr, pObj->Clone());
121 }
122 }
123
124 //inheritable item///////////////////////
125 CPDF_Object* pInheritable = NULL;
126 //1 MediaBox //required
127 if(!pCurPageDict->KeyExist("MediaBox"))
128 {
129
130 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "MediaBox");
131 if(!pInheritable)
132 {
133 //Search the "CropBox" from source page dictionary, if not exists,we take the letter size.
134 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "CropBox");
135 if(pInheritable)
136 pCurPageDict->SetAt("MediaBox", pInheritable->Clone());
137 else
138 {
139 //Make the default size to be letter size (8.5'x11')
140 CPDF_Array* pArray = new CPDF_Array;
141 pArray->AddNumber(0);
142 pArray->AddNumber(0);
143 pArray->AddNumber(612);
144 pArray->AddNumber(792);
145 pCurPageDict->SetAt("MediaBox", pArray);
146 }
147 }
148 else
149 pCurPageDict->SetAt("MediaBox", pInheritable->Clone());
150 }
151 //2 Resources //required
152 if(!pCurPageDict->KeyExist("Resources"))
153 {
154 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "Resources");
155 if(!pInheritable)
156 {
157 delete pMapPtrToPtr;
158 return FALSE;
159 }
160 pCurPageDict->SetAt("Resources", pInheritable->Clone());
161 }
162 //3 CropBox //Optional
163 if(!pCurPageDict->KeyExist("CropBox"))
164 {
165 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "CropBox");
166 if(pInheritable)
167 pCurPageDict->SetAt("CropBox", pInheritable->Clone());
168 }
169 //4 Rotate //Optional
170 if(!pCurPageDict->KeyExist("Rotate"))
171 {
172 pInheritable = PageDictGetInheritableTag(pSrcPageDict, "Rotate");
173 if(pInheritable)
174 pCurPageDict->SetAt("Rotate", pInheritable->Clone());
175 }
176
177 /////////////////////////////////////////////
178 //Update the reference
179 FX_DWORD dwOldPageObj = pSrcPageDict->GetObjNum();
180 FX_DWORD dwNewPageObj = pCurPageDict->GetObjNum();
181
Tom Sepezd7e5cc72015-06-10 14:33:37 -0700182 pMapPtrToPtr->SetAt((void*)(uintptr_t)dwOldPageObj, (void*)(uintptr_t)dwNewPageObj);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700183
184 this->UpdateReference(pCurPageDict, pDestPDFDoc, pMapPtrToPtr);
185 curpage++;
186 }
187
188 delete pMapPtrToPtr;
189 return TRUE;
190}
191
192CPDF_Object* CPDF_PageOrganizer::PageDictGetInheritableTag(CPDF_Dictionary *pDict, CFX_ByteString nSrctag)
193{
194 if(!pDict || !pDict->KeyExist("Type") || nSrctag.IsEmpty())
195 return NULL;
196
197 CPDF_Object* pType = pDict->GetElement("Type")->GetDirect();
198 if(!pType || pType->GetType() != PDFOBJ_NAME) return NULL;
199
200 if(pType->GetString().Compare("Page")) return NULL;
201
202 if(!pDict->KeyExist("Parent")) return NULL;
203 CPDF_Object* pParent = pDict->GetElement("Parent")->GetDirect();
204 if(!pParent || pParent->GetType() != PDFOBJ_DICTIONARY) return NULL;
205
206 CPDF_Dictionary* pp = (CPDF_Dictionary*)pParent;
207
208 if(pDict->KeyExist((const char*)nSrctag))
209 return pDict->GetElement((const char*)nSrctag);
210 while (pp)
211 {
212 if(pp->KeyExist((const char*)nSrctag))
213 return pp->GetElement((const char*)nSrctag);
Bo Xud38a35e2014-08-12 11:10:51 -0700214 else if (pp->KeyExist("Parent"))
215 {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700216 pp = (CPDF_Dictionary*)pp->GetElement("Parent")->GetDirect();
Bo Xud38a35e2014-08-12 11:10:51 -0700217 if (pp->GetType() == PDFOBJ_NULL) break;
218 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700219 else break;
220 }
221
222 return NULL;
223}
224
225FX_BOOL CPDF_PageOrganizer::UpdateReference(CPDF_Object *pObj, CPDF_Document *pDoc,
226 CFX_MapPtrToPtr* pMapPtrToPtr)
227{
228 switch (pObj->GetType())
229 {
230 case PDFOBJ_REFERENCE:
231 {
232 CPDF_Reference* pReference = (CPDF_Reference*)pObj;
233 int newobjnum = GetNewObjId(pDoc, pMapPtrToPtr, pReference);
234 if (newobjnum == 0) return FALSE;
235 pReference->SetRef(pDoc, newobjnum);//, 0);
236 break;
237 }
238 case PDFOBJ_DICTIONARY:
239 {
240 CPDF_Dictionary* pDict = (CPDF_Dictionary*)pObj;
241
242 FX_POSITION pos = pDict->GetStartPos();
243 while(pos)
244 {
245 CFX_ByteString key("");
246 CPDF_Object* pNextObj = pDict->GetNextElement(pos, key);
247 if (!FXSYS_strcmp(key, "Parent") || !FXSYS_strcmp(key, "Prev") || !FXSYS_strcmp(key, "First"))
248 continue;
249 if(pNextObj)
250 {
251 if(!UpdateReference(pNextObj, pDoc, pMapPtrToPtr))
252 pDict->RemoveAt(key);
253 }
254 else
255 return FALSE;
256 }
257 break;
258 }
259 case PDFOBJ_ARRAY:
260 {
261 CPDF_Array* pArray = (CPDF_Array*)pObj;
262 FX_DWORD count = pArray->GetCount();
263 for(FX_DWORD i = 0; i < count; i ++)
264 {
265 CPDF_Object* pNextObj = pArray->GetElement(i);
266 if(pNextObj)
267 {
268 if(!UpdateReference(pNextObj, pDoc, pMapPtrToPtr))
269 return FALSE;
270 }
271 else
272 return FALSE;
273 }
274 break;
275 }
276 case PDFOBJ_STREAM:
277 {
278 CPDF_Stream* pStream = (CPDF_Stream*)pObj;
279 CPDF_Dictionary* pDict = pStream->GetDict();
280 if(pDict)
281 {
282 if(!UpdateReference(pDict, pDoc, pMapPtrToPtr))
283 return FALSE;
284 }
285 else
286 return FALSE;
287 break;
288 }
289 default: break;
290 }
291
292 return TRUE;
293}
294
295int CPDF_PageOrganizer::GetNewObjId(CPDF_Document *pDoc, CFX_MapPtrToPtr* pMapPtrToPtr,
296 CPDF_Reference *pRef)
297{
298 size_t dwObjnum = 0;
299 if(!pRef)
300 return 0;
301 dwObjnum = pRef->GetRefObjNum();
302
303 size_t dwNewObjNum = 0;
304
Tom Sepezd7e5cc72015-06-10 14:33:37 -0700305 pMapPtrToPtr->Lookup((void*)dwObjnum, (void*&)dwNewObjNum);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700306 if(dwNewObjNum)
307 {
308 return (int)dwNewObjNum;
309 }
310 else
311 {
Jun Fang4cf36952014-09-08 11:27:02 -0700312 CPDF_Object* pDirect = pRef->GetDirect();
313 if(!pDirect)
314 {
Bo Xu287e11a2014-06-30 09:49:21 -0700315 return 0;
Jun Fang4cf36952014-09-08 11:27:02 -0700316 }
317
318 CPDF_Object* pClone = pDirect->Clone();
319 if(!pClone)
320 {
321 return 0;
322 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700323
324 if(pClone->GetType() == PDFOBJ_DICTIONARY)
325 {
326 CPDF_Dictionary* pDictClone = (CPDF_Dictionary*)pClone;
327 if(pDictClone->KeyExist("Type"))
328 {
329 CFX_ByteString strType = pDictClone->GetString("Type");
330 if(!FXSYS_stricmp(strType, "Pages"))
331 {
332 pDictClone->Release();
333 return 4;
334 }
335 else if(!FXSYS_stricmp(strType, "Page"))
336 {
337 pDictClone->Release();
338 return 0;
339 }
340 }
341 }
342 dwNewObjNum = pDoc->AddIndirectObject(pClone);//, onum, gnum);
Tom Sepezd7e5cc72015-06-10 14:33:37 -0700343 pMapPtrToPtr->SetAt((void*)dwObjnum, (void*)dwNewObjNum);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700344
345 if(!UpdateReference(pClone, pDoc, pMapPtrToPtr))
346 {
347 pClone->Release();
348 return 0;
349 }
350 return (int)dwNewObjNum;
351 }
352 return 0;
353}
354
355FPDF_BOOL ParserPageRangeString(CFX_ByteString rangstring, CFX_WordArray* pageArray,int nCount)
356{
357
358 if(rangstring.GetLength() != 0)
359 {
360 rangstring.Remove(' ');
361 int nLength = rangstring.GetLength();
362 CFX_ByteString cbCompareString("0123456789-,");
363 for(int i=0; i<nLength; i++)
364 {
365 if(cbCompareString.Find(rangstring[i]) == -1)
366 return FALSE;
367 }
368 CFX_ByteString cbMidRange;
369 int nStringFrom = 0;
370 int nStringTo=0;
371 while(nStringTo < nLength)
372 {
373 nStringTo = rangstring.Find(',',nStringFrom);
374 if(nStringTo == -1)
375 {
376 nStringTo = nLength;
377 }
378 cbMidRange = rangstring.Mid(nStringFrom,nStringTo-nStringFrom);
379
380 int nMid = cbMidRange.Find('-');
381 if(nMid == -1)
382 {
383 long lPageNum = atol(cbMidRange);
384 if(lPageNum <= 0 || lPageNum > nCount)
385 return FALSE;
386 pageArray->Add((FX_WORD)lPageNum);
387 }
388 else
389 {
390 int nStartPageNum = atol(cbMidRange.Mid(0,nMid));
391 if (nStartPageNum ==0)
392 {
393 return FALSE;
394 }
395
396
397 nMid = nMid+1;
398 int nEnd = cbMidRange.GetLength()-nMid;
399
400 if(nEnd ==0)return FALSE;
401
402 // int nEndPageNum = (nEnd == 0)?nCount:atol(cbMidRange.Mid(nMid,nEnd));
403 int nEndPageNum = atol(cbMidRange.Mid(nMid,nEnd));
404
405 if(nStartPageNum < 0 ||nStartPageNum >nEndPageNum|| nEndPageNum > nCount)
406 {
407 return FALSE;
408 }
409 else
410 {
411 for(int nIndex=nStartPageNum; nIndex <= nEndPageNum; nIndex ++)
412 pageArray->Add(nIndex);
413 }
414 }
415 nStringFrom = nStringTo +1;
416 }
417 }
418 return TRUE;
419}
420
421DLLEXPORT FPDF_BOOL STDCALL FPDF_ImportPages(FPDF_DOCUMENT dest_doc,FPDF_DOCUMENT src_doc,
422 FPDF_BYTESTRING pagerange, int index)
423{
424 if(dest_doc == NULL || src_doc == NULL )
425 return FALSE;
426 CFX_WordArray pageArray;
Bo Xufdc00a72014-10-28 23:03:33 -0700427 CPDFXFA_Document* pSrcDoc = (CPDFXFA_Document*)src_doc;
428 CPDF_Document* pSrcPDFDoc = pSrcDoc->GetPDFDoc();
429 int nCount = pSrcPDFDoc->GetPageCount();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700430 if(pagerange)
431 {
432 if(ParserPageRangeString(pagerange,&pageArray,nCount) == FALSE)
433 return FALSE;
434 }
435 else
436 {
437 for(int i=1; i<=nCount; i++)
438 {
439 pageArray.Add(i);
440 }
441 }
442
Bo Xufdc00a72014-10-28 23:03:33 -0700443 CPDFXFA_Document* pDestDoc = (CPDFXFA_Document*)dest_doc;
444 CPDF_Document* pDestPDFDoc = pDestDoc->GetPDFDoc();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700445 CPDF_PageOrganizer pageOrg;
446
Bo Xufdc00a72014-10-28 23:03:33 -0700447 pageOrg.PDFDocInit(pDestPDFDoc,pSrcPDFDoc);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700448
Bo Xufdc00a72014-10-28 23:03:33 -0700449 if(pageOrg.ExportPage(pSrcPDFDoc,&pageArray,pDestPDFDoc,index))
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700450 return TRUE;
451 return FALSE;
452}
453
454DLLEXPORT FPDF_BOOL STDCALL FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc)
455{
456 if(src_doc == NULL || dest_doc == NULL)
457 return false;
Bo Xufdc00a72014-10-28 23:03:33 -0700458 CPDFXFA_Document* pSrcDoc = (CPDFXFA_Document*)src_doc;
459 CPDF_Document* pSrcPDFDoc = pSrcDoc->GetPDFDoc();
460 CPDF_Dictionary* pSrcDict = pSrcPDFDoc->GetRoot();
461 pSrcDict = pSrcDict->GetDict(FX_BSTRC("ViewerPreferences"));
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700462 if(!pSrcDict)
463 return FALSE;
Bo Xufdc00a72014-10-28 23:03:33 -0700464 CPDFXFA_Document* pDstDoc = (CPDFXFA_Document*)dest_doc;
465 CPDF_Document* pDstPDFDoc = pDstDoc->GetPDFDoc();
466 CPDF_Dictionary* pDstDict = pDstPDFDoc->GetRoot();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700467 if(!pDstDict)
468 return FALSE;
469 pDstDict->SetAt(FX_BSTRC("ViewerPreferences"), pSrcDict->Clone(TRUE));
470 return TRUE;
471}
472