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