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 "core/fpdfapi/edit/cpdf_creator.h" 8 9 #include <algorithm> 10 11 #include "core/fpdfapi/edit/cpdf_encryptor.h" 12 #include "core/fpdfapi/edit/cpdf_flateencoder.h" 13 #include "core/fpdfapi/parser/cpdf_array.h" 14 #include "core/fpdfapi/parser/cpdf_crypto_handler.h" 15 #include "core/fpdfapi/parser/cpdf_document.h" 16 #include "core/fpdfapi/parser/cpdf_number.h" 17 #include "core/fpdfapi/parser/cpdf_parser.h" 18 #include "core/fpdfapi/parser/cpdf_security_handler.h" 19 #include "core/fpdfapi/parser/cpdf_string.h" 20 #include "core/fpdfapi/parser/fpdf_parser_decode.h" 21 #include "core/fxcrt/fx_extension.h" 22 #include "core/fxcrt/fx_random.h" 23 24 namespace { 25 26 const size_t kArchiveBufferSize = 32768; 27 28 class CFX_FileBufferArchive : public IFX_ArchiveStream { 29 public: 30 explicit CFX_FileBufferArchive(const RetainPtr<IFX_WriteStream>& archive); 31 ~CFX_FileBufferArchive() override; 32 33 bool WriteBlock(const void* pBuf, size_t size) override; 34 bool WriteByte(uint8_t byte) override; 35 bool WriteDWord(uint32_t i) override; 36 bool WriteString(const ByteStringView& str) override; 37 38 FX_FILESIZE CurrentOffset() const override { return offset_; } 39 40 private: 41 bool Flush(); 42 43 FX_FILESIZE offset_; 44 size_t current_length_; 45 std::vector<uint8_t> buffer_; 46 RetainPtr<IFX_WriteStream> backing_file_; 47 }; 48 49 CFX_FileBufferArchive::CFX_FileBufferArchive( 50 const RetainPtr<IFX_WriteStream>& file) 51 : offset_(0), 52 current_length_(0), 53 buffer_(kArchiveBufferSize), 54 backing_file_(file) { 55 ASSERT(file); 56 } 57 58 CFX_FileBufferArchive::~CFX_FileBufferArchive() { 59 Flush(); 60 } 61 62 bool CFX_FileBufferArchive::Flush() { 63 size_t nRemaining = current_length_; 64 current_length_ = 0; 65 if (!backing_file_) 66 return false; 67 if (!nRemaining) 68 return true; 69 return backing_file_->WriteBlock(buffer_.data(), nRemaining); 70 } 71 72 bool CFX_FileBufferArchive::WriteBlock(const void* pBuf, size_t size) { 73 ASSERT(pBuf && size > 0); 74 75 const uint8_t* buffer = reinterpret_cast<const uint8_t*>(pBuf); 76 size_t temp_size = size; 77 while (temp_size) { 78 size_t buf_size = std::min(kArchiveBufferSize - current_length_, temp_size); 79 memcpy(buffer_.data() + current_length_, buffer, buf_size); 80 81 current_length_ += buf_size; 82 if (current_length_ == kArchiveBufferSize && !Flush()) 83 return false; 84 85 temp_size -= buf_size; 86 buffer += buf_size; 87 } 88 89 pdfium::base::CheckedNumeric<FX_FILESIZE> safe_offset = offset_; 90 safe_offset += size; 91 if (!safe_offset.IsValid()) 92 return false; 93 94 offset_ = safe_offset.ValueOrDie(); 95 return true; 96 } 97 98 bool CFX_FileBufferArchive::WriteByte(uint8_t byte) { 99 return WriteBlock(&byte, 1); 100 } 101 102 bool CFX_FileBufferArchive::WriteDWord(uint32_t i) { 103 char buf[32]; 104 FXSYS_itoa(i, buf, 10); 105 return WriteBlock(buf, strlen(buf)); 106 } 107 108 bool CFX_FileBufferArchive::WriteString(const ByteStringView& str) { 109 return WriteBlock(str.raw_str(), str.GetLength()); 110 } 111 112 std::vector<uint8_t> GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) { 113 std::vector<uint8_t> buffer(sizeof(uint32_t) * 4); 114 uint32_t* pBuffer = reinterpret_cast<uint32_t*>(buffer.data()); 115 void* pContext = FX_Random_MT_Start(dwSeed1); 116 for (int i = 0; i < 2; ++i) 117 *pBuffer++ = FX_Random_MT_Generate(pContext); 118 119 FX_Random_MT_Close(pContext); 120 pContext = FX_Random_MT_Start(dwSeed2); 121 for (int i = 0; i < 2; ++i) 122 *pBuffer++ = FX_Random_MT_Generate(pContext); 123 124 FX_Random_MT_Close(pContext); 125 return buffer; 126 } 127 128 int32_t OutputIndex(IFX_ArchiveStream* archive, FX_FILESIZE offset) { 129 if (!archive->WriteByte(static_cast<uint8_t>(offset >> 24)) || 130 !archive->WriteByte(static_cast<uint8_t>(offset >> 16)) || 131 !archive->WriteByte(static_cast<uint8_t>(offset >> 8)) || 132 !archive->WriteByte(static_cast<uint8_t>(offset)) || 133 !archive->WriteByte(0)) { 134 return -1; 135 } 136 return 0; 137 } 138 139 } // namespace 140 141 CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc, 142 const RetainPtr<IFX_WriteStream>& archive) 143 : m_pDocument(pDoc), 144 m_pParser(pDoc->GetParser()), 145 m_bSecurityChanged(false), 146 m_pEncryptDict(m_pParser ? m_pParser->GetEncryptDict() : nullptr), 147 m_dwEncryptObjNum(0), 148 m_pSecurityHandler(m_pParser ? m_pParser->GetSecurityHandler() : nullptr), 149 m_pMetadata(nullptr), 150 m_dwLastObjNum(m_pDocument->GetLastObjNum()), 151 m_Archive(pdfium::MakeUnique<CFX_FileBufferArchive>(archive)), 152 m_SavedOffset(0), 153 m_iStage(-1), 154 m_dwFlags(0), 155 m_CurObjNum(0), 156 m_XrefStart(0), 157 m_pIDArray(nullptr), 158 m_FileVersion(0) {} 159 160 CPDF_Creator::~CPDF_Creator() {} 161 162 bool CPDF_Creator::WriteStream(const CPDF_Object* pStream, 163 uint32_t objnum, 164 CPDF_CryptoHandler* pCrypto) { 165 CPDF_FlateEncoder encoder(const_cast<CPDF_Stream*>(pStream->AsStream()), 166 pStream != m_pMetadata); 167 CPDF_Encryptor encryptor(pCrypto, objnum, encoder.GetData(), 168 encoder.GetSize()); 169 if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) != 170 encryptor.GetSize()) { 171 encoder.CloneDict(); 172 encoder.GetDict()->SetNewFor<CPDF_Number>( 173 "Length", static_cast<int>(encryptor.GetSize())); 174 } 175 176 if (!WriteDirectObj(objnum, encoder.GetDict(), true) || 177 !m_Archive->WriteString("stream\r\n")) { 178 return false; 179 } 180 181 // Allow for empty streams. 182 if (encryptor.GetSize() > 0 && 183 !m_Archive->WriteBlock(encryptor.GetData(), encryptor.GetSize())) { 184 return false; 185 } 186 187 return m_Archive->WriteString("\r\nendstream"); 188 } 189 190 bool CPDF_Creator::WriteIndirectObj(uint32_t objnum, const CPDF_Object* pObj) { 191 if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(" 0 obj\r\n")) 192 return false; 193 194 if (pObj->IsStream()) { 195 CPDF_CryptoHandler* pHandler = 196 pObj != m_pMetadata ? GetCryptoHandler() : nullptr; 197 if (!WriteStream(pObj, objnum, pHandler)) 198 return false; 199 } else if (!WriteDirectObj(objnum, pObj, true)) { 200 return false; 201 } 202 203 return m_Archive->WriteString("\r\nendobj\r\n"); 204 } 205 206 bool CPDF_Creator::WriteDirectObj(uint32_t objnum, 207 const CPDF_Object* pObj, 208 bool bEncrypt) { 209 switch (pObj->GetType()) { 210 case CPDF_Object::BOOLEAN: 211 case CPDF_Object::NAME: 212 case CPDF_Object::NULLOBJ: 213 case CPDF_Object::NUMBER: 214 case CPDF_Object::REFERENCE: 215 if (!pObj->WriteTo(m_Archive.get())) 216 return false; 217 break; 218 219 case CPDF_Object::STRING: { 220 ByteString str = pObj->GetString(); 221 bool bHex = pObj->AsString()->IsHex(); 222 if (!GetCryptoHandler() || !bEncrypt) { 223 if (!pObj->WriteTo(m_Archive.get())) 224 return false; 225 break; 226 } 227 CPDF_Encryptor encryptor(GetCryptoHandler(), objnum, 228 (uint8_t*)str.c_str(), str.GetLength()); 229 ByteString content = PDF_EncodeString( 230 ByteString(encryptor.GetData(), encryptor.GetSize()), bHex); 231 if (!m_Archive->WriteString(content.AsStringView())) 232 return false; 233 break; 234 } 235 case CPDF_Object::STREAM: { 236 CPDF_FlateEncoder encoder(const_cast<CPDF_Stream*>(pObj->AsStream()), 237 true); 238 CPDF_Encryptor encryptor(GetCryptoHandler(), objnum, encoder.GetData(), 239 encoder.GetSize()); 240 if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) != 241 encryptor.GetSize()) { 242 encoder.CloneDict(); 243 encoder.GetDict()->SetNewFor<CPDF_Number>( 244 "Length", static_cast<int>(encryptor.GetSize())); 245 } 246 if (!WriteDirectObj(objnum, encoder.GetDict(), true) || 247 !m_Archive->WriteString("stream\r\n") || 248 !m_Archive->WriteBlock(encryptor.GetData(), encryptor.GetSize()) || 249 !m_Archive->WriteString("\r\nendstream")) { 250 return false; 251 } 252 253 break; 254 } 255 case CPDF_Object::ARRAY: { 256 if (!m_Archive->WriteString("[")) 257 return false; 258 259 const CPDF_Array* p = pObj->AsArray(); 260 for (size_t i = 0; i < p->GetCount(); i++) { 261 CPDF_Object* pElement = p->GetObjectAt(i); 262 if (!pElement->IsInline()) { 263 if (!m_Archive->WriteString(" ") || 264 !m_Archive->WriteDWord(pElement->GetObjNum()) || 265 !m_Archive->WriteString(" 0 R")) { 266 return false; 267 } 268 } else if (!WriteDirectObj(objnum, pElement, true)) { 269 return false; 270 } 271 } 272 if (!m_Archive->WriteString("]")) 273 return false; 274 break; 275 } 276 case CPDF_Object::DICTIONARY: { 277 if (!GetCryptoHandler() || pObj == m_pEncryptDict) { 278 if (!pObj->WriteTo(m_Archive.get())) 279 return false; 280 break; 281 } 282 283 if (!m_Archive->WriteString("<<")) 284 return false; 285 286 const CPDF_Dictionary* p = pObj->AsDictionary(); 287 bool bSignDict = p->IsSignatureDict(); 288 for (const auto& it : *p) { 289 bool bSignValue = false; 290 const ByteString& key = it.first; 291 CPDF_Object* pValue = it.second.get(); 292 if (!m_Archive->WriteString("/") || 293 !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) { 294 return false; 295 } 296 297 if (bSignDict && key == "Contents") 298 bSignValue = true; 299 if (!pValue->IsInline()) { 300 if (!m_Archive->WriteString(" ") || 301 !m_Archive->WriteDWord(pValue->GetObjNum()) || 302 !m_Archive->WriteString(" 0 R ")) { 303 return false; 304 } 305 } else if (!WriteDirectObj(objnum, pValue, !bSignValue)) { 306 return false; 307 } 308 } 309 if (!m_Archive->WriteString(">>")) 310 return false; 311 break; 312 } 313 } 314 return true; 315 } 316 317 bool CPDF_Creator::WriteOldIndirectObject(uint32_t objnum) { 318 if (m_pParser->IsObjectFreeOrNull(objnum)) 319 return true; 320 321 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset(); 322 323 bool bExistInMap = !!m_pDocument->GetIndirectObject(objnum); 324 CPDF_Object* pObj = m_pDocument->GetOrParseIndirectObject(objnum); 325 if (!pObj) { 326 m_ObjectOffsets.erase(objnum); 327 return true; 328 } 329 if (!WriteIndirectObj(pObj->GetObjNum(), pObj)) 330 return false; 331 if (!bExistInMap) 332 m_pDocument->DeleteIndirectObject(objnum); 333 return true; 334 } 335 336 bool CPDF_Creator::WriteOldObjs() { 337 uint32_t nLastObjNum = m_pParser->GetLastObjNum(); 338 if (!m_pParser->IsValidObjectNumber(nLastObjNum)) 339 return true; 340 341 for (uint32_t objnum = m_CurObjNum; objnum <= nLastObjNum; ++objnum) { 342 if (!WriteOldIndirectObject(objnum)) 343 return false; 344 } 345 return true; 346 } 347 348 bool CPDF_Creator::WriteNewObjs() { 349 for (size_t i = m_CurObjNum; i < m_NewObjNumArray.size(); ++i) { 350 uint32_t objnum = m_NewObjNumArray[i]; 351 CPDF_Object* pObj = m_pDocument->GetIndirectObject(objnum); 352 if (!pObj) 353 continue; 354 355 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset(); 356 if (!WriteIndirectObj(pObj->GetObjNum(), pObj)) 357 return false; 358 } 359 return true; 360 } 361 362 void CPDF_Creator::InitOldObjNumOffsets() { 363 if (!m_pParser) 364 return; 365 366 uint32_t dwStart = 0; 367 uint32_t dwEnd = m_pParser->GetLastObjNum(); 368 while (dwStart <= dwEnd) { 369 while (dwStart <= dwEnd && m_pParser->IsObjectFreeOrNull(dwStart)) 370 dwStart++; 371 372 if (dwStart > dwEnd) 373 break; 374 375 uint32_t j = dwStart; 376 while (j <= dwEnd && !m_pParser->IsObjectFreeOrNull(j)) 377 j++; 378 379 dwStart = j; 380 } 381 } 382 383 void CPDF_Creator::InitNewObjNumOffsets() { 384 for (const auto& pair : *m_pDocument) { 385 const uint32_t objnum = pair.first; 386 if (IsIncremental() || 387 pair.second->GetObjNum() == CPDF_Object::kInvalidObjNum) { 388 continue; 389 } 390 if (m_pParser && m_pParser->IsValidObjectNumber(objnum) && 391 !m_pParser->IsObjectFree(objnum)) { 392 continue; 393 } 394 m_NewObjNumArray.insert(std::lower_bound(m_NewObjNumArray.begin(), 395 m_NewObjNumArray.end(), objnum), 396 objnum); 397 } 398 } 399 400 int32_t CPDF_Creator::WriteDoc_Stage1() { 401 ASSERT(m_iStage > -1 || m_iStage < 20); 402 if (m_iStage == 0) { 403 if (!m_pParser) 404 m_dwFlags &= ~FPDFCREATE_INCREMENTAL; 405 if (m_bSecurityChanged && IsOriginal()) 406 m_dwFlags &= ~FPDFCREATE_INCREMENTAL; 407 408 const CPDF_Dictionary* pDict = m_pDocument->GetRoot(); 409 m_pMetadata = pDict ? pDict->GetDirectObjectFor("Metadata") : nullptr; 410 m_iStage = 10; 411 } 412 if (m_iStage == 10) { 413 if (!IsIncremental()) { 414 if (!m_Archive->WriteString("%PDF-1.")) 415 return -1; 416 417 int32_t version = 7; 418 if (m_FileVersion) 419 version = m_FileVersion; 420 else if (m_pParser) 421 version = m_pParser->GetFileVersion(); 422 423 if (!m_Archive->WriteDWord(version % 10) || 424 !m_Archive->WriteString("\r\n%\xA1\xB3\xC5\xD7\r\n")) { 425 return -1; 426 } 427 428 InitOldObjNumOffsets(); 429 m_iStage = 20; 430 } else { 431 m_SavedOffset = m_pParser->GetFileAccess()->GetSize(); 432 m_iStage = 15; 433 } 434 } 435 if (m_iStage == 15) { 436 if (IsOriginal() && m_SavedOffset > 0) { 437 RetainPtr<IFX_SeekableReadStream> pSrcFile = m_pParser->GetFileAccess(); 438 std::vector<uint8_t> buffer(4096); 439 FX_FILESIZE src_size = m_SavedOffset; 440 while (src_size) { 441 uint32_t block_size = src_size > 4096 ? 4096 : src_size; 442 if (!pSrcFile->ReadBlock(buffer.data(), 443 m_Archive->CurrentOffset() - src_size, 444 block_size)) { 445 return -1; 446 } 447 if (!m_Archive->WriteBlock(buffer.data(), block_size)) 448 return -1; 449 450 src_size -= block_size; 451 } 452 } 453 if (IsOriginal() && m_pParser->GetLastXRefOffset() == 0) { 454 InitOldObjNumOffsets(); 455 456 for (uint32_t num = 0; num <= m_pParser->GetLastObjNum(); ++num) { 457 if (m_pParser->IsObjectFreeOrNull(num)) 458 continue; 459 460 m_ObjectOffsets[num] = m_pParser->GetObjectPositionOrZero(num); 461 } 462 } 463 m_iStage = 20; 464 } 465 InitNewObjNumOffsets(); 466 return m_iStage; 467 } 468 469 int32_t CPDF_Creator::WriteDoc_Stage2() { 470 ASSERT(m_iStage >= 20 || m_iStage < 30); 471 if (m_iStage == 20) { 472 if (!IsIncremental() && m_pParser) { 473 m_CurObjNum = 0; 474 m_iStage = 21; 475 } else { 476 m_iStage = 25; 477 } 478 } 479 if (m_iStage == 21) { 480 if (!WriteOldObjs()) 481 return -1; 482 483 m_iStage = 25; 484 } 485 if (m_iStage == 25) { 486 m_CurObjNum = 0; 487 m_iStage = 26; 488 } 489 if (m_iStage == 26) { 490 if (!WriteNewObjs()) 491 return -1; 492 493 m_iStage = 27; 494 } 495 if (m_iStage == 27) { 496 if (m_pEncryptDict && m_pEncryptDict->IsInline()) { 497 m_dwLastObjNum += 1; 498 FX_FILESIZE saveOffset = m_Archive->CurrentOffset(); 499 if (!WriteIndirectObj(m_dwLastObjNum, m_pEncryptDict.Get())) 500 return -1; 501 502 m_ObjectOffsets[m_dwLastObjNum] = saveOffset; 503 m_dwEncryptObjNum = m_dwLastObjNum; 504 if (IsIncremental()) 505 m_NewObjNumArray.push_back(m_dwLastObjNum); 506 } 507 m_iStage = 80; 508 } 509 return m_iStage; 510 } 511 512 int32_t CPDF_Creator::WriteDoc_Stage3() { 513 ASSERT(m_iStage >= 80 || m_iStage < 90); 514 515 uint32_t dwLastObjNum = m_dwLastObjNum; 516 if (m_iStage == 80) { 517 m_XrefStart = m_Archive->CurrentOffset(); 518 if (!IsIncremental() || !m_pParser->IsXRefStream()) { 519 if (!IsIncremental() || m_pParser->GetLastXRefOffset() == 0) { 520 ByteString str; 521 str = pdfium::ContainsKey(m_ObjectOffsets, 1) 522 ? "xref\r\n" 523 : "xref\r\n0 1\r\n0000000000 65535 f\r\n"; 524 if (!m_Archive->WriteString(str.AsStringView())) 525 return -1; 526 527 m_CurObjNum = 1; 528 m_iStage = 81; 529 } else { 530 if (!m_Archive->WriteString("xref\r\n")) 531 return -1; 532 533 m_CurObjNum = 0; 534 m_iStage = 82; 535 } 536 } else { 537 m_iStage = 90; 538 } 539 } 540 if (m_iStage == 81) { 541 ByteString str; 542 uint32_t i = m_CurObjNum; 543 uint32_t j; 544 while (i <= dwLastObjNum) { 545 while (i <= dwLastObjNum && !pdfium::ContainsKey(m_ObjectOffsets, i)) 546 i++; 547 548 if (i > dwLastObjNum) 549 break; 550 551 j = i; 552 while (j <= dwLastObjNum && pdfium::ContainsKey(m_ObjectOffsets, j)) 553 j++; 554 555 if (i == 1) 556 str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j); 557 else 558 str = ByteString::Format("%d %d\r\n", i, j - i); 559 560 if (!m_Archive->WriteBlock(str.c_str(), str.GetLength())) 561 return -1; 562 563 while (i < j) { 564 str = ByteString::Format("%010d 00000 n\r\n", m_ObjectOffsets[i++]); 565 if (!m_Archive->WriteBlock(str.c_str(), str.GetLength())) 566 return -1; 567 } 568 if (i > dwLastObjNum) 569 break; 570 } 571 m_iStage = 90; 572 } 573 if (m_iStage == 82) { 574 ByteString str; 575 uint32_t iCount = pdfium::CollectionSize<uint32_t>(m_NewObjNumArray); 576 uint32_t i = m_CurObjNum; 577 while (i < iCount) { 578 size_t j = i; 579 uint32_t objnum = m_NewObjNumArray[i]; 580 while (j < iCount) { 581 if (++j == iCount) 582 break; 583 uint32_t dwCurrent = m_NewObjNumArray[j]; 584 if (dwCurrent - objnum > 1) 585 break; 586 objnum = dwCurrent; 587 } 588 objnum = m_NewObjNumArray[i]; 589 if (objnum == 1) 590 str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j - i + 1); 591 else 592 str = ByteString::Format("%d %d\r\n", objnum, j - i); 593 594 if (!m_Archive->WriteBlock(str.c_str(), str.GetLength())) 595 return -1; 596 597 while (i < j) { 598 objnum = m_NewObjNumArray[i++]; 599 str = ByteString::Format("%010d 00000 n\r\n", m_ObjectOffsets[objnum]); 600 if (!m_Archive->WriteBlock(str.c_str(), str.GetLength())) 601 return -1; 602 } 603 } 604 m_iStage = 90; 605 } 606 return m_iStage; 607 } 608 609 int32_t CPDF_Creator::WriteDoc_Stage4() { 610 ASSERT(m_iStage >= 90); 611 612 bool bXRefStream = IsIncremental() && m_pParser->IsXRefStream(); 613 if (!bXRefStream) { 614 if (!m_Archive->WriteString("trailer\r\n<<")) 615 return -1; 616 } else { 617 if (!m_Archive->WriteDWord(m_pDocument->GetLastObjNum() + 1) || 618 !m_Archive->WriteString(" 0 obj <<")) { 619 return -1; 620 } 621 } 622 623 if (m_pParser) { 624 std::unique_ptr<CPDF_Dictionary> p = m_pParser->GetCombinedTrailer(); 625 for (const auto& it : *p) { 626 const ByteString& key = it.first; 627 CPDF_Object* pValue = it.second.get(); 628 if (key == "Encrypt" || key == "Size" || key == "Filter" || 629 key == "Index" || key == "Length" || key == "Prev" || key == "W" || 630 key == "XRefStm" || key == "ID") { 631 continue; 632 } 633 if (!m_Archive->WriteString(("/")) || 634 !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) { 635 return -1; 636 } 637 if (!pValue->IsInline()) { 638 if (!m_Archive->WriteString(" ") || 639 !m_Archive->WriteDWord(pValue->GetObjNum()) || 640 !m_Archive->WriteString(" 0 R ")) { 641 return -1; 642 } 643 } else if (!pValue->WriteTo(m_Archive.get())) { 644 return -1; 645 } 646 } 647 } else { 648 if (!m_Archive->WriteString("\r\n/Root ") || 649 !m_Archive->WriteDWord(m_pDocument->GetRoot()->GetObjNum()) || 650 !m_Archive->WriteString(" 0 R\r\n")) { 651 return -1; 652 } 653 if (m_pDocument->GetInfo()) { 654 if (!m_Archive->WriteString("/Info ") || 655 !m_Archive->WriteDWord(m_pDocument->GetInfo()->GetObjNum()) || 656 !m_Archive->WriteString(" 0 R\r\n")) { 657 return -1; 658 } 659 } 660 } 661 if (m_pEncryptDict) { 662 if (!m_Archive->WriteString("/Encrypt")) 663 return -1; 664 665 uint32_t dwObjNum = m_pEncryptDict->GetObjNum(); 666 if (dwObjNum == 0) 667 dwObjNum = m_pDocument->GetLastObjNum() + 1; 668 if (!m_Archive->WriteString(" ") || !m_Archive->WriteDWord(dwObjNum) || 669 !m_Archive->WriteString(" 0 R ")) { 670 return -1; 671 } 672 } 673 674 if (!m_Archive->WriteString("/Size ") || 675 !m_Archive->WriteDWord(m_dwLastObjNum + (bXRefStream ? 2 : 1))) { 676 return -1; 677 } 678 if (IsIncremental()) { 679 FX_FILESIZE prev = m_pParser->GetLastXRefOffset(); 680 if (prev) { 681 if (!m_Archive->WriteString("/Prev ")) 682 return -1; 683 684 char offset_buf[20]; 685 memset(offset_buf, 0, sizeof(offset_buf)); 686 FXSYS_i64toa(prev, offset_buf, 10); 687 if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf))) 688 return -1; 689 } 690 } 691 if (m_pIDArray) { 692 if (!m_Archive->WriteString(("/ID")) || 693 !m_pIDArray->WriteTo(m_Archive.get())) { 694 return -1; 695 } 696 } 697 if (!bXRefStream) { 698 if (!m_Archive->WriteString(">>")) 699 return -1; 700 } else { 701 if (!m_Archive->WriteString("/W[0 4 1]/Index[")) 702 return -1; 703 if (IsIncremental() && m_pParser && m_pParser->GetLastXRefOffset() == 0) { 704 uint32_t i = 0; 705 for (i = 0; i < m_dwLastObjNum; i++) { 706 if (!pdfium::ContainsKey(m_ObjectOffsets, i)) 707 continue; 708 if (!m_Archive->WriteDWord(i) || !m_Archive->WriteString(" 1 ")) 709 return -1; 710 } 711 if (!m_Archive->WriteString("]/Length ") || 712 !m_Archive->WriteDWord(m_dwLastObjNum * 5) || 713 !m_Archive->WriteString(">>stream\r\n")) { 714 return -1; 715 } 716 for (i = 0; i < m_dwLastObjNum; i++) { 717 auto it = m_ObjectOffsets.find(i); 718 if (it == m_ObjectOffsets.end()) 719 continue; 720 OutputIndex(m_Archive.get(), it->second); 721 } 722 } else { 723 size_t count = m_NewObjNumArray.size(); 724 size_t i = 0; 725 for (i = 0; i < count; i++) { 726 if (!m_Archive->WriteDWord(m_NewObjNumArray[i]) || 727 !m_Archive->WriteString(" 1 ")) { 728 return -1; 729 } 730 } 731 if (!m_Archive->WriteString("]/Length ") || 732 !m_Archive->WriteDWord(count * 5) || 733 !m_Archive->WriteString(">>stream\r\n")) { 734 return -1; 735 } 736 for (i = 0; i < count; ++i) 737 OutputIndex(m_Archive.get(), m_ObjectOffsets[m_NewObjNumArray[i]]); 738 } 739 if (!m_Archive->WriteString("\r\nendstream")) 740 return -1; 741 } 742 743 if (!m_Archive->WriteString("\r\nstartxref\r\n")) 744 return -1; 745 746 char offset_buf[20]; 747 memset(offset_buf, 0, sizeof(offset_buf)); 748 FXSYS_i64toa(m_XrefStart, offset_buf, 10); 749 if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf)) || 750 !m_Archive->WriteString("\r\n%%EOF\r\n")) { 751 return -1; 752 } 753 754 m_iStage = 100; 755 return m_iStage; 756 } 757 758 bool CPDF_Creator::Create(uint32_t flags) { 759 m_dwFlags = flags; 760 m_iStage = 0; 761 m_dwLastObjNum = m_pDocument->GetLastObjNum(); 762 m_ObjectOffsets.clear(); 763 m_NewObjNumArray.clear(); 764 765 InitID(); 766 return Continue() > -1; 767 } 768 769 void CPDF_Creator::InitID() { 770 const CPDF_Array* pOldIDArray = m_pParser ? m_pParser->GetIDArray() : nullptr; 771 772 bool idArrayPreExisting = !!m_pIDArray; 773 if (!idArrayPreExisting) { 774 m_pIDArray = pdfium::MakeUnique<CPDF_Array>(); 775 CPDF_Object* pID1 = pOldIDArray ? pOldIDArray->GetObjectAt(0) : nullptr; 776 if (pID1) { 777 m_pIDArray->Add(pID1->Clone()); 778 } else { 779 std::vector<uint8_t> buffer = 780 GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum); 781 ByteString bsBuffer(buffer.data(), buffer.size()); 782 m_pIDArray->AddNew<CPDF_String>(bsBuffer, true); 783 } 784 } 785 786 if (pOldIDArray) { 787 CPDF_Object* pID2 = pOldIDArray->GetObjectAt(1); 788 if (IsIncremental() && m_pEncryptDict && pID2) { 789 m_pIDArray->Add(pID2->Clone()); 790 return; 791 } 792 std::vector<uint8_t> buffer = 793 GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum); 794 ByteString bsBuffer(buffer.data(), buffer.size()); 795 m_pIDArray->AddNew<CPDF_String>(bsBuffer, true); 796 return; 797 } 798 799 m_pIDArray->Add(m_pIDArray->GetObjectAt(0)->Clone()); 800 if (m_pEncryptDict && !pOldIDArray && m_pParser && !idArrayPreExisting) { 801 if (m_pEncryptDict->GetStringFor("Filter") == "Standard") { 802 ByteString user_pass = m_pParser->GetPassword(); 803 m_pSecurityHandler = pdfium::MakeUnique<CPDF_SecurityHandler>(); 804 m_pSecurityHandler->OnCreate(m_pEncryptDict.Get(), m_pIDArray.get(), 805 user_pass); 806 m_bSecurityChanged = true; 807 } 808 } 809 } 810 811 int32_t CPDF_Creator::Continue() { 812 if (m_iStage < 0) 813 return m_iStage; 814 815 int32_t iRet = 0; 816 while (m_iStage < 100) { 817 if (m_iStage < 20) 818 iRet = WriteDoc_Stage1(); 819 else if (m_iStage < 30) 820 iRet = WriteDoc_Stage2(); 821 else if (m_iStage < 90) 822 iRet = WriteDoc_Stage3(); 823 else 824 iRet = WriteDoc_Stage4(); 825 826 if (iRet < m_iStage) 827 break; 828 } 829 830 if (iRet < 1 || m_iStage == 100) { 831 m_iStage = -1; 832 return iRet > 99 ? 0 : (iRet < 1 ? -1 : iRet); 833 } 834 return m_iStage; 835 } 836 837 bool CPDF_Creator::SetFileVersion(int32_t fileVersion) { 838 if (fileVersion < 10 || fileVersion > 17) 839 return false; 840 m_FileVersion = fileVersion; 841 return true; 842 } 843 844 void CPDF_Creator::RemoveSecurity() { 845 m_pSecurityHandler.Reset(); 846 m_bSecurityChanged = true; 847 m_pEncryptDict = nullptr; 848 } 849 850 CPDF_CryptoHandler* CPDF_Creator::GetCryptoHandler() { 851 return m_pSecurityHandler ? m_pSecurityHandler->GetCryptoHandler() : nullptr; 852 } 853