Remove "this==NULL" and adjust corresponding callers
[pdfium.git] / fpdfsdk / src / fpdfppo.cpp
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
26 CPDF_PageOrganizer::CPDF_PageOrganizer()
27 {
28
29 }
30
31 CPDF_PageOrganizer::~CPDF_PageOrganizer()
32 {
33
34 }
35
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")? pNewRoot->GetElement("Pages")->GetDirect() : NULL);
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
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)(FX_UINTPTR)dwOldPageObj, (FX_LPVOID)(FX_UINTPTR)dwNewPageObj);
187
188                 this->UpdateReference(pCurPageDict, pDestPDFDoc, pMapPtrToPtr);
189                 curpage++;
190         }
191
192         delete pMapPtrToPtr;
193         return TRUE;
194 }
195
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
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
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)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)                     
315                         return 0;
316                 
317                 if(pClone->GetType() == PDFOBJ_DICTIONARY)
318                 {
319                         CPDF_Dictionary* pDictClone = (CPDF_Dictionary*)pClone;
320                         if(pDictClone->KeyExist("Type"))
321                         {
322                                 CFX_ByteString strType = pDictClone->GetString("Type");
323                                 if(!FXSYS_stricmp(strType, "Pages"))
324                                 {
325                                         pDictClone->Release();
326                                         return 4;
327                                 }
328                                 else if(!FXSYS_stricmp(strType, "Page"))
329                                 {
330                                         pDictClone->Release();
331                                         return  0;
332                                 }
333                         }
334                 }
335                 dwNewObjNum = pDoc->AddIndirectObject(pClone);//, onum, gnum);
336                 pMapPtrToPtr->SetAt((FX_LPVOID)dwObjnum, (FX_LPVOID)dwNewObjNum);
337                 
338                 if(!UpdateReference(pClone, pDoc, pMapPtrToPtr))
339                 {
340                         pClone->Release();
341                         return 0;
342                 }
343                 return (int)dwNewObjNum;
344         }
345         return 0;
346 }
347
348 FPDF_BOOL ParserPageRangeString(CFX_ByteString rangstring, CFX_WordArray* pageArray,int nCount)
349 {
350
351         if(rangstring.GetLength() != 0)
352         {
353                 rangstring.Remove(' ');
354                 int nLength = rangstring.GetLength();
355                 CFX_ByteString cbCompareString("0123456789-,");
356                 for(int i=0; i<nLength; i++)
357                 {
358                         if(cbCompareString.Find(rangstring[i]) == -1)
359                                 return FALSE;
360                 }
361                 CFX_ByteString cbMidRange;
362                 int nStringFrom = 0;
363                 int nStringTo=0;
364                 while(nStringTo < nLength)
365                 {
366                         nStringTo = rangstring.Find(',',nStringFrom);
367                         if(nStringTo == -1)
368                         {
369                                 nStringTo = nLength;
370                         }
371                         cbMidRange = rangstring.Mid(nStringFrom,nStringTo-nStringFrom);
372                         
373                         int nMid = cbMidRange.Find('-');
374                         if(nMid == -1)
375                         {
376                                 long lPageNum = atol(cbMidRange);
377                                 if(lPageNum <= 0 || lPageNum > nCount)
378                                         return FALSE;
379                                 pageArray->Add((FX_WORD)lPageNum);
380                         }
381                         else
382                         {
383                                 int nStartPageNum = atol(cbMidRange.Mid(0,nMid));
384                                 if (nStartPageNum ==0)
385                                 {
386                                         return FALSE;
387                                 }
388
389
390                                 nMid = nMid+1;
391                                 int nEnd = cbMidRange.GetLength()-nMid;
392
393                                 if(nEnd ==0)return FALSE;
394                                 
395                                 //                              int nEndPageNum = (nEnd == 0)?nCount:atol(cbMidRange.Mid(nMid,nEnd));
396                                 int nEndPageNum = atol(cbMidRange.Mid(nMid,nEnd));
397                                 
398                                 if(nStartPageNum < 0 ||nStartPageNum >nEndPageNum|| nEndPageNum > nCount)
399                                 {
400                                         return FALSE;
401                                 }
402                                 else
403                                 {
404                                         for(int nIndex=nStartPageNum; nIndex <= nEndPageNum; nIndex ++)
405                                                 pageArray->Add(nIndex);
406                                 }
407                         }
408                         nStringFrom = nStringTo +1;
409                 }
410         }
411         return TRUE;
412 }
413
414 DLLEXPORT FPDF_BOOL STDCALL FPDF_ImportPages(FPDF_DOCUMENT dest_doc,FPDF_DOCUMENT src_doc, 
415                                                                                          FPDF_BYTESTRING pagerange, int index)
416 {
417         if(dest_doc == NULL || src_doc == NULL )
418                 return FALSE;
419         CFX_WordArray pageArray;
420         CPDF_Document* pSrcDoc = (CPDF_Document*)src_doc;
421         int nCount = pSrcDoc->GetPageCount();
422         if(pagerange)
423         {
424                 if(ParserPageRangeString(pagerange,&pageArray,nCount) == FALSE)
425                         return FALSE;
426         }
427         else
428         {
429                 for(int i=1; i<=nCount; i++)
430                 {
431                         pageArray.Add(i);
432                 }
433         }
434         
435         CPDF_Document* pDestDoc = (CPDF_Document*)dest_doc;
436         CPDF_PageOrganizer pageOrg;
437
438         pageOrg.PDFDocInit(pDestDoc,pSrcDoc);
439
440         if(pageOrg.ExportPage(pSrcDoc,&pageArray,pDestDoc,index))
441                 return TRUE;
442         return FALSE;
443 }
444
445 DLLEXPORT FPDF_BOOL STDCALL FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc)
446 {
447         if(src_doc == NULL || dest_doc == NULL)
448                 return false;
449         CPDF_Document* pSrcDoc = (CPDF_Document*)src_doc;
450         CPDF_Dictionary* pSrcDict = pSrcDoc->GetRoot();
451         pSrcDict = pSrcDict->GetDict(FX_BSTRC("ViewerPreferences"));;
452         if(!pSrcDict)
453                 return FALSE;
454         CPDF_Document* pDstDoc = (CPDF_Document*)dest_doc;
455         CPDF_Dictionary* pDstDict = pDstDoc->GetRoot();
456         if(!pDstDict)
457                 return FALSE;
458         pDstDict->SetAt(FX_BSTRC("ViewerPreferences"), pSrcDict->Clone(TRUE));
459         return TRUE;
460 }
461