7#include "core/fpdfapi/edit/cpdf_creator.h"
15#include "core/fpdfapi/parser/cpdf_array.h"
16#include "core/fpdfapi/parser/cpdf_crypto_handler.h"
17#include "core/fpdfapi/parser/cpdf_dictionary.h"
18#include "core/fpdfapi/parser/cpdf_document.h"
19#include "core/fpdfapi/parser/cpdf_encryptor.h"
20#include "core/fpdfapi/parser/cpdf_flateencoder.h"
21#include "core/fpdfapi/parser/cpdf_number.h"
22#include "core/fpdfapi/parser/cpdf_parser.h"
23#include "core/fpdfapi/parser/cpdf_security_handler.h"
24#include "core/fpdfapi/parser/cpdf_string.h"
25#include "core/fpdfapi/parser/fpdf_parser_utility.h"
26#include "core/fpdfapi/parser/object_tree_traversal_util.h"
27#include "core/fxcrt/data_vector.h"
28#include "core/fxcrt/fx_extension.h"
29#include "core/fxcrt/fx_random.h"
30#include "core/fxcrt/fx_safe_types.h"
31#include "core/fxcrt/span_util.h"
32#include "core/fxcrt/stl_util.h"
33#include "third_party/base/check.h"
34#include "third_party/base/containers/contains.h"
38const size_t kArchiveBufferSize = 32768;
43 ~CFX_FileBufferArchive()
override;
45 bool WriteBlock(pdfium::span<
const uint8_t> buffer)
override;
46 FX_FILESIZE CurrentOffset()
const override {
return offset_; }
52 DataVector<uint8_t> buffer_;
53 pdfium::span<uint8_t> available_;
57CFX_FileBufferArchive::CFX_FileBufferArchive(
59 : buffer_(kArchiveBufferSize),
61 backing_file_(std::move(file)) {
62 DCHECK(backing_file_);
65CFX_FileBufferArchive::~CFX_FileBufferArchive() {
69bool CFX_FileBufferArchive::Flush() {
70 size_t nUsed = buffer_.size() - available_.size();
71 available_ = pdfium::make_span(buffer_);
74 return backing_file_->WriteBlock(available_.first(nUsed));
77bool CFX_FileBufferArchive::WriteBlock(pdfium::span<
const uint8_t> buffer) {
81 pdfium::span<
const uint8_t> src_span = buffer;
82 while (!src_span.empty()) {
83 size_t copy_size = std::min(available_.size(), src_span.size());
84 fxcrt::spancpy(available_, src_span.first(copy_size));
85 src_span = src_span.subspan(copy_size);
86 available_ = available_.subspan(copy_size);
87 if (available_.empty() && !Flush())
91 FX_SAFE_FILESIZE safe_offset = offset_;
92 safe_offset += buffer.size();
93 if (!safe_offset.IsValid())
96 offset_ = safe_offset.ValueOrDie();
100ByteString GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) {
110 return ByteString(ByteStringView(pdfium::as_byte_span(buffer)));
114 return archive
->WriteByte(static_cast<uint8_t>(offset >> 24)
) &&
135 if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(
" 0 obj\r\n"))
138 std::unique_ptr<CPDF_Encryptor> encryptor;
139 if (GetCryptoHandler() && pObj != m_pEncryptDict)
142 if (!pObj->WriteTo(m_Archive.get(), encryptor.get()))
145 return m_Archive->WriteString(
"\r\nendobj\r\n");
148bool CPDF_Creator::WriteOldIndirectObject(uint32_t objnum) {
149 if (m_pParser->IsObjectFreeOrNull(objnum))
152 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
154 bool bExistInMap = !!m_pDocument->GetIndirectObject(objnum);
157 m_ObjectOffsets.erase(objnum);
160 if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get()))
163 m_pDocument->DeleteIndirectObject(objnum);
168 const uint32_t nLastObjNum = m_pParser->GetLastObjNum();
169 if (!m_pParser->IsValidObjectNumber(nLastObjNum)) {
172 if (m_CurObjNum > nLastObjNum) {
176 const std::set<uint32_t> objects_with_refs =
177 GetObjectsWithReferences(m_pDocument);
178 uint32_t last_object_number_written = 0;
179 for (uint32_t objnum = m_CurObjNum; objnum <= nLastObjNum; ++objnum) {
180 if (!pdfium::Contains(objects_with_refs, objnum)) {
183 if (!WriteOldIndirectObject(objnum)) {
186 last_object_number_written = objnum;
190 if (m_NewObjNumArray.empty()) {
191 m_dwLastObjNum = last_object_number_written;
197 for (size_t i = m_CurObjNum; i < m_NewObjNumArray.size(); ++i) {
198 uint32_t objnum = m_NewObjNumArray[i];
203 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
204 if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get()))
211 for (
const auto& pair : *m_pDocument) {
212 const uint32_t objnum = pair.first;
213 if (m_IsIncremental ||
214 pair.second->GetObjNum() == CPDF_Object::kInvalidObjNum) {
217 if (m_pParser && m_pParser->IsValidObjectNumber(objnum) &&
218 !m_pParser->IsObjectFree(objnum)) {
221 m_NewObjNumArray.insert(std::lower_bound(m_NewObjNumArray.begin(),
222 m_NewObjNumArray.end(), objnum),
228 DCHECK(m_iStage > Stage::kInvalid || m_iStage < Stage::kInitWriteObjs20);
229 if (m_iStage == Stage::kInit0) {
230 if (!m_pParser || (m_bSecurityChanged && m_IsOriginal))
231 m_IsIncremental =
false;
233 m_iStage = Stage::kWriteHeader10;
235 if (m_iStage == Stage::kWriteHeader10) {
236 if (!m_IsIncremental) {
237 if (!m_Archive->WriteString(
"%PDF-1."))
238 return Stage::kInvalid;
242 version = m_FileVersion;
244 version = m_pParser->GetFileVersion();
246 if (!m_Archive->WriteDWord(version % 10) ||
247 !m_Archive->WriteString(
"\r\n%\xA1\xB3\xC5\xD7\r\n")) {
248 return Stage::kInvalid;
250 m_iStage = Stage::kInitWriteObjs20;
252 m_SavedOffset = m_pParser->GetDocumentSize();
253 m_iStage = Stage::kWriteIncremental15;
256 if (m_iStage == Stage::kWriteIncremental15) {
257 if (m_IsOriginal && m_SavedOffset > 0) {
258 if (!m_pParser->WriteToArchive(m_Archive.get(), m_SavedOffset))
259 return Stage::kInvalid;
261 if (m_IsOriginal && m_pParser->GetLastXRefOffset() == 0) {
262 for (uint32_t num = 0; num <= m_pParser->GetLastObjNum(); ++num) {
263 if (m_pParser->IsObjectFreeOrNull(num))
266 m_ObjectOffsets[num] = m_pParser->GetObjectPositionOrZero(num);
269 m_iStage = Stage::kInitWriteObjs20;
271 InitNewObjNumOffsets();
276 DCHECK(m_iStage >= Stage::kInitWriteObjs20 ||
277 m_iStage < Stage::kInitWriteXRefs80);
278 if (m_iStage == Stage::kInitWriteObjs20) {
279 if (!m_IsIncremental && m_pParser) {
281 m_iStage = Stage::kWriteOldObjs21;
283 m_iStage = Stage::kInitWriteNewObjs25;
286 if (m_iStage == Stage::kWriteOldObjs21) {
288 return Stage::kInvalid;
290 m_iStage = Stage::kInitWriteNewObjs25;
292 if (m_iStage == Stage::kInitWriteNewObjs25) {
294 m_iStage = Stage::kWriteNewObjs26;
296 if (m_iStage == Stage::kWriteNewObjs26) {
298 return Stage::kInvalid;
300 m_iStage = Stage::kWriteEncryptDict27;
302 if (m_iStage == Stage::kWriteEncryptDict27) {
303 if (m_pEncryptDict && m_pEncryptDict->IsInline()) {
305 FX_FILESIZE saveOffset = m_Archive->CurrentOffset();
306 if (!WriteIndirectObj(m_dwLastObjNum, m_pEncryptDict.Get()))
307 return Stage::kInvalid;
309 m_ObjectOffsets[m_dwLastObjNum] = saveOffset;
311 m_NewObjNumArray.push_back(m_dwLastObjNum);
313 m_iStage = Stage::kInitWriteXRefs80;
319 DCHECK(m_iStage >= Stage::kInitWriteXRefs80 ||
320 m_iStage < Stage::kWriteTrailerAndFinish90);
322 uint32_t dwLastObjNum = m_dwLastObjNum;
323 if (m_iStage == Stage::kInitWriteXRefs80) {
324 m_XrefStart = m_Archive->CurrentOffset();
325 if (!m_IsIncremental || !m_pParser->IsXRefStream()) {
326 if (!m_IsIncremental || m_pParser->GetLastXRefOffset() == 0) {
328 str = pdfium::Contains(m_ObjectOffsets, 1)
330 :
"xref\r\n0 1\r\n0000000000 65535 f\r\n";
331 if (!m_Archive->WriteString(str.AsStringView()))
332 return Stage::kInvalid;
335 m_iStage = Stage::kWriteXrefsNotIncremental81;
337 if (!m_Archive->WriteString(
"xref\r\n"))
338 return Stage::kInvalid;
341 m_iStage = Stage::kWriteXrefsIncremental82;
344 m_iStage = Stage::kWriteTrailerAndFinish90;
347 if (m_iStage == Stage::kWriteXrefsNotIncremental81) {
349 uint32_t i = m_CurObjNum;
351 while (i <= dwLastObjNum) {
352 while (i <= dwLastObjNum && !pdfium::Contains(m_ObjectOffsets, i))
355 if (i > dwLastObjNum)
359 while (j <= dwLastObjNum && pdfium::Contains(m_ObjectOffsets, j))
363 str
= ByteString
::Format("0 %d\r\n0000000000 65535 f\r\n", j
);
367 if (!m_Archive->WriteString(str.AsStringView()))
368 return Stage::kInvalid;
371 str = ByteString::Format(
"%010d 00000 n\r\n", m_ObjectOffsets[i++]);
372 if (!m_Archive->WriteString(str.AsStringView()))
373 return Stage::kInvalid;
375 if (i > dwLastObjNum)
378 m_iStage = Stage::kWriteTrailerAndFinish90;
380 if (m_iStage == Stage::kWriteXrefsIncremental82) {
382 uint32_t iCount = fxcrt::CollectionSize<uint32_t>(m_NewObjNumArray);
383 uint32_t i = m_CurObjNum;
386 uint32_t objnum = m_NewObjNumArray[i];
390 uint32_t dwCurrent = m_NewObjNumArray[j];
391 if (dwCurrent - objnum > 1)
395 objnum = m_NewObjNumArray[i];
397 str = ByteString
::Format("0 %d\r\n0000000000 65535 f\r\n", j - i + 1
);
401 if (!m_Archive->WriteString(str.AsStringView()))
402 return Stage::kInvalid;
405 objnum = m_NewObjNumArray[i++];
406 str = ByteString::Format(
"%010d 00000 n\r\n", m_ObjectOffsets[objnum]);
407 if (!m_Archive->WriteString(str.AsStringView()))
408 return Stage::kInvalid;
411 m_iStage = Stage::kWriteTrailerAndFinish90;
417 DCHECK(m_iStage >= Stage::kWriteTrailerAndFinish90);
419 bool bXRefStream = m_IsIncremental && m_pParser->IsXRefStream();
421 if (!m_Archive->WriteString(
"trailer\r\n<<"))
422 return Stage::kInvalid;
424 if (!m_Archive->WriteDWord(m_pDocument->GetLastObjNum() + 1) ||
425 !m_Archive->WriteString(
" 0 obj <<")) {
426 return Stage::kInvalid;
432 for (
const auto& it : locker) {
433 const ByteString& key = it.first;
434 const RetainPtr<CPDF_Object>& pValue = it.second;
435 if (key ==
"Encrypt" || key ==
"Size" || key ==
"Filter" ||
436 key ==
"Index" || key ==
"Length" || key ==
"Prev" || key ==
"W" ||
437 key ==
"XRefStm" || key ==
"ID" || key ==
"DecodeParms" ||
441 if (!m_Archive->WriteString((
"/")) ||
442 !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) {
443 return Stage::kInvalid;
445 if (!pValue->WriteTo(m_Archive.get(),
nullptr))
446 return Stage::kInvalid;
449 if (!m_Archive->WriteString(
"\r\n/Root ") ||
450 !m_Archive->WriteDWord(m_pDocument->GetRoot()->GetObjNum()) ||
451 !m_Archive->WriteString(
" 0 R\r\n")) {
452 return Stage::kInvalid;
454 if (m_pDocument->GetInfo()) {
455 if (!m_Archive->WriteString(
"/Info ") ||
456 !m_Archive->WriteDWord(m_pDocument->GetInfo()->GetObjNum()) ||
457 !m_Archive->WriteString(
" 0 R\r\n")) {
458 return Stage::kInvalid;
462 if (m_pEncryptDict) {
463 if (!m_Archive->WriteString(
"/Encrypt"))
464 return Stage::kInvalid;
466 uint32_t dwObjNum = m_pEncryptDict->GetObjNum();
468 dwObjNum = m_pDocument->GetLastObjNum() + 1;
469 if (!m_Archive->WriteString(
" ") || !m_Archive->WriteDWord(dwObjNum) ||
470 !m_Archive->WriteString(
" 0 R ")) {
471 return Stage::kInvalid;
475 if (!m_Archive->WriteString(
"/Size ") ||
476 !m_Archive->WriteDWord(m_dwLastObjNum + (bXRefStream ? 2 : 1))) {
477 return Stage::kInvalid;
479 if (m_IsIncremental) {
482 if (!m_Archive->WriteString(
"/Prev ") || !m_Archive->WriteFilesize(prev))
483 return Stage::kInvalid;
487 if (!m_Archive->WriteString((
"/ID")) ||
488 !m_pIDArray->WriteTo(m_Archive.get(),
nullptr)) {
489 return Stage::kInvalid;
493 if (!m_Archive->WriteString(
">>"))
494 return Stage::kInvalid;
496 if (!m_Archive->WriteString(
"/W[0 4 1]/Index["))
497 return Stage::kInvalid;
498 if (m_IsIncremental && m_pParser && m_pParser->GetLastXRefOffset() == 0) {
500 for (i = 0; i < m_dwLastObjNum; i++) {
501 if (!pdfium::Contains(m_ObjectOffsets, i))
503 if (!m_Archive->WriteDWord(i) || !m_Archive->WriteString(
" 1 "))
504 return Stage::kInvalid;
506 if (!m_Archive->WriteString(
"]/Length ") ||
507 !m_Archive->WriteDWord(m_dwLastObjNum * 5) ||
508 !m_Archive->WriteString(
">>stream\r\n")) {
509 return Stage::kInvalid;
511 for (i = 0; i < m_dwLastObjNum; i++) {
512 auto it = m_ObjectOffsets.find(i);
513 if (it == m_ObjectOffsets.end())
515 if (!OutputIndex(m_Archive.get(), it->second))
516 return Stage::kInvalid;
519 int count = fxcrt::CollectionSize<
int>(m_NewObjNumArray);
521 for (i = 0; i < count; i++) {
522 if (!m_Archive->WriteDWord(m_NewObjNumArray[i]) ||
523 !m_Archive->WriteString(
" 1 ")) {
524 return Stage::kInvalid;
527 if (!m_Archive->WriteString(
"]/Length ") ||
528 !m_Archive->WriteDWord(count * 5) ||
529 !m_Archive->WriteString(
">>stream\r\n")) {
530 return Stage::kInvalid;
532 for (i = 0; i < count; ++i) {
533 if (!OutputIndex(m_Archive.get(), m_ObjectOffsets[m_NewObjNumArray[i]]))
534 return Stage::kInvalid;
537 if (!m_Archive->WriteString(
"\r\nendstream"))
538 return Stage::kInvalid;
541 if (!m_Archive->WriteString(
"\r\nstartxref\r\n") ||
542 !m_Archive->WriteFilesize(m_XrefStart) ||
543 !m_Archive->WriteString(
"\r\n%%EOF\r\n")) {
544 return Stage::kInvalid;
547 m_iStage = Stage::kComplete100;
555 m_iStage = Stage::kInit0;
556 m_dwLastObjNum = m_pDocument->GetLastObjNum();
557 m_ObjectOffsets.clear();
558 m_NewObjNumArray.clear();
567 m_pIDArray = pdfium::MakeRetain<CPDF_Array>();
568 RetainPtr<
const CPDF_Array> pOldIDArray =
569 m_pParser ? m_pParser->GetIDArray() :
nullptr;
571 pOldIDArray ? pOldIDArray->GetObjectAt(0) :
nullptr;
573 m_pIDArray->Append(pID1->Clone());
575 ByteString bsBuffer =
576 GenerateFileID((uint32_t)(uintptr_t)
this, m_dwLastObjNum);
577 m_pIDArray->AppendNew<CPDF_String>(bsBuffer,
true);
582 if (m_IsIncremental && m_pEncryptDict && pID2) {
583 m_pIDArray->Append(pID2->Clone());
586 ByteString bsBuffer =
587 GenerateFileID((uint32_t)(uintptr_t)
this, m_dwLastObjNum);
588 m_pIDArray->AppendNew<CPDF_String>(bsBuffer,
true);
592 m_pIDArray->Append(m_pIDArray->GetObjectAt(0)->Clone());
593 if (m_pEncryptDict) {
595 int revision = m_pEncryptDict->GetIntegerFor(
"R");
596 if ((revision == 2 || revision == 3) &&
597 m_pEncryptDict->GetByteStringFor(
"Filter") ==
"Standard") {
598 m_pNewEncryptDict = ToDictionary(m_pEncryptDict->Clone());
599 m_pEncryptDict = m_pNewEncryptDict;
600 m_pSecurityHandler = pdfium::MakeRetain<CPDF_SecurityHandler>();
601 m_pSecurityHandler->OnCreate(m_pNewEncryptDict.Get(), m_pIDArray.Get(),
602 m_pParser->GetEncodedPassword());
603 m_bSecurityChanged =
true;
609 if (m_iStage < Stage::kInit0)
612 Stage iRet = Stage::kInit0;
613 while (m_iStage < Stage::kComplete100) {
614 if (m_iStage < Stage::kInitWriteObjs20)
615 iRet = WriteDoc_Stage1();
616 else if (m_iStage < Stage::kInitWriteXRefs80)
617 iRet = WriteDoc_Stage2();
618 else if (m_iStage < Stage::kWriteTrailerAndFinish90)
619 iRet = WriteDoc_Stage3();
621 iRet = WriteDoc_Stage4();
627 if (iRet <= Stage::kInit0 || m_iStage == Stage::kComplete100) {
628 m_iStage = Stage::kInvalid;
629 return iRet > Stage::kInit0;
632 return m_iStage > Stage::kInvalid;
636 if (fileVersion < 10 || fileVersion > 17)
638 m_FileVersion = fileVersion;
643 m_pSecurityHandler.Reset();
644 m_bSecurityChanged =
true;
645 m_pEncryptDict =
nullptr;
646 m_pNewEncryptDict.Reset();
650 return m_pSecurityHandler ? m_pSecurityHandler->GetCryptoHandler() :
nullptr;
CPDF_Creator(CPDF_Document *pDoc, RetainPtr< IFX_RetainableWriteStream > archive)
bool SetFileVersion(int32_t fileVersion)
bool Create(uint32_t flags)
bool WriteByte(uint8_t byte)
static ByteString Format(const char *pFormat,...)
ByteString & operator=(ByteString &&that) noexcept
#define FPDFCREATE_INCREMENTAL
#define FPDFCREATE_NO_ORIGINAL
void * FX_Random_MT_Start(uint32_t dwSeed)
uint32_t FX_Random_MT_Generate(void *pContext)
void FX_Random_MT_Close(void *pContext)