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 10class CPDF_PageOrganizer 11{ 12public: 13 CPDF_PageOrganizer(); 14 ~CPDF_PageOrganizer(); 15 16public: 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 26CPDF_PageOrganizer::CPDF_PageOrganizer() 27{ 28 29} 30 31CPDF_PageOrganizer::~CPDF_PageOrganizer() 32{ 33 34} 35 36FX_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 95FX_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 196CPDF_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 226FX_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 296int 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 347FPDF_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 413DLLEXPORT 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 444DLLEXPORT 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