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