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