• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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