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