1 // Copyright 2014 The PDFium Authors
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 <stdint.h>
10
11 #include <algorithm>
12 #include <array>
13 #include <set>
14 #include <utility>
15
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"
37
38 namespace {
39
40 const size_t kArchiveBufferSize = 32768;
41
42 class CFX_FileBufferArchive final : public IFX_ArchiveStream {
43 public:
44 explicit CFX_FileBufferArchive(RetainPtr<IFX_RetainableWriteStream> file);
45 ~CFX_FileBufferArchive() override;
46
47 bool WriteBlock(pdfium::span<const uint8_t> buffer) override;
CurrentOffset() const48 FX_FILESIZE CurrentOffset() const override { return offset_; }
49
50 private:
51 bool Flush();
52
53 FX_FILESIZE offset_ = 0;
54 FixedSizeDataVector<uint8_t> buffer_;
55 pdfium::raw_span<uint8_t> available_;
56 RetainPtr<IFX_RetainableWriteStream> const backing_file_;
57 };
58
CFX_FileBufferArchive(RetainPtr<IFX_RetainableWriteStream> file)59 CFX_FileBufferArchive::CFX_FileBufferArchive(
60 RetainPtr<IFX_RetainableWriteStream> file)
61 : buffer_(FixedSizeDataVector<uint8_t>::Uninit(kArchiveBufferSize)),
62 available_(buffer_.span()),
63 backing_file_(std::move(file)) {
64 DCHECK(backing_file_);
65 }
66
~CFX_FileBufferArchive()67 CFX_FileBufferArchive::~CFX_FileBufferArchive() {
68 Flush();
69 }
70
Flush()71 bool 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));
75 }
76
WriteBlock(pdfium::span<const uint8_t> buffer)77 bool CFX_FileBufferArchive::WriteBlock(pdfium::span<const uint8_t> buffer) {
78 if (buffer.empty())
79 return true;
80
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())
87 return false;
88 }
89
90 FX_SAFE_FILESIZE safe_offset = offset_;
91 safe_offset += buffer.size();
92 if (!safe_offset.IsValid())
93 return false;
94
95 offset_ = safe_offset.ValueOrDie();
96 return true;
97 }
98
GenerateFileID(uint32_t dwSeed1,uint32_t dwSeed2)99 std::array<uint32_t, 4> GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) {
100 void* pContext1 = FX_Random_MT_Start(dwSeed1);
101 void* pContext2 = FX_Random_MT_Start(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)};
105 FX_Random_MT_Close(pContext1);
106 FX_Random_MT_Close(pContext2);
107 return buffer;
108 }
109
OutputIndex(IFX_ArchiveStream * archive,FX_FILESIZE offset)110 bool OutputIndex(IFX_ArchiveStream* archive, FX_FILESIZE offset) {
111 return archive->WriteByte(static_cast<uint8_t>(offset >> 24)) &&
112 archive->WriteByte(static_cast<uint8_t>(offset >> 16)) &&
113 archive->WriteByte(static_cast<uint8_t>(offset >> 8)) &&
114 archive->WriteByte(static_cast<uint8_t>(offset)) &&
115 archive->WriteByte(0);
116 }
117
118 } // namespace
119
CPDF_Creator(CPDF_Document * pDoc,RetainPtr<IFX_RetainableWriteStream> archive)120 CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc,
121 RetainPtr<IFX_RetainableWriteStream> archive)
122 : m_pDocument(pDoc),
123 m_pParser(pDoc->GetParser()),
124 m_pEncryptDict(m_pParser ? m_pParser->GetEncryptDict() : nullptr),
125 m_pSecurityHandler(m_pParser ? m_pParser->GetSecurityHandler() : nullptr),
126 m_dwLastObjNum(m_pDocument->GetLastObjNum()),
127 m_Archive(std::make_unique<CFX_FileBufferArchive>(std::move(archive))) {}
128
129 CPDF_Creator::~CPDF_Creator() = default;
130
WriteIndirectObj(uint32_t objnum,const CPDF_Object * pObj)131 bool CPDF_Creator::WriteIndirectObj(uint32_t objnum, const CPDF_Object* pObj) {
132 if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(" 0 obj\r\n"))
133 return false;
134
135 std::unique_ptr<CPDF_Encryptor> encryptor;
136 if (GetCryptoHandler() && pObj != m_pEncryptDict)
137 encryptor = std::make_unique<CPDF_Encryptor>(GetCryptoHandler(), objnum);
138
139 if (!pObj->WriteTo(m_Archive.get(), encryptor.get()))
140 return false;
141
142 return m_Archive->WriteString("\r\nendobj\r\n");
143 }
144
WriteOldIndirectObject(uint32_t objnum)145 bool CPDF_Creator::WriteOldIndirectObject(uint32_t objnum) {
146 if (m_pParser->IsObjectFree(objnum)) {
147 return true;
148 }
149
150 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
151
152 bool bExistInMap = !!m_pDocument->GetIndirectObject(objnum);
153 RetainPtr<CPDF_Object> pObj = m_pDocument->GetOrParseIndirectObject(objnum);
154 if (!pObj) {
155 m_ObjectOffsets.erase(objnum);
156 return true;
157 }
158 if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get()))
159 return false;
160 if (!bExistInMap)
161 m_pDocument->DeleteIndirectObject(objnum);
162 return true;
163 }
164
WriteOldObjs()165 bool CPDF_Creator::WriteOldObjs() {
166 const uint32_t nLastObjNum = m_pParser->GetLastObjNum();
167 if (!m_pParser->IsValidObjectNumber(nLastObjNum)) {
168 return true;
169 }
170 if (m_CurObjNum > nLastObjNum) {
171 return true;
172 }
173
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)) {
179 continue;
180 }
181 if (!WriteOldIndirectObject(objnum)) {
182 return false;
183 }
184 last_object_number_written = objnum;
185 }
186 // If there are no new objects to write, then adjust `m_dwLastObjNum` if
187 // needed to reflect the actual last object number.
188 if (m_NewObjNumArray.empty()) {
189 m_dwLastObjNum = last_object_number_written;
190 }
191 return true;
192 }
193
WriteNewObjs()194 bool CPDF_Creator::WriteNewObjs() {
195 for (size_t i = m_CurObjNum; i < m_NewObjNumArray.size(); ++i) {
196 uint32_t objnum = m_NewObjNumArray[i];
197 RetainPtr<const CPDF_Object> pObj = m_pDocument->GetIndirectObject(objnum);
198 if (!pObj)
199 continue;
200
201 m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
202 if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get()))
203 return false;
204 }
205 return true;
206 }
207
InitNewObjNumOffsets()208 void CPDF_Creator::InitNewObjNumOffsets() {
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) {
213 continue;
214 }
215 if (m_pParser && m_pParser->IsValidObjectNumber(objnum) &&
216 !m_pParser->IsObjectFree(objnum)) {
217 continue;
218 }
219 m_NewObjNumArray.insert(std::lower_bound(m_NewObjNumArray.begin(),
220 m_NewObjNumArray.end(), objnum),
221 objnum);
222 }
223 }
224
WriteDoc_Stage1()225 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage1() {
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;
230
231 m_iStage = Stage::kWriteHeader10;
232 }
233 if (m_iStage == Stage::kWriteHeader10) {
234 if (!m_IsIncremental) {
235 if (!m_Archive->WriteString("%PDF-1."))
236 return Stage::kInvalid;
237
238 int32_t version = 7;
239 if (m_FileVersion)
240 version = m_FileVersion;
241 else if (m_pParser)
242 version = m_pParser->GetFileVersion();
243
244 if (!m_Archive->WriteDWord(version % 10) ||
245 !m_Archive->WriteString("\r\n%\xA1\xB3\xC5\xD7\r\n")) {
246 return Stage::kInvalid;
247 }
248 m_iStage = Stage::kInitWriteObjs20;
249 } else {
250 m_SavedOffset = m_pParser->GetDocumentSize();
251 m_iStage = Stage::kWriteIncremental15;
252 }
253 }
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;
258 }
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)) {
262 continue;
263 }
264
265 m_ObjectOffsets[num] = m_pParser->GetObjectPositionOrZero(num);
266 }
267 }
268 m_iStage = Stage::kInitWriteObjs20;
269 }
270 InitNewObjNumOffsets();
271 return m_iStage;
272 }
273
WriteDoc_Stage2()274 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage2() {
275 DCHECK(m_iStage >= Stage::kInitWriteObjs20 ||
276 m_iStage < Stage::kInitWriteXRefs80);
277 if (m_iStage == Stage::kInitWriteObjs20) {
278 if (!m_IsIncremental && m_pParser) {
279 m_CurObjNum = 0;
280 m_iStage = Stage::kWriteOldObjs21;
281 } else {
282 m_iStage = Stage::kInitWriteNewObjs25;
283 }
284 }
285 if (m_iStage == Stage::kWriteOldObjs21) {
286 if (!WriteOldObjs())
287 return Stage::kInvalid;
288
289 m_iStage = Stage::kInitWriteNewObjs25;
290 }
291 if (m_iStage == Stage::kInitWriteNewObjs25) {
292 m_CurObjNum = 0;
293 m_iStage = Stage::kWriteNewObjs26;
294 }
295 if (m_iStage == Stage::kWriteNewObjs26) {
296 if (!WriteNewObjs())
297 return Stage::kInvalid;
298
299 m_iStage = Stage::kWriteEncryptDict27;
300 }
301 if (m_iStage == Stage::kWriteEncryptDict27) {
302 if (m_pEncryptDict && m_pEncryptDict->IsInline()) {
303 m_dwLastObjNum += 1;
304 FX_FILESIZE saveOffset = m_Archive->CurrentOffset();
305 if (!WriteIndirectObj(m_dwLastObjNum, m_pEncryptDict.Get()))
306 return Stage::kInvalid;
307
308 m_ObjectOffsets[m_dwLastObjNum] = saveOffset;
309 if (m_IsIncremental)
310 m_NewObjNumArray.push_back(m_dwLastObjNum);
311 }
312 m_iStage = Stage::kInitWriteXRefs80;
313 }
314 return m_iStage;
315 }
316
WriteDoc_Stage3()317 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage3() {
318 DCHECK(m_iStage >= Stage::kInitWriteXRefs80 ||
319 m_iStage < Stage::kWriteTrailerAndFinish90);
320
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) {
326 ByteString str;
327 str = pdfium::Contains(m_ObjectOffsets, 1)
328 ? "xref\r\n"
329 : "xref\r\n0 1\r\n0000000000 65535 f\r\n";
330 if (!m_Archive->WriteString(str.AsStringView()))
331 return Stage::kInvalid;
332
333 m_CurObjNum = 1;
334 m_iStage = Stage::kWriteXrefsNotIncremental81;
335 } else {
336 if (!m_Archive->WriteString("xref\r\n"))
337 return Stage::kInvalid;
338
339 m_CurObjNum = 0;
340 m_iStage = Stage::kWriteXrefsIncremental82;
341 }
342 } else {
343 m_iStage = Stage::kWriteTrailerAndFinish90;
344 }
345 }
346 if (m_iStage == Stage::kWriteXrefsNotIncremental81) {
347 ByteString str;
348 uint32_t i = m_CurObjNum;
349 uint32_t j;
350 while (i <= dwLastObjNum) {
351 while (i <= dwLastObjNum && !pdfium::Contains(m_ObjectOffsets, i))
352 i++;
353
354 if (i > dwLastObjNum)
355 break;
356
357 j = i;
358 while (j <= dwLastObjNum && pdfium::Contains(m_ObjectOffsets, j))
359 j++;
360
361 if (i == 1)
362 str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j);
363 else
364 str = ByteString::Format("%d %d\r\n", i, j - i);
365
366 if (!m_Archive->WriteString(str.AsStringView()))
367 return Stage::kInvalid;
368
369 while (i < j) {
370 str = ByteString::Format("%010d 00000 n\r\n", m_ObjectOffsets[i++]);
371 if (!m_Archive->WriteString(str.AsStringView()))
372 return Stage::kInvalid;
373 }
374 if (i > dwLastObjNum)
375 break;
376 }
377 m_iStage = Stage::kWriteTrailerAndFinish90;
378 }
379 if (m_iStage == Stage::kWriteXrefsIncremental82) {
380 ByteString str;
381 uint32_t iCount = fxcrt::CollectionSize<uint32_t>(m_NewObjNumArray);
382 uint32_t i = m_CurObjNum;
383 while (i < iCount) {
384 size_t j = i;
385 uint32_t objnum = m_NewObjNumArray[i];
386 while (j < iCount) {
387 if (++j == iCount)
388 break;
389 uint32_t dwCurrent = m_NewObjNumArray[j];
390 if (dwCurrent - objnum > 1)
391 break;
392 objnum = dwCurrent;
393 }
394 objnum = m_NewObjNumArray[i];
395 if (objnum == 1)
396 str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j - i + 1);
397 else
398 str = ByteString::Format("%d %d\r\n", objnum, j - i);
399
400 if (!m_Archive->WriteString(str.AsStringView()))
401 return Stage::kInvalid;
402
403 while (i < j) {
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;
408 }
409 }
410 m_iStage = Stage::kWriteTrailerAndFinish90;
411 }
412 return m_iStage;
413 }
414
WriteDoc_Stage4()415 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage4() {
416 DCHECK(m_iStage >= Stage::kWriteTrailerAndFinish90);
417
418 bool bXRefStream = m_IsIncremental && m_pParser->IsXRefStream();
419 if (!bXRefStream) {
420 if (!m_Archive->WriteString("trailer\r\n<<"))
421 return Stage::kInvalid;
422 } else {
423 if (!m_Archive->WriteDWord(m_pDocument->GetLastObjNum() + 1) ||
424 !m_Archive->WriteString(" 0 obj <<")) {
425 return Stage::kInvalid;
426 }
427 }
428
429 if (m_pParser) {
430 CPDF_DictionaryLocker locker(m_pParser->GetCombinedTrailer());
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" ||
437 key == "Type") {
438 continue;
439 }
440 if (!m_Archive->WriteString(("/")) ||
441 !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) {
442 return Stage::kInvalid;
443 }
444 if (!pValue->WriteTo(m_Archive.get(), nullptr))
445 return Stage::kInvalid;
446 }
447 } else {
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;
452 }
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;
458 }
459 }
460 }
461 if (m_pEncryptDict) {
462 if (!m_Archive->WriteString("/Encrypt"))
463 return Stage::kInvalid;
464
465 uint32_t dwObjNum = m_pEncryptDict->GetObjNum();
466 if (dwObjNum == 0)
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;
471 }
472 }
473
474 if (!m_Archive->WriteString("/Size ") ||
475 !m_Archive->WriteDWord(m_dwLastObjNum + (bXRefStream ? 2 : 1))) {
476 return Stage::kInvalid;
477 }
478 if (m_IsIncremental) {
479 FX_FILESIZE prev = m_pParser->GetLastXRefOffset();
480 if (prev) {
481 if (!m_Archive->WriteString("/Prev ") || !m_Archive->WriteFilesize(prev))
482 return Stage::kInvalid;
483 }
484 }
485 if (m_pIDArray) {
486 if (!m_Archive->WriteString(("/ID")) ||
487 !m_pIDArray->WriteTo(m_Archive.get(), nullptr)) {
488 return Stage::kInvalid;
489 }
490 }
491 if (!bXRefStream) {
492 if (!m_Archive->WriteString(">>"))
493 return Stage::kInvalid;
494 } else {
495 if (!m_Archive->WriteString("/W[0 4 1]/Index["))
496 return Stage::kInvalid;
497 if (m_IsIncremental && m_pParser && m_pParser->GetLastXRefOffset() == 0) {
498 uint32_t i = 0;
499 for (i = 0; i < m_dwLastObjNum; i++) {
500 if (!pdfium::Contains(m_ObjectOffsets, i))
501 continue;
502 if (!m_Archive->WriteDWord(i) || !m_Archive->WriteString(" 1 "))
503 return Stage::kInvalid;
504 }
505 if (!m_Archive->WriteString("]/Length ") ||
506 !m_Archive->WriteDWord(m_dwLastObjNum * 5) ||
507 !m_Archive->WriteString(">>stream\r\n")) {
508 return Stage::kInvalid;
509 }
510 for (i = 0; i < m_dwLastObjNum; i++) {
511 auto it = m_ObjectOffsets.find(i);
512 if (it == m_ObjectOffsets.end())
513 continue;
514 if (!OutputIndex(m_Archive.get(), it->second))
515 return Stage::kInvalid;
516 }
517 } else {
518 int count = fxcrt::CollectionSize<int>(m_NewObjNumArray);
519 int i = 0;
520 for (i = 0; i < count; i++) {
521 if (!m_Archive->WriteDWord(m_NewObjNumArray[i]) ||
522 !m_Archive->WriteString(" 1 ")) {
523 return Stage::kInvalid;
524 }
525 }
526 if (!m_Archive->WriteString("]/Length ") ||
527 !m_Archive->WriteDWord(count * 5) ||
528 !m_Archive->WriteString(">>stream\r\n")) {
529 return Stage::kInvalid;
530 }
531 for (i = 0; i < count; ++i) {
532 if (!OutputIndex(m_Archive.get(), m_ObjectOffsets[m_NewObjNumArray[i]]))
533 return Stage::kInvalid;
534 }
535 }
536 if (!m_Archive->WriteString("\r\nendstream"))
537 return Stage::kInvalid;
538 }
539
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;
544 }
545
546 m_iStage = Stage::kComplete100;
547 return m_iStage;
548 }
549
Create(uint32_t flags)550 bool CPDF_Creator::Create(uint32_t flags) {
551 m_IsIncremental = !!(flags & FPDFCREATE_INCREMENTAL);
552 m_IsOriginal = !(flags & FPDFCREATE_NO_ORIGINAL);
553
554 m_iStage = Stage::kInit0;
555 m_dwLastObjNum = m_pDocument->GetLastObjNum();
556 m_ObjectOffsets.clear();
557 m_NewObjNumArray.clear();
558
559 InitID();
560 return Continue();
561 }
562
InitID()563 void CPDF_Creator::InitID() {
564 DCHECK(!m_pIDArray);
565
566 m_pIDArray = pdfium::MakeRetain<CPDF_Array>();
567 RetainPtr<const CPDF_Array> pOldIDArray =
568 m_pParser ? m_pParser->GetIDArray() : nullptr;
569 RetainPtr<const CPDF_Object> pID1 =
570 pOldIDArray ? pOldIDArray->GetObjectAt(0) : nullptr;
571 if (pID1) {
572 m_pIDArray->Append(pID1->Clone());
573 } else {
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);
578 }
579
580 if (pOldIDArray) {
581 RetainPtr<const CPDF_Object> pID2 = pOldIDArray->GetObjectAt(1);
582 if (m_IsIncremental && m_pEncryptDict && pID2) {
583 m_pIDArray->Append(pID2->Clone());
584 return;
585 }
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);
590 return;
591 }
592
593 m_pIDArray->Append(m_pIDArray->GetObjectAt(0)->Clone());
594 if (m_pEncryptDict) {
595 DCHECK(m_pParser);
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;
605 }
606 }
607 }
608
Continue()609 bool CPDF_Creator::Continue() {
610 if (m_iStage < Stage::kInit0)
611 return false;
612
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();
621 else
622 iRet = WriteDoc_Stage4();
623
624 if (iRet < m_iStage)
625 break;
626 }
627
628 if (iRet <= Stage::kInit0 || m_iStage == Stage::kComplete100) {
629 m_iStage = Stage::kInvalid;
630 return iRet > Stage::kInit0;
631 }
632
633 return m_iStage > Stage::kInvalid;
634 }
635
SetFileVersion(int32_t fileVersion)636 bool CPDF_Creator::SetFileVersion(int32_t fileVersion) {
637 if (fileVersion < 10 || fileVersion > 17)
638 return false;
639 m_FileVersion = fileVersion;
640 return true;
641 }
642
RemoveSecurity()643 void CPDF_Creator::RemoveSecurity() {
644 m_pSecurityHandler.Reset();
645 m_bSecurityChanged = true;
646 m_pEncryptDict = nullptr;
647 m_pNewEncryptDict.Reset();
648 }
649
GetCryptoHandler()650 CPDF_CryptoHandler* CPDF_Creator::GetCryptoHandler() {
651 return m_pSecurityHandler ? m_pSecurityHandler->GetCryptoHandler() : nullptr;
652 }
653