1 // Copyright 2014 PDFium Authors. All rights reserved.
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 <algorithm>
10 
11 #include "core/fpdfapi/parser/cpdf_array.h"
12 #include "core/fpdfapi/parser/cpdf_crypto_handler.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_document.h"
15 #include "core/fpdfapi/parser/cpdf_encryptor.h"
16 #include "core/fpdfapi/parser/cpdf_flateencoder.h"
17 #include "core/fpdfapi/parser/cpdf_number.h"
18 #include "core/fpdfapi/parser/cpdf_parser.h"
19 #include "core/fpdfapi/parser/cpdf_security_handler.h"
20 #include "core/fpdfapi/parser/cpdf_string.h"
21 #include "core/fpdfapi/parser/cpdf_syntax_parser.h"
22 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
23 #include "core/fxcrt/fx_extension.h"
24 #include "core/fxcrt/fx_memory_wrappers.h"
25 #include "core/fxcrt/fx_random.h"
26 #include "core/fxcrt/fx_safe_types.h"
27 #include "third_party/base/ptr_util.h"
28 #include "third_party/base/stl_util.h"
29 
30 namespace {
31 
32 const size_t kArchiveBufferSize = 32768;
33 
34 class CFX_FileBufferArchive final : public IFX_ArchiveStream {
35  public:
36   explicit CFX_FileBufferArchive(
37       const RetainPtr<IFX_RetainableWriteStream>& file);
38   ~CFX_FileBufferArchive() override;
39 
40   bool WriteBlock(const void* pBuf, size_t size) override;
41   bool WriteByte(uint8_t byte) override;
42   bool WriteDWord(uint32_t i) override;
43   bool WriteString(ByteStringView str) override;
44 
CurrentOffset() const45   FX_FILESIZE CurrentOffset() const override { return offset_; }
46 
47  private:
48   bool Flush();
49 
50   FX_FILESIZE offset_;
51   size_t current_length_;
52   std::vector<uint8_t, FxAllocAllocator<uint8_t>> buffer_;
53   RetainPtr<IFX_RetainableWriteStream> backing_file_;
54 };
55 
CFX_FileBufferArchive(const RetainPtr<IFX_RetainableWriteStream> & file)56 CFX_FileBufferArchive::CFX_FileBufferArchive(
57     const RetainPtr<IFX_RetainableWriteStream>& file)
58     : offset_(0),
59       current_length_(0),
60       buffer_(kArchiveBufferSize),
61       backing_file_(file) {
62   ASSERT(file);
63 }
64 
~CFX_FileBufferArchive()65 CFX_FileBufferArchive::~CFX_FileBufferArchive() {
66   Flush();
67 }
68 
Flush()69 bool CFX_FileBufferArchive::Flush() {
70   size_t nRemaining = current_length_;
71   current_length_ = 0;
72   if (!backing_file_)
73     return false;
74   if (!nRemaining)
75     return true;
76   return backing_file_->WriteBlock(buffer_.data(), nRemaining);
77 }
78 
WriteBlock(const void * pBuf,size_t size)79 bool CFX_FileBufferArchive::WriteBlock(const void* pBuf, size_t size) {
80   ASSERT(pBuf);
81   ASSERT(size > 0);
82 
83   const uint8_t* buffer = reinterpret_cast<const uint8_t*>(pBuf);
84   size_t temp_size = size;
85   while (temp_size) {
86     size_t buf_size = std::min(kArchiveBufferSize - current_length_, temp_size);
87     memcpy(buffer_.data() + current_length_, buffer, buf_size);
88 
89     current_length_ += buf_size;
90     if (current_length_ == kArchiveBufferSize && !Flush())
91       return false;
92 
93     temp_size -= buf_size;
94     buffer += buf_size;
95   }
96 
97   FX_SAFE_FILESIZE safe_offset = offset_;
98   safe_offset += size;
99   if (!safe_offset.IsValid())
100     return false;
101 
102   offset_ = safe_offset.ValueOrDie();
103   return true;
104 }
105 
WriteByte(uint8_t byte)106 bool CFX_FileBufferArchive::WriteByte(uint8_t byte) {
107   return WriteBlock(&byte, 1);
108 }
109 
WriteDWord(uint32_t i)110 bool CFX_FileBufferArchive::WriteDWord(uint32_t i) {
111   char buf[32];
112   FXSYS_itoa(i, buf, 10);
113   return WriteBlock(buf, strlen(buf));
114 }
115 
WriteString(ByteStringView str)116 bool CFX_FileBufferArchive::WriteString(ByteStringView str) {
117   return WriteBlock(str.raw_str(), str.GetLength());
118 }
119 
GenerateFileID(uint32_t dwSeed1,uint32_t dwSeed2)120 ByteString GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) {
121   uint32_t buffer[4];
122   void* pContext1 = FX_Random_MT_Start(dwSeed1);
123   void* pContext2 = FX_Random_MT_Start(dwSeed2);
124   buffer[0] = FX_Random_MT_Generate(pContext1);
125   buffer[1] = FX_Random_MT_Generate(pContext1);
126   buffer[2] = FX_Random_MT_Generate(pContext2);
127   buffer[3] = FX_Random_MT_Generate(pContext2);
128   FX_Random_MT_Close(pContext1);
129   FX_Random_MT_Close(pContext2);
130   return ByteString(pdfium::as_bytes<uint32_t>(buffer));
131 }
132 
OutputIndex(IFX_ArchiveStream * archive,FX_FILESIZE offset)133 bool OutputIndex(IFX_ArchiveStream* archive, FX_FILESIZE offset) {
134   return archive->WriteByte(static_cast<uint8_t>(offset >> 24)) &&
135          archive->WriteByte(static_cast<uint8_t>(offset >> 16)) &&
136          archive->WriteByte(static_cast<uint8_t>(offset >> 8)) &&
137          archive->WriteByte(static_cast<uint8_t>(offset)) &&
138          archive->WriteByte(0);
139 }
140 
141 }  // namespace
142 
CPDF_Creator(CPDF_Document * pDoc,const RetainPtr<IFX_RetainableWriteStream> & archive)143 CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc,
144                            const RetainPtr<IFX_RetainableWriteStream>& archive)
145     : m_pDocument(pDoc),
146       m_pParser(pDoc->GetParser()),
147       m_pEncryptDict(m_pParser ? m_pParser->GetEncryptDict() : nullptr),
148       m_pSecurityHandler(m_pParser ? m_pParser->GetSecurityHandler() : nullptr),
149       m_dwLastObjNum(m_pDocument->GetLastObjNum()),
150       m_Archive(pdfium::MakeUnique<CFX_FileBufferArchive>(archive)) {}
151 
~CPDF_Creator()152 CPDF_Creator::~CPDF_Creator() {}
153 
WriteIndirectObj(uint32_t objnum,const CPDF_Object * pObj)154 bool CPDF_Creator::WriteIndirectObj(uint32_t objnum, const CPDF_Object* pObj) {
155   if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(" 0 obj\r\n"))
156     return false;
157 
158   std::unique_ptr<CPDF_Encryptor> encryptor;
159   if (GetCryptoHandler() && pObj != m_pEncryptDict)
160     encryptor = pdfium::MakeUnique<CPDF_Encryptor>(GetCryptoHandler(), objnum);
161 
162   if (!pObj->WriteTo(m_Archive.get(), encryptor.get()))
163     return false;
164 
165   return m_Archive->WriteString("\r\nendobj\r\n");
166 }
167 
WriteOldIndirectObject(uint32_t objnum)168 bool CPDF_Creator::WriteOldIndirectObject(uint32_t objnum) {
169   if (m_pParser->IsObjectFreeOrNull(objnum))
170     return true;
171 
172   m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
173 
174   bool bExistInMap = !!m_pDocument->GetIndirectObject(objnum);
175   CPDF_Object* pObj = m_pDocument->GetOrParseIndirectObject(objnum);
176   if (!pObj) {
177     m_ObjectOffsets.erase(objnum);
178     return true;
179   }
180   if (!WriteIndirectObj(pObj->GetObjNum(), pObj))
181     return false;
182   if (!bExistInMap)
183     m_pDocument->DeleteIndirectObject(objnum);
184   return true;
185 }
186 
WriteOldObjs()187 bool CPDF_Creator::WriteOldObjs() {
188   uint32_t nLastObjNum = m_pParser->GetLastObjNum();
189   if (!m_pParser->IsValidObjectNumber(nLastObjNum))
190     return true;
191 
192   for (uint32_t objnum = m_CurObjNum; objnum <= nLastObjNum; ++objnum) {
193     if (!WriteOldIndirectObject(objnum))
194       return false;
195   }
196   return true;
197 }
198 
WriteNewObjs()199 bool CPDF_Creator::WriteNewObjs() {
200   for (size_t i = m_CurObjNum; i < m_NewObjNumArray.size(); ++i) {
201     uint32_t objnum = m_NewObjNumArray[i];
202     CPDF_Object* pObj = m_pDocument->GetIndirectObject(objnum);
203     if (!pObj)
204       continue;
205 
206     m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
207     if (!WriteIndirectObj(pObj->GetObjNum(), pObj))
208       return false;
209   }
210   return true;
211 }
212 
InitNewObjNumOffsets()213 void CPDF_Creator::InitNewObjNumOffsets() {
214   for (const auto& pair : *m_pDocument) {
215     const uint32_t objnum = pair.first;
216     if (m_IsIncremental ||
217         pair.second->GetObjNum() == CPDF_Object::kInvalidObjNum) {
218       continue;
219     }
220     if (m_pParser && m_pParser->IsValidObjectNumber(objnum) &&
221         !m_pParser->IsObjectFree(objnum)) {
222       continue;
223     }
224     m_NewObjNumArray.insert(std::lower_bound(m_NewObjNumArray.begin(),
225                                              m_NewObjNumArray.end(), objnum),
226                             objnum);
227   }
228 }
229 
WriteDoc_Stage1()230 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage1() {
231   ASSERT(m_iStage > Stage::kInvalid || m_iStage < Stage::kInitWriteObjs20);
232   if (m_iStage == Stage::kInit0) {
233     if (!m_pParser || (m_bSecurityChanged && m_IsOriginal))
234       m_IsIncremental = false;
235 
236     const CPDF_Dictionary* pDict = m_pDocument->GetRoot();
237     m_pMetadata.Reset(pDict ? pDict->GetDirectObjectFor("Metadata") : nullptr);
238     m_iStage = Stage::kWriteHeader10;
239   }
240   if (m_iStage == Stage::kWriteHeader10) {
241     if (!m_IsIncremental) {
242       if (!m_Archive->WriteString("%PDF-1."))
243         return Stage::kInvalid;
244 
245       int32_t version = 7;
246       if (m_FileVersion)
247         version = m_FileVersion;
248       else if (m_pParser)
249         version = m_pParser->GetFileVersion();
250 
251       if (!m_Archive->WriteDWord(version % 10) ||
252           !m_Archive->WriteString("\r\n%\xA1\xB3\xC5\xD7\r\n")) {
253         return Stage::kInvalid;
254       }
255       m_iStage = Stage::kInitWriteObjs20;
256     } else {
257       m_SavedOffset = m_pParser->GetSyntax()->GetDocumentSize();
258       m_iStage = Stage::kWriteIncremental15;
259     }
260   }
261   if (m_iStage == Stage::kWriteIncremental15) {
262     if (m_IsOriginal && m_SavedOffset > 0) {
263       static constexpr FX_FILESIZE kBufferSize = 4096;
264       std::vector<uint8_t, FxAllocAllocator<uint8_t>> buffer(kBufferSize);
265       FX_FILESIZE src_size = m_SavedOffset;
266       m_pParser->GetSyntax()->SetPos(0);
267       while (src_size) {
268         const FX_FILESIZE block_size = std::min(kBufferSize, src_size);
269         if (!m_pParser->GetSyntax()->ReadBlock(buffer.data(), block_size)) {
270           return Stage::kInvalid;
271         }
272         if (!m_Archive->WriteBlock(buffer.data(), block_size))
273           return Stage::kInvalid;
274 
275         src_size -= block_size;
276       }
277     }
278     if (m_IsOriginal && m_pParser->GetLastXRefOffset() == 0) {
279       for (uint32_t num = 0; num <= m_pParser->GetLastObjNum(); ++num) {
280         if (m_pParser->IsObjectFreeOrNull(num))
281           continue;
282 
283         m_ObjectOffsets[num] = m_pParser->GetObjectPositionOrZero(num);
284       }
285     }
286     m_iStage = Stage::kInitWriteObjs20;
287   }
288   InitNewObjNumOffsets();
289   return m_iStage;
290 }
291 
WriteDoc_Stage2()292 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage2() {
293   ASSERT(m_iStage >= Stage::kInitWriteObjs20 ||
294          m_iStage < Stage::kInitWriteXRefs80);
295   if (m_iStage == Stage::kInitWriteObjs20) {
296     if (!m_IsIncremental && m_pParser) {
297       m_CurObjNum = 0;
298       m_iStage = Stage::kWriteOldObjs21;
299     } else {
300       m_iStage = Stage::kInitWriteNewObjs25;
301     }
302   }
303   if (m_iStage == Stage::kWriteOldObjs21) {
304     if (!WriteOldObjs())
305       return Stage::kInvalid;
306 
307     m_iStage = Stage::kInitWriteNewObjs25;
308   }
309   if (m_iStage == Stage::kInitWriteNewObjs25) {
310     m_CurObjNum = 0;
311     m_iStage = Stage::kWriteNewObjs26;
312   }
313   if (m_iStage == Stage::kWriteNewObjs26) {
314     if (!WriteNewObjs())
315       return Stage::kInvalid;
316 
317     m_iStage = Stage::kWriteEncryptDict27;
318   }
319   if (m_iStage == Stage::kWriteEncryptDict27) {
320     if (m_pEncryptDict && m_pEncryptDict->IsInline()) {
321       m_dwLastObjNum += 1;
322       FX_FILESIZE saveOffset = m_Archive->CurrentOffset();
323       if (!WriteIndirectObj(m_dwLastObjNum, m_pEncryptDict.Get()))
324         return Stage::kInvalid;
325 
326       m_ObjectOffsets[m_dwLastObjNum] = saveOffset;
327       if (m_IsIncremental)
328         m_NewObjNumArray.push_back(m_dwLastObjNum);
329     }
330     m_iStage = Stage::kInitWriteXRefs80;
331   }
332   return m_iStage;
333 }
334 
WriteDoc_Stage3()335 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage3() {
336   ASSERT(m_iStage >= Stage::kInitWriteXRefs80 ||
337          m_iStage < Stage::kWriteTrailerAndFinish90);
338 
339   uint32_t dwLastObjNum = m_dwLastObjNum;
340   if (m_iStage == Stage::kInitWriteXRefs80) {
341     m_XrefStart = m_Archive->CurrentOffset();
342     if (!m_IsIncremental || !m_pParser->IsXRefStream()) {
343       if (!m_IsIncremental || m_pParser->GetLastXRefOffset() == 0) {
344         ByteString str;
345         str = pdfium::ContainsKey(m_ObjectOffsets, 1)
346                   ? "xref\r\n"
347                   : "xref\r\n0 1\r\n0000000000 65535 f\r\n";
348         if (!m_Archive->WriteString(str.AsStringView()))
349           return Stage::kInvalid;
350 
351         m_CurObjNum = 1;
352         m_iStage = Stage::kWriteXrefsNotIncremental81;
353       } else {
354         if (!m_Archive->WriteString("xref\r\n"))
355           return Stage::kInvalid;
356 
357         m_CurObjNum = 0;
358         m_iStage = Stage::kWriteXrefsIncremental82;
359       }
360     } else {
361       m_iStage = Stage::kWriteTrailerAndFinish90;
362     }
363   }
364   if (m_iStage == Stage::kWriteXrefsNotIncremental81) {
365     ByteString str;
366     uint32_t i = m_CurObjNum;
367     uint32_t j;
368     while (i <= dwLastObjNum) {
369       while (i <= dwLastObjNum && !pdfium::ContainsKey(m_ObjectOffsets, i))
370         i++;
371 
372       if (i > dwLastObjNum)
373         break;
374 
375       j = i;
376       while (j <= dwLastObjNum && pdfium::ContainsKey(m_ObjectOffsets, j))
377         j++;
378 
379       if (i == 1)
380         str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j);
381       else
382         str = ByteString::Format("%d %d\r\n", i, j - i);
383 
384       if (!m_Archive->WriteString(str.AsStringView()))
385         return Stage::kInvalid;
386 
387       while (i < j) {
388         str = ByteString::Format("%010d 00000 n\r\n", m_ObjectOffsets[i++]);
389         if (!m_Archive->WriteString(str.AsStringView()))
390           return Stage::kInvalid;
391       }
392       if (i > dwLastObjNum)
393         break;
394     }
395     m_iStage = Stage::kWriteTrailerAndFinish90;
396   }
397   if (m_iStage == Stage::kWriteXrefsIncremental82) {
398     ByteString str;
399     uint32_t iCount = pdfium::CollectionSize<uint32_t>(m_NewObjNumArray);
400     uint32_t i = m_CurObjNum;
401     while (i < iCount) {
402       size_t j = i;
403       uint32_t objnum = m_NewObjNumArray[i];
404       while (j < iCount) {
405         if (++j == iCount)
406           break;
407         uint32_t dwCurrent = m_NewObjNumArray[j];
408         if (dwCurrent - objnum > 1)
409           break;
410         objnum = dwCurrent;
411       }
412       objnum = m_NewObjNumArray[i];
413       if (objnum == 1)
414         str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j - i + 1);
415       else
416         str = ByteString::Format("%d %d\r\n", objnum, j - i);
417 
418       if (!m_Archive->WriteString(str.AsStringView()))
419         return Stage::kInvalid;
420 
421       while (i < j) {
422         objnum = m_NewObjNumArray[i++];
423         str = ByteString::Format("%010d 00000 n\r\n", m_ObjectOffsets[objnum]);
424         if (!m_Archive->WriteString(str.AsStringView()))
425           return Stage::kInvalid;
426       }
427     }
428     m_iStage = Stage::kWriteTrailerAndFinish90;
429   }
430   return m_iStage;
431 }
432 
WriteDoc_Stage4()433 CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage4() {
434   ASSERT(m_iStage >= Stage::kWriteTrailerAndFinish90);
435 
436   bool bXRefStream = m_IsIncremental && m_pParser->IsXRefStream();
437   if (!bXRefStream) {
438     if (!m_Archive->WriteString("trailer\r\n<<"))
439       return Stage::kInvalid;
440   } else {
441     if (!m_Archive->WriteDWord(m_pDocument->GetLastObjNum() + 1) ||
442         !m_Archive->WriteString(" 0 obj <<")) {
443       return Stage::kInvalid;
444     }
445   }
446 
447   if (m_pParser) {
448     RetainPtr<CPDF_Dictionary> p = m_pParser->GetCombinedTrailer();
449     CPDF_DictionaryLocker locker(p.Get());
450     for (const auto& it : locker) {
451       const ByteString& key = it.first;
452       CPDF_Object* pValue = it.second.Get();
453       if (key == "Encrypt" || key == "Size" || key == "Filter" ||
454           key == "Index" || key == "Length" || key == "Prev" || key == "W" ||
455           key == "XRefStm" || key == "ID" || key == "DecodeParms" ||
456           key == "Type") {
457         continue;
458       }
459       if (!m_Archive->WriteString(("/")) ||
460           !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) {
461         return Stage::kInvalid;
462       }
463       if (!pValue->WriteTo(m_Archive.get(), nullptr))
464         return Stage::kInvalid;
465     }
466   } else {
467     if (!m_Archive->WriteString("\r\n/Root ") ||
468         !m_Archive->WriteDWord(m_pDocument->GetRoot()->GetObjNum()) ||
469         !m_Archive->WriteString(" 0 R\r\n")) {
470       return Stage::kInvalid;
471     }
472     if (m_pDocument->GetInfo()) {
473       if (!m_Archive->WriteString("/Info ") ||
474           !m_Archive->WriteDWord(m_pDocument->GetInfo()->GetObjNum()) ||
475           !m_Archive->WriteString(" 0 R\r\n")) {
476         return Stage::kInvalid;
477       }
478     }
479   }
480   if (m_pEncryptDict) {
481     if (!m_Archive->WriteString("/Encrypt"))
482       return Stage::kInvalid;
483 
484     uint32_t dwObjNum = m_pEncryptDict->GetObjNum();
485     if (dwObjNum == 0)
486       dwObjNum = m_pDocument->GetLastObjNum() + 1;
487     if (!m_Archive->WriteString(" ") || !m_Archive->WriteDWord(dwObjNum) ||
488         !m_Archive->WriteString(" 0 R ")) {
489       return Stage::kInvalid;
490     }
491   }
492 
493   if (!m_Archive->WriteString("/Size ") ||
494       !m_Archive->WriteDWord(m_dwLastObjNum + (bXRefStream ? 2 : 1))) {
495     return Stage::kInvalid;
496   }
497   if (m_IsIncremental) {
498     FX_FILESIZE prev = m_pParser->GetLastXRefOffset();
499     if (prev) {
500       if (!m_Archive->WriteString("/Prev "))
501         return Stage::kInvalid;
502 
503       char offset_buf[20];
504       memset(offset_buf, 0, sizeof(offset_buf));
505       FXSYS_i64toa(prev, offset_buf, 10);
506       if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf)))
507         return Stage::kInvalid;
508     }
509   }
510   if (m_pIDArray) {
511     if (!m_Archive->WriteString(("/ID")) ||
512         !m_pIDArray->WriteTo(m_Archive.get(), nullptr)) {
513       return Stage::kInvalid;
514     }
515   }
516   if (!bXRefStream) {
517     if (!m_Archive->WriteString(">>"))
518       return Stage::kInvalid;
519   } else {
520     if (!m_Archive->WriteString("/W[0 4 1]/Index["))
521       return Stage::kInvalid;
522     if (m_IsIncremental && m_pParser && m_pParser->GetLastXRefOffset() == 0) {
523       uint32_t i = 0;
524       for (i = 0; i < m_dwLastObjNum; i++) {
525         if (!pdfium::ContainsKey(m_ObjectOffsets, i))
526           continue;
527         if (!m_Archive->WriteDWord(i) || !m_Archive->WriteString(" 1 "))
528           return Stage::kInvalid;
529       }
530       if (!m_Archive->WriteString("]/Length ") ||
531           !m_Archive->WriteDWord(m_dwLastObjNum * 5) ||
532           !m_Archive->WriteString(">>stream\r\n")) {
533         return Stage::kInvalid;
534       }
535       for (i = 0; i < m_dwLastObjNum; i++) {
536         auto it = m_ObjectOffsets.find(i);
537         if (it == m_ObjectOffsets.end())
538           continue;
539         if (!OutputIndex(m_Archive.get(), it->second))
540           return Stage::kInvalid;
541       }
542     } else {
543       size_t count = m_NewObjNumArray.size();
544       size_t i = 0;
545       for (i = 0; i < count; i++) {
546         if (!m_Archive->WriteDWord(m_NewObjNumArray[i]) ||
547             !m_Archive->WriteString(" 1 ")) {
548           return Stage::kInvalid;
549         }
550       }
551       if (!m_Archive->WriteString("]/Length ") ||
552           !m_Archive->WriteDWord(count * 5) ||
553           !m_Archive->WriteString(">>stream\r\n")) {
554         return Stage::kInvalid;
555       }
556       for (i = 0; i < count; ++i) {
557         if (!OutputIndex(m_Archive.get(), m_ObjectOffsets[m_NewObjNumArray[i]]))
558           return Stage::kInvalid;
559       }
560     }
561     if (!m_Archive->WriteString("\r\nendstream"))
562       return Stage::kInvalid;
563   }
564 
565   if (!m_Archive->WriteString("\r\nstartxref\r\n"))
566     return Stage::kInvalid;
567 
568   char offset_buf[20];
569   memset(offset_buf, 0, sizeof(offset_buf));
570   FXSYS_i64toa(m_XrefStart, offset_buf, 10);
571   if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf)) ||
572       !m_Archive->WriteString("\r\n%%EOF\r\n")) {
573     return Stage::kInvalid;
574   }
575 
576   m_iStage = Stage::kComplete100;
577   return m_iStage;
578 }
579 
Create(uint32_t flags)580 bool CPDF_Creator::Create(uint32_t flags) {
581   m_IsIncremental = !!(flags & FPDFCREATE_INCREMENTAL);
582   m_IsOriginal = !(flags & FPDFCREATE_NO_ORIGINAL);
583 
584   m_iStage = Stage::kInit0;
585   m_dwLastObjNum = m_pDocument->GetLastObjNum();
586   m_ObjectOffsets.clear();
587   m_NewObjNumArray.clear();
588 
589   InitID();
590   return Continue();
591 }
592 
InitID()593 void CPDF_Creator::InitID() {
594   ASSERT(!m_pIDArray);
595 
596   m_pIDArray = pdfium::MakeRetain<CPDF_Array>();
597   const CPDF_Array* pOldIDArray = m_pParser ? m_pParser->GetIDArray() : nullptr;
598   const CPDF_Object* pID1 = pOldIDArray ? pOldIDArray->GetObjectAt(0) : nullptr;
599   if (pID1) {
600     m_pIDArray->Add(pID1->Clone());
601   } else {
602     ByteString bsBuffer =
603         GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum);
604     m_pIDArray->AddNew<CPDF_String>(bsBuffer, true);
605   }
606 
607   if (pOldIDArray) {
608     const CPDF_Object* pID2 = pOldIDArray->GetObjectAt(1);
609     if (m_IsIncremental && m_pEncryptDict && pID2) {
610       m_pIDArray->Add(pID2->Clone());
611       return;
612     }
613     ByteString bsBuffer =
614         GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum);
615     m_pIDArray->AddNew<CPDF_String>(bsBuffer, true);
616     return;
617   }
618 
619   m_pIDArray->Add(m_pIDArray->GetObjectAt(0)->Clone());
620   if (m_pEncryptDict) {
621     ASSERT(m_pParser);
622     int revision = m_pEncryptDict->GetIntegerFor("R");
623     if ((revision == 2 || revision == 3) &&
624         m_pEncryptDict->GetStringFor("Filter") == "Standard") {
625       m_pNewEncryptDict = ToDictionary(m_pEncryptDict->Clone());
626       m_pEncryptDict = m_pNewEncryptDict;
627       m_pSecurityHandler = pdfium::MakeRetain<CPDF_SecurityHandler>();
628       m_pSecurityHandler->OnCreate(m_pNewEncryptDict.Get(), m_pIDArray.Get(),
629                                    m_pParser->GetEncodedPassword());
630       m_bSecurityChanged = true;
631     }
632   }
633 }
634 
Continue()635 bool CPDF_Creator::Continue() {
636   if (m_iStage < Stage::kInit0)
637     return false;
638 
639   Stage iRet = Stage::kInit0;
640   while (m_iStage < Stage::kComplete100) {
641     if (m_iStage < Stage::kInitWriteObjs20)
642       iRet = WriteDoc_Stage1();
643     else if (m_iStage < Stage::kInitWriteXRefs80)
644       iRet = WriteDoc_Stage2();
645     else if (m_iStage < Stage::kWriteTrailerAndFinish90)
646       iRet = WriteDoc_Stage3();
647     else
648       iRet = WriteDoc_Stage4();
649 
650     if (iRet < m_iStage)
651       break;
652   }
653 
654   if (iRet <= Stage::kInit0 || m_iStage == Stage::kComplete100) {
655     m_iStage = Stage::kInvalid;
656     return iRet > Stage::kInit0;
657   }
658 
659   return m_iStage > Stage::kInvalid;
660 }
661 
SetFileVersion(int32_t fileVersion)662 bool CPDF_Creator::SetFileVersion(int32_t fileVersion) {
663   if (fileVersion < 10 || fileVersion > 17)
664     return false;
665   m_FileVersion = fileVersion;
666   return true;
667 }
668 
RemoveSecurity()669 void CPDF_Creator::RemoveSecurity() {
670   m_pSecurityHandler.Reset();
671   m_bSecurityChanged = true;
672   m_pEncryptDict = nullptr;
673   m_pNewEncryptDict.Reset();
674 }
675 
GetCryptoHandler()676 CPDF_CryptoHandler* CPDF_Creator::GetCryptoHandler() {
677   return m_pSecurityHandler ? m_pSecurityHandler->GetCryptoHandler() : nullptr;
678 }
679