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