7#include "core/fpdfapi/edit/cpdf_creator.h"
16#include "core/fpdfapi/parser/cpdf_array.h"
17#include "core/fpdfapi/parser/cpdf_crypto_handler.h"
18#include "core/fpdfapi/parser/cpdf_dictionary.h"
19#include "core/fpdfapi/parser/cpdf_document.h"
20#include "core/fpdfapi/parser/cpdf_encryptor.h"
21#include "core/fpdfapi/parser/cpdf_flateencoder.h"
22#include "core/fpdfapi/parser/cpdf_number.h"
23#include "core/fpdfapi/parser/cpdf_parser.h"
24#include "core/fpdfapi/parser/cpdf_security_handler.h"
25#include "core/fpdfapi/parser/cpdf_string.h"
26#include "core/fpdfapi/parser/fpdf_parser_utility.h"
27#include "core/fpdfapi/parser/object_tree_traversal_util.h"
28#include "core/fxcrt/check.h"
29#include "core/fxcrt/containers/contains.h"
30#include "core/fxcrt/fixed_size_data_vector.h"
31#include "core/fxcrt/fx_extension.h"
32#include "core/fxcrt/fx_random.h"
33#include "core/fxcrt/fx_safe_types.h"
34#include "core/fxcrt/raw_span.h"
35#include "core/fxcrt/span_util.h"
36#include "core/fxcrt/stl_util.h"
40const size_t kArchiveBufferSize = 32768;
45 ~CFX_FileBufferArchive()
override;
47 bool WriteBlock(pdfium::span<
const uint8_t> buffer)
override;
48 FX_FILESIZE CurrentOffset()
const override {
return offset_; }
54 FixedSizeDataVector<uint8_t> buffer_;
55 pdfium::raw_span<uint8_t> available_;
59CFX_FileBufferArchive::CFX_FileBufferArchive(
61 : buffer_(FixedSizeDataVector<uint8_t>::Uninit(kArchiveBufferSize)),
62 available_(buffer_.span()),
63 backing_file_(std::move(file)) {
67CFX_FileBufferArchive::~CFX_FileBufferArchive() {
71bool CFX_FileBufferArchive::Flush() {
72 size_t used = buffer_.size() - available_.size();
73 available_ = buffer_.span();
74 return used == 0 || backing_file_->WriteBlock(available_.first(used));
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 available_ = fxcrt::spancpy(available_, src_span.first(copy_size));
85 src_span = src_span.subspan(copy_size);
86 if (available_.empty() && !Flush())
91 safe_offset += buffer.size();
92 if (!safe_offset.IsValid())
95 offset_ = safe_offset.ValueOrDie();
99std::array<uint32_t, 4> GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) {
102 std::array<uint32_t, 4> buffer = {
103 FX_Random_MT_Generate(pContext1), FX_Random_MT_Generate(pContext1),
104 FX_Random_MT_Generate(pContext2), FX_Random_MT_Generate(pContext2)};
111 return archive
->WriteByte(static_cast<uint8_t>(offset >> 24)
) &&
132 if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(
" 0 obj\r\n"))
135 std::unique_ptr<CPDF_Encryptor> encryptor;
136 if (GetCryptoHandler() && pObj != m_pEncryptDict)
139 if (!pObj->WriteTo(m_Archive.get(), encryptor.get()))
142 return m_Archive->WriteString(
"\r\nendobj\r\n");
145bool CPDF_Creator::WriteOldIndirectObject(uint32_t objnum) {
146 if (m_pParser->IsObjectFree(objnum)) {
150 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
152 bool bExistInMap = !!m_pDocument->GetIndirectObject(objnum);
155 m_ObjectOffsets.erase(objnum);
158 if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get()))
161 m_pDocument->DeleteIndirectObject(objnum);
166 const uint32_t nLastObjNum = m_pParser->GetLastObjNum();
167 if (!m_pParser->IsValidObjectNumber(nLastObjNum)) {
170 if (m_CurObjNum > nLastObjNum) {
174 const std::set<uint32_t> objects_with_refs =
175 GetObjectsWithReferences(m_pDocument);
176 uint32_t last_object_number_written = 0;
177 for (uint32_t objnum = m_CurObjNum; objnum <= nLastObjNum; ++objnum) {
178 if (!
pdfium::Contains(objects_with_refs, objnum)) {
181 if (!WriteOldIndirectObject(objnum)) {
184 last_object_number_written = objnum;
188 if (m_NewObjNumArray.empty()) {
189 m_dwLastObjNum = last_object_number_written;
195 for (size_t i = m_CurObjNum; i < m_NewObjNumArray.size(); ++i) {
196 uint32_t objnum = m_NewObjNumArray[i];
201 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
202 if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get()))
209 for (
const auto& pair : *m_pDocument) {
210 const uint32_t objnum = pair.first;
211 if (m_IsIncremental ||
212 pair.second->GetObjNum() == CPDF_Object::kInvalidObjNum) {
215 if (m_pParser && m_pParser->IsValidObjectNumber(objnum) &&
216 !m_pParser->IsObjectFree(objnum)) {
219 m_NewObjNumArray.insert(std::lower_bound(m_NewObjNumArray.begin(),
220 m_NewObjNumArray.end(), objnum),
226 DCHECK(m_iStage > Stage::kInvalid || m_iStage < Stage::kInitWriteObjs20);
227 if (m_iStage == Stage::kInit0) {
228 if (!m_pParser || (m_bSecurityChanged && m_IsOriginal))
229 m_IsIncremental =
false;
231 m_iStage = Stage::kWriteHeader10;
233 if (m_iStage == Stage::kWriteHeader10) {
234 if (!m_IsIncremental) {
235 if (!m_Archive->WriteString(
"%PDF-1."))
236 return Stage::kInvalid;
240 version = m_FileVersion;
242 version = m_pParser->GetFileVersion();
244 if (!m_Archive->WriteDWord(version % 10) ||
245 !m_Archive->WriteString(
"\r\n%\xA1\xB3\xC5\xD7\r\n")) {
246 return Stage::kInvalid;
248 m_iStage = Stage::kInitWriteObjs20;
250 m_SavedOffset = m_pParser->GetDocumentSize();
251 m_iStage = Stage::kWriteIncremental15;
254 if (m_iStage == Stage::kWriteIncremental15) {
255 if (m_IsOriginal && m_SavedOffset > 0) {
256 if (!m_pParser->WriteToArchive(m_Archive.get(), m_SavedOffset))
257 return Stage::kInvalid;
259 if (m_IsOriginal && m_pParser->GetLastXRefOffset() == 0) {
260 for (uint32_t num = 0; num <= m_pParser->GetLastObjNum(); ++num) {
261 if (m_pParser->IsObjectFree(num)) {
265 m_ObjectOffsets[num] = m_pParser->GetObjectPositionOrZero(num);
268 m_iStage = Stage::kInitWriteObjs20;
270 InitNewObjNumOffsets();
275 DCHECK(m_iStage >= Stage::kInitWriteObjs20 ||
276 m_iStage < Stage::kInitWriteXRefs80);
277 if (m_iStage == Stage::kInitWriteObjs20) {
278 if (!m_IsIncremental && m_pParser) {
280 m_iStage = Stage::kWriteOldObjs21;
282 m_iStage = Stage::kInitWriteNewObjs25;
285 if (m_iStage == Stage::kWriteOldObjs21) {
287 return Stage::kInvalid;
289 m_iStage = Stage::kInitWriteNewObjs25;
291 if (m_iStage == Stage::kInitWriteNewObjs25) {
293 m_iStage = Stage::kWriteNewObjs26;
295 if (m_iStage == Stage::kWriteNewObjs26) {
297 return Stage::kInvalid;
299 m_iStage = Stage::kWriteEncryptDict27;
301 if (m_iStage == Stage::kWriteEncryptDict27) {
302 if (m_pEncryptDict && m_pEncryptDict->IsInline()) {
304 FX_FILESIZE saveOffset = m_Archive->CurrentOffset();
305 if (!WriteIndirectObj(m_dwLastObjNum, m_pEncryptDict.Get()))
306 return Stage::kInvalid;
308 m_ObjectOffsets[m_dwLastObjNum] = saveOffset;
310 m_NewObjNumArray.push_back(m_dwLastObjNum);
312 m_iStage = Stage::kInitWriteXRefs80;
318 DCHECK(m_iStage >= Stage::kInitWriteXRefs80 ||
319 m_iStage < Stage::kWriteTrailerAndFinish90);
321 uint32_t dwLastObjNum = m_dwLastObjNum;
322 if (m_iStage == Stage::kInitWriteXRefs80) {
323 m_XrefStart = m_Archive->CurrentOffset();
324 if (!m_IsIncremental || !m_pParser->IsXRefStream()) {
325 if (!m_IsIncremental || m_pParser->GetLastXRefOffset() == 0) {
327 str = pdfium::Contains(m_ObjectOffsets, 1)
329 :
"xref\r\n0 1\r\n0000000000 65535 f\r\n";
330 if (!m_Archive->WriteString(str.AsStringView()))
331 return Stage::kInvalid;
334 m_iStage = Stage::kWriteXrefsNotIncremental81;
336 if (!m_Archive->WriteString(
"xref\r\n"))
337 return Stage::kInvalid;
340 m_iStage = Stage::kWriteXrefsIncremental82;
343 m_iStage = Stage::kWriteTrailerAndFinish90;
346 if (m_iStage == Stage::kWriteXrefsNotIncremental81) {
348 uint32_t i = m_CurObjNum;
350 while (i <= dwLastObjNum) {
351 while (i <= dwLastObjNum && !pdfium::Contains(m_ObjectOffsets, i))
354 if (i > dwLastObjNum)
358 while (j <= dwLastObjNum && pdfium::Contains(m_ObjectOffsets, j))
366 if (!m_Archive->WriteString(str.AsStringView()))
367 return Stage::kInvalid;
370 str = ByteString::Format(
"%010d 00000 n\r\n", m_ObjectOffsets[i++]);
371 if (!m_Archive->WriteString(str.AsStringView()))
372 return Stage::kInvalid;
374 if (i > dwLastObjNum)
377 m_iStage = Stage::kWriteTrailerAndFinish90;
379 if (m_iStage == Stage::kWriteXrefsIncremental82) {
381 uint32_t iCount = fxcrt::CollectionSize<uint32_t>(m_NewObjNumArray);
382 uint32_t i = m_CurObjNum;
385 uint32_t objnum = m_NewObjNumArray[i];
389 uint32_t dwCurrent = m_NewObjNumArray[j];
390 if (dwCurrent - objnum > 1)
394 objnum = m_NewObjNumArray[i];
400 if (!m_Archive->WriteString(str.AsStringView()))
401 return Stage::kInvalid;
404 objnum = m_NewObjNumArray[i++];
405 str = ByteString::Format(
"%010d 00000 n\r\n", m_ObjectOffsets[objnum]);
406 if (!m_Archive->WriteString(str.AsStringView()))
407 return Stage::kInvalid;
410 m_iStage = Stage::kWriteTrailerAndFinish90;
416 DCHECK(m_iStage >= Stage::kWriteTrailerAndFinish90);
418 bool bXRefStream = m_IsIncremental && m_pParser->IsXRefStream();
420 if (!m_Archive->WriteString(
"trailer\r\n<<"))
421 return Stage::kInvalid;
423 if (!m_Archive->WriteDWord(m_pDocument->GetLastObjNum() + 1) ||
424 !m_Archive->WriteString(
" 0 obj <<")) {
425 return Stage::kInvalid;
431 for (
const auto& it : locker) {
432 const ByteString& key = it.first;
433 const RetainPtr<CPDF_Object>& pValue = it.second;
434 if (key ==
"Encrypt" || key ==
"Size" || key ==
"Filter" ||
435 key ==
"Index" || key ==
"Length" || key ==
"Prev" || key ==
"W" ||
436 key ==
"XRefStm" || key ==
"ID" || key ==
"DecodeParms" ||
440 if (!m_Archive->WriteString((
"/")) ||
441 !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) {
442 return Stage::kInvalid;
444 if (!pValue->WriteTo(m_Archive.get(),
nullptr))
445 return Stage::kInvalid;
448 if (!m_Archive->WriteString(
"\r\n/Root ") ||
449 !m_Archive->WriteDWord(m_pDocument->GetRoot()->GetObjNum()) ||
450 !m_Archive->WriteString(
" 0 R\r\n")) {
451 return Stage::kInvalid;
453 if (m_pDocument->GetInfo()) {
454 if (!m_Archive->WriteString(
"/Info ") ||
455 !m_Archive->WriteDWord(m_pDocument->GetInfo()->GetObjNum()) ||
456 !m_Archive->WriteString(
" 0 R\r\n")) {
457 return Stage::kInvalid;
461 if (m_pEncryptDict) {
462 if (!m_Archive->WriteString(
"/Encrypt"))
463 return Stage::kInvalid;
465 uint32_t dwObjNum = m_pEncryptDict->GetObjNum();
467 dwObjNum = m_pDocument->GetLastObjNum() + 1;
468 if (!m_Archive->WriteString(
" ") || !m_Archive->WriteDWord(dwObjNum) ||
469 !m_Archive->WriteString(
" 0 R ")) {
470 return Stage::kInvalid;
474 if (!m_Archive->WriteString(
"/Size ") ||
475 !m_Archive->WriteDWord(m_dwLastObjNum + (bXRefStream ? 2 : 1))) {
476 return Stage::kInvalid;
478 if (m_IsIncremental) {
481 if (!m_Archive->WriteString(
"/Prev ") || !m_Archive->WriteFilesize(prev))
482 return Stage::kInvalid;
486 if (!m_Archive->WriteString((
"/ID")) ||
487 !m_pIDArray->WriteTo(m_Archive.get(),
nullptr)) {
488 return Stage::kInvalid;
492 if (!m_Archive->WriteString(
">>"))
493 return Stage::kInvalid;
495 if (!m_Archive->WriteString(
"/W[0 4 1]/Index["))
496 return Stage::kInvalid;
497 if (m_IsIncremental && m_pParser && m_pParser->GetLastXRefOffset() == 0) {
499 for (i = 0; i < m_dwLastObjNum; i++) {
500 if (!pdfium::Contains(m_ObjectOffsets, i))
502 if (!m_Archive->WriteDWord(i) || !m_Archive->WriteString(
" 1 "))
503 return Stage::kInvalid;
505 if (!m_Archive->WriteString(
"]/Length ") ||
506 !m_Archive->WriteDWord(m_dwLastObjNum * 5) ||
507 !m_Archive->WriteString(
">>stream\r\n")) {
508 return Stage::kInvalid;
510 for (i = 0; i < m_dwLastObjNum; i++) {
511 auto it = m_ObjectOffsets.find(i);
512 if (it == m_ObjectOffsets.end())
514 if (!OutputIndex(m_Archive.get(), it->second))
515 return Stage::kInvalid;
518 int count = fxcrt::CollectionSize<
int>(m_NewObjNumArray);
520 for (i = 0; i < count; i++) {
521 if (!m_Archive->WriteDWord(m_NewObjNumArray[i]) ||
522 !m_Archive->WriteString(
" 1 ")) {
523 return Stage::kInvalid;
526 if (!m_Archive->WriteString(
"]/Length ") ||
527 !m_Archive->WriteDWord(count * 5) ||
528 !m_Archive->WriteString(
">>stream\r\n")) {
529 return Stage::kInvalid;
531 for (i = 0; i < count; ++i) {
532 if (!OutputIndex(m_Archive.get(), m_ObjectOffsets[m_NewObjNumArray[i]]))
533 return Stage::kInvalid;
536 if (!m_Archive->WriteString(
"\r\nendstream"))
537 return Stage::kInvalid;
540 if (!m_Archive->WriteString(
"\r\nstartxref\r\n") ||
541 !m_Archive->WriteFilesize(m_XrefStart) ||
542 !m_Archive->WriteString(
"\r\n%%EOF\r\n")) {
543 return Stage::kInvalid;
546 m_iStage = Stage::kComplete100;
554 m_iStage = Stage::kInit0;
555 m_dwLastObjNum = m_pDocument->GetLastObjNum();
556 m_ObjectOffsets.clear();
557 m_NewObjNumArray.clear();
566 m_pIDArray = pdfium::MakeRetain<CPDF_Array>();
568 m_pParser ? m_pParser->GetIDArray() :
nullptr;
570 pOldIDArray ? pOldIDArray->GetObjectAt(0) :
nullptr;
572 m_pIDArray->Append(pID1->Clone());
574 std::array<uint32_t, 4> file_id =
575 GenerateFileID((uint32_t)(uintptr_t)
this, m_dwLastObjNum);
576 m_pIDArray->AppendNew<CPDF_String>(pdfium::as_byte_span(file_id),
577 CPDF_String::DataType::kIsHex);
582 if (m_IsIncremental && m_pEncryptDict && pID2) {
583 m_pIDArray->Append(pID2->Clone());
586 std::array<uint32_t, 4> file_id =
587 GenerateFileID((uint32_t)(uintptr_t)
this, m_dwLastObjNum);
588 m_pIDArray->AppendNew<CPDF_String>(pdfium::as_byte_span(file_id),
589 CPDF_String::DataType::kIsHex);
593 m_pIDArray->Append(m_pIDArray->GetObjectAt(0)->Clone());
594 if (m_pEncryptDict) {
596 int revision = m_pEncryptDict->GetIntegerFor(
"R");
597 if ((revision == 2 || revision == 3) &&
598 m_pEncryptDict->GetByteStringFor(
"Filter") ==
"Standard") {
599 m_pNewEncryptDict = ToDictionary(m_pEncryptDict->Clone());
600 m_pEncryptDict = m_pNewEncryptDict;
601 m_pSecurityHandler = pdfium::MakeRetain<CPDF_SecurityHandler>();
602 m_pSecurityHandler->OnCreate(m_pNewEncryptDict.Get(), m_pIDArray.Get(),
603 m_pParser->GetEncodedPassword());
604 m_bSecurityChanged =
true;
610 if (m_iStage < Stage::kInit0)
613 Stage iRet = Stage::kInit0;
614 while (m_iStage < Stage::kComplete100) {
615 if (m_iStage < Stage::kInitWriteObjs20)
616 iRet = WriteDoc_Stage1();
617 else if (m_iStage < Stage::kInitWriteXRefs80)
618 iRet = WriteDoc_Stage2();
619 else if (m_iStage < Stage::kWriteTrailerAndFinish90)
620 iRet = WriteDoc_Stage3();
622 iRet = WriteDoc_Stage4();
628 if (iRet <= Stage::kInit0 || m_iStage == Stage::kComplete100) {
629 m_iStage = Stage::kInvalid;
630 return iRet > Stage::kInit0;
633 return m_iStage > Stage::kInvalid;
637 if (fileVersion < 10 || fileVersion > 17)
639 m_FileVersion = fileVersion;
644 m_pSecurityHandler.Reset();
645 m_bSecurityChanged =
true;
646 m_pEncryptDict =
nullptr;
647 m_pNewEncryptDict.Reset();
651 return m_pSecurityHandler ? m_pSecurityHandler->GetCryptoHandler() :
nullptr;
fxcrt::ByteString ByteString
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
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)
void FX_Random_MT_Close(void *pContext)
pdfium::CheckedNumeric< FX_FILESIZE > FX_SAFE_FILESIZE