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/edit/cpdf_encryptor.h"
12 #include "core/fpdfapi/edit/cpdf_flateencoder.h"
13 #include "core/fpdfapi/parser/cpdf_array.h"
14 #include "core/fpdfapi/parser/cpdf_crypto_handler.h"
15 #include "core/fpdfapi/parser/cpdf_document.h"
16 #include "core/fpdfapi/parser/cpdf_number.h"
17 #include "core/fpdfapi/parser/cpdf_parser.h"
18 #include "core/fpdfapi/parser/cpdf_security_handler.h"
19 #include "core/fpdfapi/parser/cpdf_string.h"
20 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
21 #include "core/fxcrt/fx_extension.h"
22 #include "core/fxcrt/fx_random.h"
23 
24 namespace {
25 
26 const size_t kArchiveBufferSize = 32768;
27 
28 class CFX_FileBufferArchive : public IFX_ArchiveStream {
29  public:
30   explicit CFX_FileBufferArchive(const RetainPtr<IFX_WriteStream>& archive);
31   ~CFX_FileBufferArchive() override;
32 
33   bool WriteBlock(const void* pBuf, size_t size) override;
34   bool WriteByte(uint8_t byte) override;
35   bool WriteDWord(uint32_t i) override;
36   bool WriteString(const ByteStringView& str) override;
37 
CurrentOffset() const38   FX_FILESIZE CurrentOffset() const override { return offset_; }
39 
40  private:
41   bool Flush();
42 
43   FX_FILESIZE offset_;
44   size_t current_length_;
45   std::vector<uint8_t> buffer_;
46   RetainPtr<IFX_WriteStream> backing_file_;
47 };
48 
CFX_FileBufferArchive(const RetainPtr<IFX_WriteStream> & file)49 CFX_FileBufferArchive::CFX_FileBufferArchive(
50     const RetainPtr<IFX_WriteStream>& file)
51     : offset_(0),
52       current_length_(0),
53       buffer_(kArchiveBufferSize),
54       backing_file_(file) {
55   ASSERT(file);
56 }
57 
~CFX_FileBufferArchive()58 CFX_FileBufferArchive::~CFX_FileBufferArchive() {
59   Flush();
60 }
61 
Flush()62 bool CFX_FileBufferArchive::Flush() {
63   size_t nRemaining = current_length_;
64   current_length_ = 0;
65   if (!backing_file_)
66     return false;
67   if (!nRemaining)
68     return true;
69   return backing_file_->WriteBlock(buffer_.data(), nRemaining);
70 }
71 
WriteBlock(const void * pBuf,size_t size)72 bool CFX_FileBufferArchive::WriteBlock(const void* pBuf, size_t size) {
73   ASSERT(pBuf && size > 0);
74 
75   const uint8_t* buffer = reinterpret_cast<const uint8_t*>(pBuf);
76   size_t temp_size = size;
77   while (temp_size) {
78     size_t buf_size = std::min(kArchiveBufferSize - current_length_, temp_size);
79     memcpy(buffer_.data() + current_length_, buffer, buf_size);
80 
81     current_length_ += buf_size;
82     if (current_length_ == kArchiveBufferSize && !Flush())
83       return false;
84 
85     temp_size -= buf_size;
86     buffer += buf_size;
87   }
88 
89   pdfium::base::CheckedNumeric<FX_FILESIZE> safe_offset = offset_;
90   safe_offset += size;
91   if (!safe_offset.IsValid())
92     return false;
93 
94   offset_ = safe_offset.ValueOrDie();
95   return true;
96 }
97 
WriteByte(uint8_t byte)98 bool CFX_FileBufferArchive::WriteByte(uint8_t byte) {
99   return WriteBlock(&byte, 1);
100 }
101 
WriteDWord(uint32_t i)102 bool CFX_FileBufferArchive::WriteDWord(uint32_t i) {
103   char buf[32];
104   FXSYS_itoa(i, buf, 10);
105   return WriteBlock(buf, strlen(buf));
106 }
107 
WriteString(const ByteStringView & str)108 bool CFX_FileBufferArchive::WriteString(const ByteStringView& str) {
109   return WriteBlock(str.raw_str(), str.GetLength());
110 }
111 
GenerateFileID(uint32_t dwSeed1,uint32_t dwSeed2)112 std::vector<uint8_t> GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) {
113   std::vector<uint8_t> buffer(sizeof(uint32_t) * 4);
114   uint32_t* pBuffer = reinterpret_cast<uint32_t*>(buffer.data());
115   void* pContext = FX_Random_MT_Start(dwSeed1);
116   for (int i = 0; i < 2; ++i)
117     *pBuffer++ = FX_Random_MT_Generate(pContext);
118 
119   FX_Random_MT_Close(pContext);
120   pContext = FX_Random_MT_Start(dwSeed2);
121   for (int i = 0; i < 2; ++i)
122     *pBuffer++ = FX_Random_MT_Generate(pContext);
123 
124   FX_Random_MT_Close(pContext);
125   return buffer;
126 }
127 
OutputIndex(IFX_ArchiveStream * archive,FX_FILESIZE offset)128 int32_t OutputIndex(IFX_ArchiveStream* archive, FX_FILESIZE offset) {
129   if (!archive->WriteByte(static_cast<uint8_t>(offset >> 24)) ||
130       !archive->WriteByte(static_cast<uint8_t>(offset >> 16)) ||
131       !archive->WriteByte(static_cast<uint8_t>(offset >> 8)) ||
132       !archive->WriteByte(static_cast<uint8_t>(offset)) ||
133       !archive->WriteByte(0)) {
134     return -1;
135   }
136   return 0;
137 }
138 
139 }  // namespace
140 
CPDF_Creator(CPDF_Document * pDoc,const RetainPtr<IFX_WriteStream> & archive)141 CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc,
142                            const RetainPtr<IFX_WriteStream>& archive)
143     : m_pDocument(pDoc),
144       m_pParser(pDoc->GetParser()),
145       m_bSecurityChanged(false),
146       m_pEncryptDict(m_pParser ? m_pParser->GetEncryptDict() : nullptr),
147       m_dwEncryptObjNum(0),
148       m_pSecurityHandler(m_pParser ? m_pParser->GetSecurityHandler() : nullptr),
149       m_pMetadata(nullptr),
150       m_dwLastObjNum(m_pDocument->GetLastObjNum()),
151       m_Archive(pdfium::MakeUnique<CFX_FileBufferArchive>(archive)),
152       m_SavedOffset(0),
153       m_iStage(-1),
154       m_dwFlags(0),
155       m_CurObjNum(0),
156       m_XrefStart(0),
157       m_pIDArray(nullptr),
158       m_FileVersion(0) {}
159 
~CPDF_Creator()160 CPDF_Creator::~CPDF_Creator() {}
161 
WriteStream(const CPDF_Object * pStream,uint32_t objnum,CPDF_CryptoHandler * pCrypto)162 bool CPDF_Creator::WriteStream(const CPDF_Object* pStream,
163                                uint32_t objnum,
164                                CPDF_CryptoHandler* pCrypto) {
165   CPDF_FlateEncoder encoder(const_cast<CPDF_Stream*>(pStream->AsStream()),
166                             pStream != m_pMetadata);
167   CPDF_Encryptor encryptor(pCrypto, objnum, encoder.GetData(),
168                            encoder.GetSize());
169   if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) !=
170       encryptor.GetSize()) {
171     encoder.CloneDict();
172     encoder.GetDict()->SetNewFor<CPDF_Number>(
173         "Length", static_cast<int>(encryptor.GetSize()));
174   }
175 
176   if (!WriteDirectObj(objnum, encoder.GetDict(), true) ||
177       !m_Archive->WriteString("stream\r\n")) {
178     return false;
179   }
180 
181   // Allow for empty streams.
182   if (encryptor.GetSize() > 0 &&
183       !m_Archive->WriteBlock(encryptor.GetData(), encryptor.GetSize())) {
184     return false;
185   }
186 
187   return m_Archive->WriteString("\r\nendstream");
188 }
189 
WriteIndirectObj(uint32_t objnum,const CPDF_Object * pObj)190 bool CPDF_Creator::WriteIndirectObj(uint32_t objnum, const CPDF_Object* pObj) {
191   if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(" 0 obj\r\n"))
192     return false;
193 
194   if (pObj->IsStream()) {
195     CPDF_CryptoHandler* pHandler =
196         pObj != m_pMetadata ? GetCryptoHandler() : nullptr;
197     if (!WriteStream(pObj, objnum, pHandler))
198       return false;
199   } else if (!WriteDirectObj(objnum, pObj, true)) {
200     return false;
201   }
202 
203   return m_Archive->WriteString("\r\nendobj\r\n");
204 }
205 
WriteDirectObj(uint32_t objnum,const CPDF_Object * pObj,bool bEncrypt)206 bool CPDF_Creator::WriteDirectObj(uint32_t objnum,
207                                   const CPDF_Object* pObj,
208                                   bool bEncrypt) {
209   switch (pObj->GetType()) {
210     case CPDF_Object::BOOLEAN:
211     case CPDF_Object::NAME:
212     case CPDF_Object::NULLOBJ:
213     case CPDF_Object::NUMBER:
214     case CPDF_Object::REFERENCE:
215       if (!pObj->WriteTo(m_Archive.get()))
216         return false;
217       break;
218 
219     case CPDF_Object::STRING: {
220       ByteString str = pObj->GetString();
221       bool bHex = pObj->AsString()->IsHex();
222       if (!GetCryptoHandler() || !bEncrypt) {
223         if (!pObj->WriteTo(m_Archive.get()))
224           return false;
225         break;
226       }
227       CPDF_Encryptor encryptor(GetCryptoHandler(), objnum,
228                                (uint8_t*)str.c_str(), str.GetLength());
229       ByteString content = PDF_EncodeString(
230           ByteString(encryptor.GetData(), encryptor.GetSize()), bHex);
231       if (!m_Archive->WriteString(content.AsStringView()))
232         return false;
233       break;
234     }
235     case CPDF_Object::STREAM: {
236       CPDF_FlateEncoder encoder(const_cast<CPDF_Stream*>(pObj->AsStream()),
237                                 true);
238       CPDF_Encryptor encryptor(GetCryptoHandler(), objnum, encoder.GetData(),
239                                encoder.GetSize());
240       if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) !=
241           encryptor.GetSize()) {
242         encoder.CloneDict();
243         encoder.GetDict()->SetNewFor<CPDF_Number>(
244             "Length", static_cast<int>(encryptor.GetSize()));
245       }
246       if (!WriteDirectObj(objnum, encoder.GetDict(), true) ||
247           !m_Archive->WriteString("stream\r\n") ||
248           !m_Archive->WriteBlock(encryptor.GetData(), encryptor.GetSize()) ||
249           !m_Archive->WriteString("\r\nendstream")) {
250         return false;
251       }
252 
253       break;
254     }
255     case CPDF_Object::ARRAY: {
256       if (!m_Archive->WriteString("["))
257         return false;
258 
259       const CPDF_Array* p = pObj->AsArray();
260       for (size_t i = 0; i < p->GetCount(); i++) {
261         CPDF_Object* pElement = p->GetObjectAt(i);
262         if (!pElement->IsInline()) {
263           if (!m_Archive->WriteString(" ") ||
264               !m_Archive->WriteDWord(pElement->GetObjNum()) ||
265               !m_Archive->WriteString(" 0 R")) {
266             return false;
267           }
268         } else if (!WriteDirectObj(objnum, pElement, true)) {
269           return false;
270         }
271       }
272       if (!m_Archive->WriteString("]"))
273         return false;
274       break;
275     }
276     case CPDF_Object::DICTIONARY: {
277       if (!GetCryptoHandler() || pObj == m_pEncryptDict) {
278         if (!pObj->WriteTo(m_Archive.get()))
279           return false;
280         break;
281       }
282 
283       if (!m_Archive->WriteString("<<"))
284         return false;
285 
286       const CPDF_Dictionary* p = pObj->AsDictionary();
287       bool bSignDict = p->IsSignatureDict();
288       for (const auto& it : *p) {
289         bool bSignValue = false;
290         const ByteString& key = it.first;
291         CPDF_Object* pValue = it.second.get();
292         if (!m_Archive->WriteString("/") ||
293             !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) {
294           return false;
295         }
296 
297         if (bSignDict && key == "Contents")
298           bSignValue = true;
299         if (!pValue->IsInline()) {
300           if (!m_Archive->WriteString(" ") ||
301               !m_Archive->WriteDWord(pValue->GetObjNum()) ||
302               !m_Archive->WriteString(" 0 R ")) {
303             return false;
304           }
305         } else if (!WriteDirectObj(objnum, pValue, !bSignValue)) {
306           return false;
307         }
308       }
309       if (!m_Archive->WriteString(">>"))
310         return false;
311       break;
312     }
313   }
314   return true;
315 }
316 
WriteOldIndirectObject(uint32_t objnum)317 bool CPDF_Creator::WriteOldIndirectObject(uint32_t objnum) {
318   if (m_pParser->IsObjectFreeOrNull(objnum))
319     return true;
320 
321   m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
322 
323   bool bExistInMap = !!m_pDocument->GetIndirectObject(objnum);
324   CPDF_Object* pObj = m_pDocument->GetOrParseIndirectObject(objnum);
325   if (!pObj) {
326     m_ObjectOffsets.erase(objnum);
327     return true;
328   }
329   if (!WriteIndirectObj(pObj->GetObjNum(), pObj))
330     return false;
331   if (!bExistInMap)
332     m_pDocument->DeleteIndirectObject(objnum);
333   return true;
334 }
335 
WriteOldObjs()336 bool CPDF_Creator::WriteOldObjs() {
337   uint32_t nLastObjNum = m_pParser->GetLastObjNum();
338   if (!m_pParser->IsValidObjectNumber(nLastObjNum))
339     return true;
340 
341   for (uint32_t objnum = m_CurObjNum; objnum <= nLastObjNum; ++objnum) {
342     if (!WriteOldIndirectObject(objnum))
343       return false;
344   }
345   return true;
346 }
347 
WriteNewObjs()348 bool CPDF_Creator::WriteNewObjs() {
349   for (size_t i = m_CurObjNum; i < m_NewObjNumArray.size(); ++i) {
350     uint32_t objnum = m_NewObjNumArray[i];
351     CPDF_Object* pObj = m_pDocument->GetIndirectObject(objnum);
352     if (!pObj)
353       continue;
354 
355     m_ObjectOffsets[objnum] = m_Archive->CurrentOffset();
356     if (!WriteIndirectObj(pObj->GetObjNum(), pObj))
357       return false;
358   }
359   return true;
360 }
361 
InitOldObjNumOffsets()362 void CPDF_Creator::InitOldObjNumOffsets() {
363   if (!m_pParser)
364     return;
365 
366   uint32_t dwStart = 0;
367   uint32_t dwEnd = m_pParser->GetLastObjNum();
368   while (dwStart <= dwEnd) {
369     while (dwStart <= dwEnd && m_pParser->IsObjectFreeOrNull(dwStart))
370       dwStart++;
371 
372     if (dwStart > dwEnd)
373       break;
374 
375     uint32_t j = dwStart;
376     while (j <= dwEnd && !m_pParser->IsObjectFreeOrNull(j))
377       j++;
378 
379     dwStart = j;
380   }
381 }
382 
InitNewObjNumOffsets()383 void CPDF_Creator::InitNewObjNumOffsets() {
384   for (const auto& pair : *m_pDocument) {
385     const uint32_t objnum = pair.first;
386     if (IsIncremental() ||
387         pair.second->GetObjNum() == CPDF_Object::kInvalidObjNum) {
388       continue;
389     }
390     if (m_pParser && m_pParser->IsValidObjectNumber(objnum) &&
391         !m_pParser->IsObjectFree(objnum)) {
392       continue;
393     }
394     m_NewObjNumArray.insert(std::lower_bound(m_NewObjNumArray.begin(),
395                                              m_NewObjNumArray.end(), objnum),
396                             objnum);
397   }
398 }
399 
WriteDoc_Stage1()400 int32_t CPDF_Creator::WriteDoc_Stage1() {
401   ASSERT(m_iStage > -1 || m_iStage < 20);
402   if (m_iStage == 0) {
403     if (!m_pParser)
404       m_dwFlags &= ~FPDFCREATE_INCREMENTAL;
405     if (m_bSecurityChanged && IsOriginal())
406       m_dwFlags &= ~FPDFCREATE_INCREMENTAL;
407 
408     const CPDF_Dictionary* pDict = m_pDocument->GetRoot();
409     m_pMetadata = pDict ? pDict->GetDirectObjectFor("Metadata") : nullptr;
410     m_iStage = 10;
411   }
412   if (m_iStage == 10) {
413     if (!IsIncremental()) {
414       if (!m_Archive->WriteString("%PDF-1."))
415         return -1;
416 
417       int32_t version = 7;
418       if (m_FileVersion)
419         version = m_FileVersion;
420       else if (m_pParser)
421         version = m_pParser->GetFileVersion();
422 
423       if (!m_Archive->WriteDWord(version % 10) ||
424           !m_Archive->WriteString("\r\n%\xA1\xB3\xC5\xD7\r\n")) {
425         return -1;
426       }
427 
428       InitOldObjNumOffsets();
429       m_iStage = 20;
430     } else {
431       m_SavedOffset = m_pParser->GetFileAccess()->GetSize();
432       m_iStage = 15;
433     }
434   }
435   if (m_iStage == 15) {
436     if (IsOriginal() && m_SavedOffset > 0) {
437       RetainPtr<IFX_SeekableReadStream> pSrcFile = m_pParser->GetFileAccess();
438       std::vector<uint8_t> buffer(4096);
439       FX_FILESIZE src_size = m_SavedOffset;
440       while (src_size) {
441         uint32_t block_size = src_size > 4096 ? 4096 : src_size;
442         if (!pSrcFile->ReadBlock(buffer.data(),
443                                  m_Archive->CurrentOffset() - src_size,
444                                  block_size)) {
445           return -1;
446         }
447         if (!m_Archive->WriteBlock(buffer.data(), block_size))
448           return -1;
449 
450         src_size -= block_size;
451       }
452     }
453     if (IsOriginal() && m_pParser->GetLastXRefOffset() == 0) {
454       InitOldObjNumOffsets();
455 
456       for (uint32_t num = 0; num <= m_pParser->GetLastObjNum(); ++num) {
457         if (m_pParser->IsObjectFreeOrNull(num))
458           continue;
459 
460         m_ObjectOffsets[num] = m_pParser->GetObjectPositionOrZero(num);
461       }
462     }
463     m_iStage = 20;
464   }
465   InitNewObjNumOffsets();
466   return m_iStage;
467 }
468 
WriteDoc_Stage2()469 int32_t CPDF_Creator::WriteDoc_Stage2() {
470   ASSERT(m_iStage >= 20 || m_iStage < 30);
471   if (m_iStage == 20) {
472     if (!IsIncremental() && m_pParser) {
473       m_CurObjNum = 0;
474       m_iStage = 21;
475     } else {
476       m_iStage = 25;
477     }
478   }
479   if (m_iStage == 21) {
480     if (!WriteOldObjs())
481       return -1;
482 
483     m_iStage = 25;
484   }
485   if (m_iStage == 25) {
486     m_CurObjNum = 0;
487     m_iStage = 26;
488   }
489   if (m_iStage == 26) {
490     if (!WriteNewObjs())
491       return -1;
492 
493     m_iStage = 27;
494   }
495   if (m_iStage == 27) {
496     if (m_pEncryptDict && m_pEncryptDict->IsInline()) {
497       m_dwLastObjNum += 1;
498       FX_FILESIZE saveOffset = m_Archive->CurrentOffset();
499       if (!WriteIndirectObj(m_dwLastObjNum, m_pEncryptDict.Get()))
500         return -1;
501 
502       m_ObjectOffsets[m_dwLastObjNum] = saveOffset;
503       m_dwEncryptObjNum = m_dwLastObjNum;
504       if (IsIncremental())
505         m_NewObjNumArray.push_back(m_dwLastObjNum);
506     }
507     m_iStage = 80;
508   }
509   return m_iStage;
510 }
511 
WriteDoc_Stage3()512 int32_t CPDF_Creator::WriteDoc_Stage3() {
513   ASSERT(m_iStage >= 80 || m_iStage < 90);
514 
515   uint32_t dwLastObjNum = m_dwLastObjNum;
516   if (m_iStage == 80) {
517     m_XrefStart = m_Archive->CurrentOffset();
518     if (!IsIncremental() || !m_pParser->IsXRefStream()) {
519       if (!IsIncremental() || m_pParser->GetLastXRefOffset() == 0) {
520         ByteString str;
521         str = pdfium::ContainsKey(m_ObjectOffsets, 1)
522                   ? "xref\r\n"
523                   : "xref\r\n0 1\r\n0000000000 65535 f\r\n";
524         if (!m_Archive->WriteString(str.AsStringView()))
525           return -1;
526 
527         m_CurObjNum = 1;
528         m_iStage = 81;
529       } else {
530         if (!m_Archive->WriteString("xref\r\n"))
531           return -1;
532 
533         m_CurObjNum = 0;
534         m_iStage = 82;
535       }
536     } else {
537       m_iStage = 90;
538     }
539   }
540   if (m_iStage == 81) {
541     ByteString str;
542     uint32_t i = m_CurObjNum;
543     uint32_t j;
544     while (i <= dwLastObjNum) {
545       while (i <= dwLastObjNum && !pdfium::ContainsKey(m_ObjectOffsets, i))
546         i++;
547 
548       if (i > dwLastObjNum)
549         break;
550 
551       j = i;
552       while (j <= dwLastObjNum && pdfium::ContainsKey(m_ObjectOffsets, j))
553         j++;
554 
555       if (i == 1)
556         str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j);
557       else
558         str = ByteString::Format("%d %d\r\n", i, j - i);
559 
560       if (!m_Archive->WriteBlock(str.c_str(), str.GetLength()))
561         return -1;
562 
563       while (i < j) {
564         str = ByteString::Format("%010d 00000 n\r\n", m_ObjectOffsets[i++]);
565         if (!m_Archive->WriteBlock(str.c_str(), str.GetLength()))
566           return -1;
567       }
568       if (i > dwLastObjNum)
569         break;
570     }
571     m_iStage = 90;
572   }
573   if (m_iStage == 82) {
574     ByteString str;
575     uint32_t iCount = pdfium::CollectionSize<uint32_t>(m_NewObjNumArray);
576     uint32_t i = m_CurObjNum;
577     while (i < iCount) {
578       size_t j = i;
579       uint32_t objnum = m_NewObjNumArray[i];
580       while (j < iCount) {
581         if (++j == iCount)
582           break;
583         uint32_t dwCurrent = m_NewObjNumArray[j];
584         if (dwCurrent - objnum > 1)
585           break;
586         objnum = dwCurrent;
587       }
588       objnum = m_NewObjNumArray[i];
589       if (objnum == 1)
590         str = ByteString::Format("0 %d\r\n0000000000 65535 f\r\n", j - i + 1);
591       else
592         str = ByteString::Format("%d %d\r\n", objnum, j - i);
593 
594       if (!m_Archive->WriteBlock(str.c_str(), str.GetLength()))
595         return -1;
596 
597       while (i < j) {
598         objnum = m_NewObjNumArray[i++];
599         str = ByteString::Format("%010d 00000 n\r\n", m_ObjectOffsets[objnum]);
600         if (!m_Archive->WriteBlock(str.c_str(), str.GetLength()))
601           return -1;
602       }
603     }
604     m_iStage = 90;
605   }
606   return m_iStage;
607 }
608 
WriteDoc_Stage4()609 int32_t CPDF_Creator::WriteDoc_Stage4() {
610   ASSERT(m_iStage >= 90);
611 
612   bool bXRefStream = IsIncremental() && m_pParser->IsXRefStream();
613   if (!bXRefStream) {
614     if (!m_Archive->WriteString("trailer\r\n<<"))
615       return -1;
616   } else {
617     if (!m_Archive->WriteDWord(m_pDocument->GetLastObjNum() + 1) ||
618         !m_Archive->WriteString(" 0 obj <<")) {
619       return -1;
620     }
621   }
622 
623   if (m_pParser) {
624     std::unique_ptr<CPDF_Dictionary> p = m_pParser->GetCombinedTrailer();
625     for (const auto& it : *p) {
626       const ByteString& key = it.first;
627       CPDF_Object* pValue = it.second.get();
628       if (key == "Encrypt" || key == "Size" || key == "Filter" ||
629           key == "Index" || key == "Length" || key == "Prev" || key == "W" ||
630           key == "XRefStm" || key == "ID") {
631         continue;
632       }
633       if (!m_Archive->WriteString(("/")) ||
634           !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) {
635         return -1;
636       }
637       if (!pValue->IsInline()) {
638         if (!m_Archive->WriteString(" ") ||
639             !m_Archive->WriteDWord(pValue->GetObjNum()) ||
640             !m_Archive->WriteString(" 0 R ")) {
641           return -1;
642         }
643       } else if (!pValue->WriteTo(m_Archive.get())) {
644         return -1;
645       }
646     }
647   } else {
648     if (!m_Archive->WriteString("\r\n/Root ") ||
649         !m_Archive->WriteDWord(m_pDocument->GetRoot()->GetObjNum()) ||
650         !m_Archive->WriteString(" 0 R\r\n")) {
651       return -1;
652     }
653     if (m_pDocument->GetInfo()) {
654       if (!m_Archive->WriteString("/Info ") ||
655           !m_Archive->WriteDWord(m_pDocument->GetInfo()->GetObjNum()) ||
656           !m_Archive->WriteString(" 0 R\r\n")) {
657         return -1;
658       }
659     }
660   }
661   if (m_pEncryptDict) {
662     if (!m_Archive->WriteString("/Encrypt"))
663       return -1;
664 
665     uint32_t dwObjNum = m_pEncryptDict->GetObjNum();
666     if (dwObjNum == 0)
667       dwObjNum = m_pDocument->GetLastObjNum() + 1;
668     if (!m_Archive->WriteString(" ") || !m_Archive->WriteDWord(dwObjNum) ||
669         !m_Archive->WriteString(" 0 R ")) {
670       return -1;
671     }
672   }
673 
674   if (!m_Archive->WriteString("/Size ") ||
675       !m_Archive->WriteDWord(m_dwLastObjNum + (bXRefStream ? 2 : 1))) {
676     return -1;
677   }
678   if (IsIncremental()) {
679     FX_FILESIZE prev = m_pParser->GetLastXRefOffset();
680     if (prev) {
681       if (!m_Archive->WriteString("/Prev "))
682         return -1;
683 
684       char offset_buf[20];
685       memset(offset_buf, 0, sizeof(offset_buf));
686       FXSYS_i64toa(prev, offset_buf, 10);
687       if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf)))
688         return -1;
689     }
690   }
691   if (m_pIDArray) {
692     if (!m_Archive->WriteString(("/ID")) ||
693         !m_pIDArray->WriteTo(m_Archive.get())) {
694       return -1;
695     }
696   }
697   if (!bXRefStream) {
698     if (!m_Archive->WriteString(">>"))
699       return -1;
700   } else {
701     if (!m_Archive->WriteString("/W[0 4 1]/Index["))
702       return -1;
703     if (IsIncremental() && m_pParser && m_pParser->GetLastXRefOffset() == 0) {
704       uint32_t i = 0;
705       for (i = 0; i < m_dwLastObjNum; i++) {
706         if (!pdfium::ContainsKey(m_ObjectOffsets, i))
707           continue;
708         if (!m_Archive->WriteDWord(i) || !m_Archive->WriteString(" 1 "))
709           return -1;
710       }
711       if (!m_Archive->WriteString("]/Length ") ||
712           !m_Archive->WriteDWord(m_dwLastObjNum * 5) ||
713           !m_Archive->WriteString(">>stream\r\n")) {
714         return -1;
715       }
716       for (i = 0; i < m_dwLastObjNum; i++) {
717         auto it = m_ObjectOffsets.find(i);
718         if (it == m_ObjectOffsets.end())
719           continue;
720         OutputIndex(m_Archive.get(), it->second);
721       }
722     } else {
723       size_t count = m_NewObjNumArray.size();
724       size_t i = 0;
725       for (i = 0; i < count; i++) {
726         if (!m_Archive->WriteDWord(m_NewObjNumArray[i]) ||
727             !m_Archive->WriteString(" 1 ")) {
728           return -1;
729         }
730       }
731       if (!m_Archive->WriteString("]/Length ") ||
732           !m_Archive->WriteDWord(count * 5) ||
733           !m_Archive->WriteString(">>stream\r\n")) {
734         return -1;
735       }
736       for (i = 0; i < count; ++i)
737         OutputIndex(m_Archive.get(), m_ObjectOffsets[m_NewObjNumArray[i]]);
738     }
739     if (!m_Archive->WriteString("\r\nendstream"))
740       return -1;
741   }
742 
743   if (!m_Archive->WriteString("\r\nstartxref\r\n"))
744     return -1;
745 
746   char offset_buf[20];
747   memset(offset_buf, 0, sizeof(offset_buf));
748   FXSYS_i64toa(m_XrefStart, offset_buf, 10);
749   if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf)) ||
750       !m_Archive->WriteString("\r\n%%EOF\r\n")) {
751     return -1;
752   }
753 
754   m_iStage = 100;
755   return m_iStage;
756 }
757 
Create(uint32_t flags)758 bool CPDF_Creator::Create(uint32_t flags) {
759   m_dwFlags = flags;
760   m_iStage = 0;
761   m_dwLastObjNum = m_pDocument->GetLastObjNum();
762   m_ObjectOffsets.clear();
763   m_NewObjNumArray.clear();
764 
765   InitID();
766   return Continue() > -1;
767 }
768 
InitID()769 void CPDF_Creator::InitID() {
770   const CPDF_Array* pOldIDArray = m_pParser ? m_pParser->GetIDArray() : nullptr;
771 
772   bool idArrayPreExisting = !!m_pIDArray;
773   if (!idArrayPreExisting) {
774     m_pIDArray = pdfium::MakeUnique<CPDF_Array>();
775     CPDF_Object* pID1 = pOldIDArray ? pOldIDArray->GetObjectAt(0) : nullptr;
776     if (pID1) {
777       m_pIDArray->Add(pID1->Clone());
778     } else {
779       std::vector<uint8_t> buffer =
780           GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum);
781       ByteString bsBuffer(buffer.data(), buffer.size());
782       m_pIDArray->AddNew<CPDF_String>(bsBuffer, true);
783     }
784   }
785 
786   if (pOldIDArray) {
787     CPDF_Object* pID2 = pOldIDArray->GetObjectAt(1);
788     if (IsIncremental() && m_pEncryptDict && pID2) {
789       m_pIDArray->Add(pID2->Clone());
790       return;
791     }
792     std::vector<uint8_t> buffer =
793         GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum);
794     ByteString bsBuffer(buffer.data(), buffer.size());
795     m_pIDArray->AddNew<CPDF_String>(bsBuffer, true);
796     return;
797   }
798 
799   m_pIDArray->Add(m_pIDArray->GetObjectAt(0)->Clone());
800   if (m_pEncryptDict && !pOldIDArray && m_pParser && !idArrayPreExisting) {
801     if (m_pEncryptDict->GetStringFor("Filter") == "Standard") {
802       ByteString user_pass = m_pParser->GetPassword();
803       m_pSecurityHandler = pdfium::MakeUnique<CPDF_SecurityHandler>();
804       m_pSecurityHandler->OnCreate(m_pEncryptDict.Get(), m_pIDArray.get(),
805                                    user_pass);
806       m_bSecurityChanged = true;
807     }
808   }
809 }
810 
Continue()811 int32_t CPDF_Creator::Continue() {
812   if (m_iStage < 0)
813     return m_iStage;
814 
815   int32_t iRet = 0;
816   while (m_iStage < 100) {
817     if (m_iStage < 20)
818       iRet = WriteDoc_Stage1();
819     else if (m_iStage < 30)
820       iRet = WriteDoc_Stage2();
821     else if (m_iStage < 90)
822       iRet = WriteDoc_Stage3();
823     else
824       iRet = WriteDoc_Stage4();
825 
826     if (iRet < m_iStage)
827       break;
828   }
829 
830   if (iRet < 1 || m_iStage == 100) {
831     m_iStage = -1;
832     return iRet > 99 ? 0 : (iRet < 1 ? -1 : iRet);
833   }
834   return m_iStage;
835 }
836 
SetFileVersion(int32_t fileVersion)837 bool CPDF_Creator::SetFileVersion(int32_t fileVersion) {
838   if (fileVersion < 10 || fileVersion > 17)
839     return false;
840   m_FileVersion = fileVersion;
841   return true;
842 }
843 
RemoveSecurity()844 void CPDF_Creator::RemoveSecurity() {
845   m_pSecurityHandler.Reset();
846   m_bSecurityChanged = true;
847   m_pEncryptDict = nullptr;
848 }
849 
GetCryptoHandler()850 CPDF_CryptoHandler* CPDF_Creator::GetCryptoHandler() {
851   return m_pSecurityHandler ? m_pSecurityHandler->GetCryptoHandler() : nullptr;
852 }
853