Extern in .cpp files is a code smell.
[pdfium.git] / core / src / fpdfapi / fpdf_edit / fpdf_edit_create.cpp
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 "../../../include/fxcrt/fx_ext.h"
8 #include "../../../include/fpdfapi/fpdf_serial.h"
9 #include "../../../include/fpdfapi/fpdf_parser.h"
10 #include "editint.h"
11
12 #define PDF_OBJECTSTREAM_MAXLENGTH (256 * 1024)
13 #define PDF_XREFSTREAM_MAXSIZE 10000
14
15 int32_t PDF_CreatorAppendObject(const CPDF_Object* pObj,
16                                 CFX_FileBufferArchive* pFile,
17                                 FX_FILESIZE& offset) {
18   int32_t len = 0;
19   if (pObj == NULL) {
20     if (pFile->AppendString(FX_BSTRC(" null")) < 0) {
21       return -1;
22     }
23     offset += 5;
24     return 1;
25   }
26   switch (pObj->GetType()) {
27     case PDFOBJ_NULL:
28       if (pFile->AppendString(FX_BSTRC(" null")) < 0) {
29         return -1;
30       }
31       offset += 5;
32       break;
33     case PDFOBJ_BOOLEAN:
34     case PDFOBJ_NUMBER:
35       if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
36         return -1;
37       }
38       if ((len = pFile->AppendString(pObj->GetString())) < 0) {
39         return -1;
40       }
41       offset += len + 1;
42       break;
43     case PDFOBJ_STRING: {
44       CFX_ByteString str = pObj->GetString();
45       FX_BOOL bHex = ((CPDF_String*)pObj)->IsHex();
46       if ((len = pFile->AppendString(PDF_EncodeString(str, bHex))) < 0) {
47         return -1;
48       }
49       offset += len;
50       break;
51     }
52     case PDFOBJ_NAME: {
53       if (pFile->AppendString(FX_BSTRC("/")) < 0) {
54         return -1;
55       }
56       CFX_ByteString str = pObj->GetString();
57       if ((len = pFile->AppendString(PDF_NameEncode(str))) < 0) {
58         return -1;
59       }
60       offset += len + 1;
61       break;
62     }
63     case PDFOBJ_REFERENCE: {
64       if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
65         return -1;
66       }
67       CPDF_Reference* p = (CPDF_Reference*)pObj;
68       if ((len = pFile->AppendDWord(p->GetRefObjNum())) < 0) {
69         return -1;
70       }
71       if (pFile->AppendString(FX_BSTRC(" 0 R ")) < 0) {
72         return -1;
73       }
74       offset += len + 6;
75       break;
76     }
77     case PDFOBJ_ARRAY: {
78       if (pFile->AppendString(FX_BSTRC("[")) < 0) {
79         return -1;
80       }
81       offset += 1;
82       CPDF_Array* p = (CPDF_Array*)pObj;
83       for (FX_DWORD i = 0; i < p->GetCount(); i++) {
84         CPDF_Object* pElement = p->GetElement(i);
85         if (pElement->GetObjNum()) {
86           if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
87             return -1;
88           }
89           if ((len = pFile->AppendDWord(pElement->GetObjNum())) < 0) {
90             return -1;
91           }
92           if (pFile->AppendString(FX_BSTRC(" 0 R")) < 0) {
93             return -1;
94           }
95           offset += len + 5;
96         } else {
97           if (PDF_CreatorAppendObject(pElement, pFile, offset) < 0) {
98             return -1;
99           }
100         }
101       }
102       if (pFile->AppendString(FX_BSTRC("]")) < 0) {
103         return -1;
104       }
105       offset += 1;
106       break;
107     }
108     case PDFOBJ_DICTIONARY: {
109       if (pFile->AppendString(FX_BSTRC("<<")) < 0) {
110         return -1;
111       }
112       offset += 2;
113       CPDF_Dictionary* p = (CPDF_Dictionary*)pObj;
114       FX_POSITION pos = p->GetStartPos();
115       while (pos) {
116         CFX_ByteString key;
117         CPDF_Object* pValue = p->GetNextElement(pos, key);
118         if (pFile->AppendString(FX_BSTRC("/")) < 0) {
119           return -1;
120         }
121         if ((len = pFile->AppendString(PDF_NameEncode(key))) < 0) {
122           return -1;
123         }
124         offset += len + 1;
125         if (pValue->GetObjNum()) {
126           if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
127             return -1;
128           }
129           if ((len = pFile->AppendDWord(pValue->GetObjNum())) < 0) {
130             return -1;
131           }
132           if (pFile->AppendString(FX_BSTRC(" 0 R")) < 0) {
133             return -1;
134           }
135           offset += len + 5;
136         } else {
137           if (PDF_CreatorAppendObject(pValue, pFile, offset) < 0) {
138             return -1;
139           }
140         }
141       }
142       if (pFile->AppendString(FX_BSTRC(">>")) < 0) {
143         return -1;
144       }
145       offset += 2;
146       break;
147     }
148     case PDFOBJ_STREAM: {
149       CPDF_Stream* p = (CPDF_Stream*)pObj;
150       if (PDF_CreatorAppendObject(p->GetDict(), pFile, offset) < 0) {
151         return -1;
152       }
153       if (pFile->AppendString(FX_BSTRC("stream\r\n")) < 0) {
154         return -1;
155       }
156       offset += 8;
157       CPDF_StreamAcc acc;
158       acc.LoadAllData(p, TRUE);
159       if (pFile->AppendBlock(acc.GetData(), acc.GetSize()) < 0) {
160         return -1;
161       }
162       offset += acc.GetSize();
163       if ((len = pFile->AppendString(FX_BSTRC("\r\nendstream"))) < 0) {
164         return -1;
165       }
166       offset += len;
167       break;
168     }
169     default:
170       ASSERT(FALSE);
171       break;
172   }
173   return 1;
174 }
175 int32_t PDF_CreatorWriteTrailer(CPDF_Document* pDocument,
176                                 CFX_FileBufferArchive* pFile,
177                                 CPDF_Array* pIDArray,
178                                 FX_BOOL bCompress) {
179   FX_FILESIZE offset = 0;
180   int32_t len = 0;
181   FXSYS_assert(pDocument && pFile);
182   CPDF_Parser* pParser = (CPDF_Parser*)pDocument->GetParser();
183   if (pParser) {
184     CPDF_Dictionary* p = pParser->GetTrailer();
185     FX_POSITION pos = p->GetStartPos();
186     while (pos) {
187       CFX_ByteString key;
188       CPDF_Object* pValue = p->GetNextElement(pos, key);
189       if (key == FX_BSTRC("Encrypt") || key == FX_BSTRC("Size") ||
190           key == FX_BSTRC("Filter") || key == FX_BSTRC("Index") ||
191           key == FX_BSTRC("Length") || key == FX_BSTRC("Prev") ||
192           key == FX_BSTRC("W") || key == FX_BSTRC("XRefStm") ||
193           key == FX_BSTRC("Type") || key == FX_BSTRC("ID")) {
194         continue;
195       }
196       if (bCompress && key == FX_BSTRC("DecodeParms")) {
197         continue;
198       }
199       if (pFile->AppendString((FX_BSTRC("/"))) < 0) {
200         return -1;
201       }
202       if ((len = pFile->AppendString(PDF_NameEncode(key))) < 0) {
203         return -1;
204       }
205       offset += len + 1;
206       if (pValue->GetObjNum()) {
207         if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
208           return -1;
209         }
210         if ((len = pFile->AppendDWord(pValue->GetObjNum())) < 0) {
211           return -1;
212         }
213         if (pFile->AppendString(FX_BSTRC(" 0 R ")) < 0) {
214           return -1;
215         }
216         offset += len + 6;
217       } else {
218         if (PDF_CreatorAppendObject(pValue, pFile, offset) < 0) {
219           return -1;
220         }
221       }
222     }
223     if (pIDArray) {
224       if (pFile->AppendString((FX_BSTRC("/ID"))) < 0) {
225         return -1;
226       }
227       offset += 3;
228       if (PDF_CreatorAppendObject(pIDArray, pFile, offset) < 0) {
229         return -1;
230       }
231     }
232     return offset;
233   }
234   if (pFile->AppendString(FX_BSTRC("\r\n/Root ")) < 0) {
235     return -1;
236   }
237   if ((len = pFile->AppendDWord(pDocument->GetRoot()->GetObjNum())) < 0) {
238     return -1;
239   }
240   if (pFile->AppendString(FX_BSTRC(" 0 R\r\n")) < 0) {
241     return -1;
242   }
243   offset += len + 14;
244   if (pDocument->GetInfo()) {
245     if (pFile->AppendString(FX_BSTRC("/Info ")) < 0) {
246       return -1;
247     }
248     if ((len = pFile->AppendDWord(pDocument->GetInfo()->GetObjNum())) < 0) {
249       return -1;
250     }
251     if (pFile->AppendString(FX_BSTRC(" 0 R\r\n")) < 0) {
252       return -1;
253     }
254     offset += len + 12;
255   }
256   if (pIDArray) {
257     if (pFile->AppendString((FX_BSTRC("/ID"))) < 0) {
258       return -1;
259     }
260     offset += 3;
261     if (PDF_CreatorAppendObject(pIDArray, pFile, offset) < 0) {
262       return -1;
263     }
264   }
265   return offset;
266 }
267 int32_t PDF_CreatorWriteEncrypt(const CPDF_Dictionary* pEncryptDict,
268                                 FX_DWORD dwObjNum,
269                                 CFX_FileBufferArchive* pFile) {
270   if (!pEncryptDict) {
271     return 0;
272   }
273   FXSYS_assert(pFile);
274   FX_FILESIZE offset = 0;
275   int32_t len = 0;
276   if (pFile->AppendString(FX_BSTRC("/Encrypt")) < 0) {
277     return -1;
278   }
279   offset += 8;
280   if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
281     return -1;
282   }
283   if ((len = pFile->AppendDWord(dwObjNum)) < 0) {
284     return -1;
285   }
286   if (pFile->AppendString(FX_BSTRC(" 0 R ")) < 0) {
287     return -1;
288   }
289   offset += len + 6;
290   return offset;
291 }
292 FX_BOOL PDF_GenerateFileID(FX_DWORD dwSeed1,
293                            FX_DWORD dwSeed2,
294                            FX_DWORD* pBuffer) {
295   if (!pBuffer) {
296     return FALSE;
297   }
298   void* pContext = FX_Random_MT_Start(dwSeed1);
299   int32_t i = 0;
300   for (i = 0; i < 2; i++) {
301     *pBuffer++ = FX_Random_MT_Generate(pContext);
302   }
303   FX_Random_MT_Close(pContext);
304   pContext = FX_Random_MT_Start(dwSeed2);
305   for (i = 0; i < 2; i++) {
306     *pBuffer++ = FX_Random_MT_Generate(pContext);
307   }
308   FX_Random_MT_Close(pContext);
309   return TRUE;
310 }
311 class CPDF_FlateEncoder {
312  public:
313   CPDF_FlateEncoder();
314   ~CPDF_FlateEncoder();
315   FX_BOOL Initialize(CPDF_Stream* pStream, FX_BOOL bFlateEncode);
316   FX_BOOL Initialize(const uint8_t* pBuffer,
317                      FX_DWORD size,
318                      FX_BOOL bFlateEncode,
319                      FX_BOOL bXRefStream = FALSE);
320   void CloneDict();
321   uint8_t* m_pData;
322   FX_DWORD m_dwSize;
323   CPDF_Dictionary* m_pDict;
324   FX_BOOL m_bCloned;
325   FX_BOOL m_bNewData;
326   CPDF_StreamAcc m_Acc;
327 };
328 CPDF_FlateEncoder::CPDF_FlateEncoder() {
329   m_pData = NULL;
330   m_dwSize = 0;
331   m_pDict = NULL;
332   m_bCloned = FALSE;
333   m_bNewData = FALSE;
334 }
335 void CPDF_FlateEncoder::CloneDict() {
336   if (!m_bCloned) {
337     m_pDict = (CPDF_Dictionary*)m_pDict->Clone();
338     m_bCloned = TRUE;
339   }
340 }
341 FX_BOOL CPDF_FlateEncoder::Initialize(CPDF_Stream* pStream,
342                                       FX_BOOL bFlateEncode) {
343   m_Acc.LoadAllData(pStream, TRUE);
344   if ((pStream && pStream->GetDict() &&
345        pStream->GetDict()->KeyExist("Filter")) ||
346       !bFlateEncode) {
347     if (pStream->GetDict()->KeyExist("Filter") && !bFlateEncode) {
348       CPDF_StreamAcc destAcc;
349       destAcc.LoadAllData(pStream);
350       m_dwSize = destAcc.GetSize();
351       m_pData = (uint8_t*)destAcc.DetachData();
352       m_pDict = (CPDF_Dictionary*)pStream->GetDict()->Clone();
353       m_pDict->RemoveAt(FX_BSTRC("Filter"));
354       m_bNewData = TRUE;
355       m_bCloned = TRUE;
356     } else {
357       m_pData = (uint8_t*)m_Acc.GetData();
358       m_dwSize = m_Acc.GetSize();
359       m_pDict = pStream->GetDict();
360     }
361     return TRUE;
362   }
363   m_pData = NULL;
364   m_dwSize = 0;
365   m_bNewData = TRUE;
366   m_bCloned = TRUE;
367   ::FlateEncode(m_Acc.GetData(), m_Acc.GetSize(), m_pData, m_dwSize);
368   m_pDict = (CPDF_Dictionary*)pStream->GetDict()->Clone();
369   m_pDict->SetAtInteger("Length", m_dwSize);
370   m_pDict->SetAtName("Filter", "FlateDecode");
371   m_pDict->RemoveAt("DecodeParms");
372   return TRUE;
373 }
374 FX_BOOL CPDF_FlateEncoder::Initialize(const uint8_t* pBuffer,
375                                       FX_DWORD size,
376                                       FX_BOOL bFlateEncode,
377                                       FX_BOOL bXRefStream) {
378   if (!bFlateEncode) {
379     m_pData = (uint8_t*)pBuffer;
380     m_dwSize = size;
381     return TRUE;
382   }
383   m_bNewData = TRUE;
384   if (bXRefStream) {
385     ::FlateEncode(pBuffer, size, 12, 1, 8, 7, m_pData, m_dwSize);
386   } else {
387     ::FlateEncode(pBuffer, size, m_pData, m_dwSize);
388   }
389   return TRUE;
390 }
391 CPDF_FlateEncoder::~CPDF_FlateEncoder() {
392   if (m_bCloned && m_pDict) {
393     m_pDict->Release();
394   }
395   if (m_bNewData) {
396     FX_Free(m_pData);
397   }
398 }
399 class CPDF_Encryptor {
400  public:
401   CPDF_Encryptor();
402   ~CPDF_Encryptor();
403   FX_BOOL Initialize(CPDF_CryptoHandler* pHandler,
404                      int objnum,
405                      uint8_t* src_data,
406                      FX_DWORD src_size);
407   uint8_t* m_pData;
408   FX_DWORD m_dwSize;
409   FX_BOOL m_bNewBuf;
410 };
411 CPDF_Encryptor::CPDF_Encryptor() {
412   m_pData = NULL;
413   m_dwSize = 0;
414   m_bNewBuf = FALSE;
415 }
416 FX_BOOL CPDF_Encryptor::Initialize(CPDF_CryptoHandler* pHandler,
417                                    int objnum,
418                                    uint8_t* src_data,
419                                    FX_DWORD src_size) {
420   if (src_size == 0) {
421     return TRUE;
422   }
423   if (pHandler == NULL) {
424     m_pData = (uint8_t*)src_data;
425     m_dwSize = src_size;
426     m_bNewBuf = FALSE;
427     return TRUE;
428   }
429   m_dwSize = pHandler->EncryptGetSize(objnum, 0, src_data, src_size);
430   m_pData = FX_Alloc(uint8_t, m_dwSize);
431   pHandler->EncryptContent(objnum, 0, src_data, src_size, m_pData, m_dwSize);
432   m_bNewBuf = TRUE;
433   return TRUE;
434 }
435 CPDF_Encryptor::~CPDF_Encryptor() {
436   if (m_bNewBuf) {
437     FX_Free(m_pData);
438   }
439 }
440 CPDF_ObjectStream::CPDF_ObjectStream() : m_dwObjNum(0), m_index(0) {}
441 FX_BOOL CPDF_ObjectStream::Start() {
442   m_ObjNumArray.RemoveAll();
443   m_OffsetArray.RemoveAll();
444   m_Buffer.Clear();
445   m_dwObjNum = 0;
446   m_index = 0;
447   return TRUE;
448 }
449 int32_t CPDF_ObjectStream::CompressIndirectObject(FX_DWORD dwObjNum,
450                                                   const CPDF_Object* pObj) {
451   m_ObjNumArray.Add(dwObjNum);
452   m_OffsetArray.Add(m_Buffer.GetLength());
453   m_Buffer << pObj;
454   return 1;
455 }
456 int32_t CPDF_ObjectStream::CompressIndirectObject(FX_DWORD dwObjNum,
457                                                   const uint8_t* pBuffer,
458                                                   FX_DWORD dwSize) {
459   m_ObjNumArray.Add(dwObjNum);
460   m_OffsetArray.Add(m_Buffer.GetLength());
461   m_Buffer.AppendBlock(pBuffer, dwSize);
462   return 1;
463 }
464 FX_FILESIZE CPDF_ObjectStream::End(CPDF_Creator* pCreator) {
465   FXSYS_assert(pCreator);
466   if (m_ObjNumArray.GetSize() == 0) {
467     return 0;
468   }
469   CFX_FileBufferArchive* pFile = &pCreator->m_File;
470   CPDF_CryptoHandler* pHandler = pCreator->m_pCryptoHandler;
471   FX_FILESIZE ObjOffset = pCreator->m_Offset;
472   if (!m_dwObjNum) {
473     m_dwObjNum = ++pCreator->m_dwLastObjNum;
474   }
475   CFX_ByteTextBuf tempBuffer;
476   int32_t iCount = m_ObjNumArray.GetSize();
477   for (int32_t i = 0; i < iCount; i++) {
478     tempBuffer << m_ObjNumArray.ElementAt(i) << FX_BSTRC(" ")
479                << m_OffsetArray.ElementAt(i) << FX_BSTRC(" ");
480   }
481   FX_FILESIZE& offset = pCreator->m_Offset;
482   int32_t len = pFile->AppendDWord(m_dwObjNum);
483   if (len < 0) {
484     return -1;
485   }
486   offset += len;
487   if ((len = pFile->AppendString(FX_BSTRC(" 0 obj\r\n<</Type /ObjStm /N "))) <
488       0) {
489     return -1;
490   }
491   offset += len;
492   if ((len = pFile->AppendDWord((FX_DWORD)iCount)) < 0) {
493     return -1;
494   }
495   offset += len;
496   if (pFile->AppendString(FX_BSTRC("/First ")) < 0) {
497     return -1;
498   }
499   if ((len = pFile->AppendDWord((FX_DWORD)tempBuffer.GetLength())) < 0) {
500     return -1;
501   }
502   if (pFile->AppendString(FX_BSTRC("/Length ")) < 0) {
503     return -1;
504   }
505   offset += len + 15;
506   if (!pCreator->m_bCompress && !pHandler) {
507     if ((len = pFile->AppendDWord(
508              (FX_DWORD)(tempBuffer.GetLength() + m_Buffer.GetLength()))) < 0) {
509       return -1;
510     }
511     offset += len;
512     if ((len = pFile->AppendString(FX_BSTRC(">>stream\r\n"))) < 0) {
513       return -1;
514     }
515     if (pFile->AppendBlock(tempBuffer.GetBuffer(), tempBuffer.GetLength()) <
516         0) {
517       return -1;
518     }
519     if (pFile->AppendBlock(m_Buffer.GetBuffer(), m_Buffer.GetLength()) < 0) {
520       return -1;
521     }
522     offset += len + tempBuffer.GetLength() + m_Buffer.GetLength();
523   } else {
524     tempBuffer << m_Buffer;
525     CPDF_FlateEncoder encoder;
526     encoder.Initialize(tempBuffer.GetBuffer(), tempBuffer.GetLength(),
527                        pCreator->m_bCompress);
528     CPDF_Encryptor encryptor;
529     encryptor.Initialize(pHandler, m_dwObjNum, encoder.m_pData,
530                          encoder.m_dwSize);
531     if ((len = pFile->AppendDWord(encryptor.m_dwSize)) < 0) {
532       return -1;
533     }
534     offset += len;
535     if (pCreator->m_bCompress) {
536       if (pFile->AppendString(FX_BSTRC("/Filter /FlateDecode")) < 0) {
537         return -1;
538       }
539       offset += 20;
540     }
541     if ((len = pFile->AppendString(FX_BSTRC(">>stream\r\n"))) < 0) {
542       return -1;
543     }
544     if (pFile->AppendBlock(encryptor.m_pData, encryptor.m_dwSize) < 0) {
545       return -1;
546     }
547     offset += len + encryptor.m_dwSize;
548   }
549   if ((len = pFile->AppendString(FX_BSTRC("\r\nendstream\r\nendobj\r\n"))) <
550       0) {
551     return -1;
552   }
553   offset += len;
554   return ObjOffset;
555 }
556 CPDF_XRefStream::CPDF_XRefStream()
557     : m_PrevOffset(0), m_dwTempObjNum(0), m_iSeg(0) {}
558 FX_BOOL CPDF_XRefStream::Start() {
559   m_IndexArray.RemoveAll();
560   m_Buffer.Clear();
561   m_iSeg = 0;
562   return TRUE;
563 }
564 int32_t CPDF_XRefStream::CompressIndirectObject(FX_DWORD dwObjNum,
565                                                 const CPDF_Object* pObj,
566                                                 CPDF_Creator* pCreator) {
567   if (!pCreator) {
568     return 0;
569   }
570   m_ObjStream.CompressIndirectObject(dwObjNum, pObj);
571   if (m_ObjStream.m_ObjNumArray.GetSize() < pCreator->m_ObjectStreamSize &&
572       m_ObjStream.m_Buffer.GetLength() < PDF_OBJECTSTREAM_MAXLENGTH) {
573     return 1;
574   }
575   return EndObjectStream(pCreator);
576 }
577 int32_t CPDF_XRefStream::CompressIndirectObject(FX_DWORD dwObjNum,
578                                                 const uint8_t* pBuffer,
579                                                 FX_DWORD dwSize,
580                                                 CPDF_Creator* pCreator) {
581   if (!pCreator) {
582     return 0;
583   }
584   m_ObjStream.CompressIndirectObject(dwObjNum, pBuffer, dwSize);
585   if (m_ObjStream.m_ObjNumArray.GetSize() < pCreator->m_ObjectStreamSize &&
586       m_ObjStream.m_Buffer.GetLength() < PDF_OBJECTSTREAM_MAXLENGTH) {
587     return 1;
588   }
589   return EndObjectStream(pCreator);
590 }
591 static void _AppendIndex0(CFX_ByteTextBuf& buffer,
592                           FX_BOOL bFirstObject = TRUE) {
593   buffer.AppendByte(0);
594   buffer.AppendByte(0);
595   buffer.AppendByte(0);
596   buffer.AppendByte(0);
597   buffer.AppendByte(0);
598   if (bFirstObject) {
599     buffer.AppendByte(0xFF);
600     buffer.AppendByte(0xFF);
601   } else {
602     buffer.AppendByte(0);
603     buffer.AppendByte(0);
604   }
605 }
606 static void _AppendIndex1(CFX_ByteTextBuf& buffer, FX_FILESIZE offset) {
607   buffer.AppendByte(1);
608   buffer.AppendByte(FX_GETBYTEOFFSET24(offset));
609   buffer.AppendByte(FX_GETBYTEOFFSET16(offset));
610   buffer.AppendByte(FX_GETBYTEOFFSET8(offset));
611   buffer.AppendByte(FX_GETBYTEOFFSET0(offset));
612   buffer.AppendByte(0);
613   buffer.AppendByte(0);
614 }
615 static void _AppendIndex2(CFX_ByteTextBuf& buffer,
616                           FX_DWORD objnum,
617                           int32_t index) {
618   buffer.AppendByte(2);
619   buffer.AppendByte(FX_GETBYTEOFFSET24(objnum));
620   buffer.AppendByte(FX_GETBYTEOFFSET16(objnum));
621   buffer.AppendByte(FX_GETBYTEOFFSET8(objnum));
622   buffer.AppendByte(FX_GETBYTEOFFSET0(objnum));
623   buffer.AppendByte(FX_GETBYTEOFFSET8(index));
624   buffer.AppendByte(FX_GETBYTEOFFSET0(index));
625 }
626 int32_t CPDF_XRefStream::EndObjectStream(CPDF_Creator* pCreator, FX_BOOL bEOF) {
627   FX_FILESIZE objOffset = 0;
628   if (bEOF) {
629     objOffset = m_ObjStream.End(pCreator);
630     if (objOffset < 0) {
631       return -1;
632     }
633   }
634   FX_DWORD& dwObjStmNum = m_ObjStream.m_dwObjNum;
635   if (!dwObjStmNum) {
636     dwObjStmNum = ++pCreator->m_dwLastObjNum;
637   }
638   int32_t iSize = m_ObjStream.m_ObjNumArray.GetSize();
639   int32_t iSeg = m_IndexArray.GetSize() / 2;
640   if (!(pCreator->m_dwFlags & FPDFCREATE_INCREMENTAL)) {
641     if (m_dwTempObjNum == 0) {
642       _AppendIndex0(m_Buffer);
643       m_dwTempObjNum++;
644     }
645     FX_DWORD end_num = m_IndexArray.GetAt((iSeg - 1) * 2) +
646                        m_IndexArray.GetAt((iSeg - 1) * 2 + 1);
647     int index = 0;
648     for (; m_dwTempObjNum < end_num; m_dwTempObjNum++) {
649       FX_FILESIZE* offset = pCreator->m_ObjectOffset.GetPtrAt(m_dwTempObjNum);
650       if (offset) {
651         if (index >= iSize ||
652             m_dwTempObjNum != m_ObjStream.m_ObjNumArray[index]) {
653           _AppendIndex1(m_Buffer, *offset);
654         } else {
655           _AppendIndex2(m_Buffer, dwObjStmNum, index++);
656         }
657       } else {
658         _AppendIndex0(m_Buffer, FALSE);
659       }
660     }
661     if (iSize > 0 && bEOF) {
662       pCreator->m_ObjectOffset.Add(dwObjStmNum, 1);
663       pCreator->m_ObjectSize.Add(dwObjStmNum, 1);
664       pCreator->m_ObjectOffset[dwObjStmNum] = objOffset;
665     }
666     m_iSeg = iSeg;
667     if (bEOF) {
668       m_ObjStream.Start();
669     }
670     return 1;
671   }
672   int32_t& j = m_ObjStream.m_index;
673   for (int i = m_iSeg; i < iSeg; i++) {
674     FX_DWORD start = m_IndexArray.ElementAt(i * 2);
675     FX_DWORD end = m_IndexArray.ElementAt(i * 2 + 1) + start;
676     for (FX_DWORD m = start; m < end; m++) {
677       if (j >= iSize || m != m_ObjStream.m_ObjNumArray.ElementAt(j)) {
678         _AppendIndex1(m_Buffer, pCreator->m_ObjectOffset[m]);
679       } else {
680         _AppendIndex2(m_Buffer, dwObjStmNum, j++);
681       }
682     }
683   }
684   if (iSize > 0 && bEOF) {
685     _AppendIndex1(m_Buffer, objOffset);
686     m_IndexArray.Add(dwObjStmNum);
687     m_IndexArray.Add(1);
688     iSeg += 1;
689   }
690   m_iSeg = iSeg;
691   if (bEOF) {
692     m_ObjStream.Start();
693   }
694   return 1;
695 }
696 FX_BOOL CPDF_XRefStream::GenerateXRefStream(CPDF_Creator* pCreator,
697                                             FX_BOOL bEOF) {
698   FX_FILESIZE offset_tmp = pCreator->m_Offset;
699   FX_DWORD objnum = ++pCreator->m_dwLastObjNum;
700   CFX_FileBufferArchive* pFile = &pCreator->m_File;
701   FX_BOOL bIncremental = (pCreator->m_dwFlags & FPDFCREATE_INCREMENTAL) != 0;
702   if (bIncremental) {
703     AddObjectNumberToIndexArray(objnum);
704   } else {
705     for (; m_dwTempObjNum < pCreator->m_dwLastObjNum; m_dwTempObjNum++) {
706       FX_FILESIZE* offset = pCreator->m_ObjectOffset.GetPtrAt(m_dwTempObjNum);
707       if (offset) {
708         _AppendIndex1(m_Buffer, *offset);
709       } else {
710         _AppendIndex0(m_Buffer, FALSE);
711       }
712     }
713   }
714   _AppendIndex1(m_Buffer, offset_tmp);
715   FX_FILESIZE& offset = pCreator->m_Offset;
716   int32_t len = pFile->AppendDWord(objnum);
717   if (len < 0) {
718     return FALSE;
719   }
720   offset += len;
721   if ((len = pFile->AppendString(
722            FX_BSTRC(" 0 obj\r\n<</Type /XRef/W[1 4 2]/Index["))) < 0) {
723     return FALSE;
724   }
725   offset += len;
726   if (!bIncremental) {
727     if ((len = pFile->AppendDWord(0)) < 0) {
728       return FALSE;
729     }
730     if ((len = pFile->AppendString(FX_BSTRC(" "))) < 0) {
731       return FALSE;
732     }
733     offset += len + 1;
734     if ((len = pFile->AppendDWord(objnum + 1)) < 0) {
735       return FALSE;
736     }
737     offset += len;
738   } else {
739     int32_t iSeg = m_IndexArray.GetSize() / 2;
740     for (int32_t i = 0; i < iSeg; i++) {
741       if ((len = pFile->AppendDWord(m_IndexArray.ElementAt(i * 2))) < 0) {
742         return FALSE;
743       }
744       if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
745         return FALSE;
746       }
747       offset += len + 1;
748       if ((len = pFile->AppendDWord(m_IndexArray.ElementAt(i * 2 + 1))) < 0) {
749         return FALSE;
750       }
751       if (pFile->AppendString(FX_BSTRC(" ")) < 0) {
752         return FALSE;
753       }
754       offset += len + 1;
755     }
756   }
757   if (pFile->AppendString(FX_BSTRC("]/Size ")) < 0) {
758     return FALSE;
759   }
760   if ((len = pFile->AppendDWord(objnum + 1)) < 0) {
761     return FALSE;
762   }
763   offset += len + 7;
764   if (m_PrevOffset > 0) {
765     if (pFile->AppendString(FX_BSTRC("/Prev ")) < 0) {
766       return FALSE;
767     }
768     FX_CHAR offset_buf[20];
769     FXSYS_memset(offset_buf, 0, sizeof(offset_buf));
770     FXSYS_i64toa(m_PrevOffset, offset_buf, 10);
771     int32_t len = (int32_t)FXSYS_strlen(offset_buf);
772     if (pFile->AppendBlock(offset_buf, len) < 0) {
773       return FALSE;
774     }
775     offset += len + 6;
776   }
777   FX_BOOL bPredictor = TRUE;
778   CPDF_FlateEncoder encoder;
779   encoder.Initialize(m_Buffer.GetBuffer(), m_Buffer.GetLength(),
780                      pCreator->m_bCompress, bPredictor);
781   if (pCreator->m_bCompress) {
782     if (pFile->AppendString(FX_BSTRC("/Filter /FlateDecode")) < 0) {
783       return FALSE;
784     }
785     offset += 20;
786     if (bPredictor) {
787       if ((len = pFile->AppendString(
788                FX_BSTRC("/DecodeParms<</Columns 7/Predictor 12>>"))) < 0) {
789         return FALSE;
790       }
791       offset += len;
792     }
793   }
794   if (pFile->AppendString(FX_BSTRC("/Length ")) < 0) {
795     return FALSE;
796   }
797   if ((len = pFile->AppendDWord(encoder.m_dwSize)) < 0) {
798     return FALSE;
799   }
800   offset += len + 8;
801   if (bEOF) {
802     if ((len = PDF_CreatorWriteTrailer(pCreator->m_pDocument, pFile,
803                                        pCreator->m_pIDArray,
804                                        pCreator->m_bCompress)) < 0) {
805       return FALSE;
806     }
807     offset += len;
808     if (pCreator->m_pEncryptDict) {
809       FX_DWORD dwEncryptObjNum = pCreator->m_pEncryptDict->GetObjNum();
810       if (dwEncryptObjNum == 0) {
811         dwEncryptObjNum = pCreator->m_dwEnryptObjNum;
812       }
813       if ((len = PDF_CreatorWriteEncrypt(pCreator->m_pEncryptDict,
814                                          dwEncryptObjNum, pFile)) < 0) {
815         return FALSE;
816       }
817       offset += len;
818     }
819   }
820   if ((len = pFile->AppendString(FX_BSTRC(">>stream\r\n"))) < 0) {
821     return FALSE;
822   }
823   offset += len;
824   if (pFile->AppendBlock(encoder.m_pData, encoder.m_dwSize) < 0) {
825     return FALSE;
826   }
827   if ((len = pFile->AppendString(FX_BSTRC("\r\nendstream\r\nendobj\r\n"))) <
828       0) {
829     return FALSE;
830   }
831   offset += encoder.m_dwSize + len;
832   m_PrevOffset = offset_tmp;
833   return TRUE;
834 }
835 FX_BOOL CPDF_XRefStream::End(CPDF_Creator* pCreator, FX_BOOL bEOF) {
836   if (EndObjectStream(pCreator, bEOF) < 0) {
837     return FALSE;
838   }
839   return GenerateXRefStream(pCreator, bEOF);
840 }
841 FX_BOOL CPDF_XRefStream::EndXRefStream(CPDF_Creator* pCreator) {
842   if (!(pCreator->m_dwFlags & FPDFCREATE_INCREMENTAL)) {
843     _AppendIndex0(m_Buffer);
844     for (FX_DWORD i = 1; i < pCreator->m_dwLastObjNum + 1; i++) {
845       FX_FILESIZE* offset = pCreator->m_ObjectOffset.GetPtrAt(i);
846       if (offset) {
847         _AppendIndex1(m_Buffer, *offset);
848       } else {
849         _AppendIndex0(m_Buffer, FALSE);
850       }
851     }
852   } else {
853     int32_t iSeg = m_IndexArray.GetSize() / 2;
854     for (int i = 0; i < iSeg; i++) {
855       FX_DWORD start = m_IndexArray.ElementAt(i * 2);
856       FX_DWORD end = m_IndexArray.ElementAt(i * 2 + 1) + start;
857       for (FX_DWORD j = start; j < end; j++) {
858         _AppendIndex1(m_Buffer, pCreator->m_ObjectOffset[j]);
859       }
860     }
861   }
862   return GenerateXRefStream(pCreator, FALSE);
863 }
864 FX_BOOL CPDF_XRefStream::AddObjectNumberToIndexArray(FX_DWORD objnum) {
865   int32_t iSize = m_IndexArray.GetSize();
866   if (iSize == 0) {
867     m_IndexArray.Add(objnum);
868     m_IndexArray.Add(1);
869   } else {
870     FXSYS_assert(iSize > 1);
871     FX_DWORD startobjnum = m_IndexArray.ElementAt(iSize - 2);
872     int32_t iCount = m_IndexArray.ElementAt(iSize - 1);
873     if (objnum == startobjnum + iCount) {
874       m_IndexArray[iSize - 1] = iCount + 1;
875     } else {
876       m_IndexArray.Add(objnum);
877       m_IndexArray.Add(1);
878     }
879   }
880   return TRUE;
881 }
882 CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc) {
883   m_pDocument = pDoc;
884   m_pParser = (CPDF_Parser*)pDoc->m_pParser;
885   m_bCompress = TRUE;
886   if (m_pParser) {
887     m_pEncryptDict = m_pParser->GetEncryptDict();
888     m_pCryptoHandler = m_pParser->GetCryptoHandler();
889   } else {
890     m_pEncryptDict = NULL;
891     m_pCryptoHandler = NULL;
892   }
893   m_bSecurityChanged = FALSE;
894   m_bStandardSecurity = FALSE;
895   m_pMetadata = NULL;
896   m_bEncryptCloned = FALSE;
897   m_bEncryptMetadata = FALSE;
898   m_Offset = 0;
899   m_iStage = -1;
900   m_dwFlags = 0;
901   m_Pos = NULL;
902   m_XrefStart = 0;
903   m_pXRefStream = NULL;
904   m_ObjectStreamSize = 200;
905   m_dwLastObjNum = m_pDocument->GetLastObjNum();
906   m_pIDArray = NULL;
907   m_FileVersion = 0;
908   m_dwEnryptObjNum = 0;
909   m_bNewCrypto = FALSE;
910 }
911 CPDF_Creator::~CPDF_Creator() {
912   ResetStandardSecurity();
913   if (m_bEncryptCloned && m_pEncryptDict) {
914     m_pEncryptDict->Release();
915     m_pEncryptDict = NULL;
916   }
917   Clear();
918 }
919 static FX_BOOL _IsXRefNeedEnd(CPDF_XRefStream* pXRef, FX_DWORD flag) {
920   if (!(flag & FPDFCREATE_INCREMENTAL)) {
921     return FALSE;
922   }
923   int32_t iSize = pXRef->m_IndexArray.GetSize() / 2;
924   int32_t iCount = 0;
925   for (int32_t i = 0; i < iSize; i++) {
926     iCount += pXRef->m_IndexArray.ElementAt(i * 2 + 1);
927   }
928   return (iCount >= PDF_XREFSTREAM_MAXSIZE);
929 }
930 int32_t CPDF_Creator::WriteIndirectObjectToStream(const CPDF_Object* pObj) {
931   if (!m_pXRefStream) {
932     return 1;
933   }
934   FX_DWORD objnum = pObj->GetObjNum();
935   if (m_pParser && m_pParser->m_ObjVersion.GetSize() > (int32_t)objnum &&
936       m_pParser->m_ObjVersion[objnum] > 0) {
937     return 1;
938   }
939   if (pObj->GetType() == PDFOBJ_NUMBER) {
940     return 1;
941   }
942   CPDF_Dictionary* pDict = pObj->GetDict();
943   if (pObj->GetType() == PDFOBJ_STREAM) {
944     if (pDict && pDict->GetString(FX_BSTRC("Type")) == FX_BSTRC("XRef")) {
945       return 0;
946     }
947     return 1;
948   }
949   if (pDict) {
950     if (pDict == m_pDocument->m_pRootDict || pDict == m_pEncryptDict) {
951       return 1;
952     }
953     if (IsSignatureDict(pDict)) {
954       return 1;
955     }
956     if (pDict->GetString(FX_BSTRC("Type")) == FX_BSTRC("Page")) {
957       return 1;
958     }
959   }
960   m_pXRefStream->AddObjectNumberToIndexArray(objnum);
961   if (m_pXRefStream->CompressIndirectObject(objnum, pObj, this) < 0) {
962     return -1;
963   }
964   if (!_IsXRefNeedEnd(m_pXRefStream, m_dwFlags)) {
965     return 0;
966   }
967   if (!m_pXRefStream->End(this)) {
968     return -1;
969   }
970   if (!m_pXRefStream->Start()) {
971     return -1;
972   }
973   return 0;
974 }
975 int32_t CPDF_Creator::WriteIndirectObjectToStream(FX_DWORD objnum,
976                                                   const uint8_t* pBuffer,
977                                                   FX_DWORD dwSize) {
978   if (!m_pXRefStream) {
979     return 1;
980   }
981   m_pXRefStream->AddObjectNumberToIndexArray(objnum);
982   int32_t iRet =
983       m_pXRefStream->CompressIndirectObject(objnum, pBuffer, dwSize, this);
984   if (iRet < 1) {
985     return iRet;
986   }
987   if (!_IsXRefNeedEnd(m_pXRefStream, m_dwFlags)) {
988     return 0;
989   }
990   if (!m_pXRefStream->End(this)) {
991     return -1;
992   }
993   if (!m_pXRefStream->Start()) {
994     return -1;
995   }
996   return 0;
997 }
998 int32_t CPDF_Creator::AppendObjectNumberToXRef(FX_DWORD objnum) {
999   if (!m_pXRefStream) {
1000     return 1;
1001   }
1002   m_pXRefStream->AddObjectNumberToIndexArray(objnum);
1003   if (!_IsXRefNeedEnd(m_pXRefStream, m_dwFlags)) {
1004     return 0;
1005   }
1006   if (!m_pXRefStream->End(this)) {
1007     return -1;
1008   }
1009   if (!m_pXRefStream->Start()) {
1010     return -1;
1011   }
1012   return 0;
1013 }
1014 int32_t CPDF_Creator::WriteStream(const CPDF_Object* pStream,
1015                                   FX_DWORD objnum,
1016                                   CPDF_CryptoHandler* pCrypto) {
1017   CPDF_FlateEncoder encoder;
1018   encoder.Initialize((CPDF_Stream*)pStream,
1019                      pStream == m_pMetadata ? FALSE : m_bCompress);
1020   CPDF_Encryptor encryptor;
1021   if (!encryptor.Initialize(pCrypto, objnum, encoder.m_pData,
1022                             encoder.m_dwSize)) {
1023     return -1;
1024   }
1025   if ((FX_DWORD)encoder.m_pDict->GetInteger(FX_BSTRC("Length")) !=
1026       encryptor.m_dwSize) {
1027     encoder.CloneDict();
1028     encoder.m_pDict->SetAtInteger(FX_BSTRC("Length"), encryptor.m_dwSize);
1029   }
1030   if (WriteDirectObj(objnum, encoder.m_pDict) < 0) {
1031     return -1;
1032   }
1033   int len = m_File.AppendString(FX_BSTRC("stream\r\n"));
1034   if (len < 0) {
1035     return -1;
1036   }
1037   m_Offset += len;
1038   if (m_File.AppendBlock(encryptor.m_pData, encryptor.m_dwSize) < 0) {
1039     return -1;
1040   }
1041   m_Offset += encryptor.m_dwSize;
1042   if ((len = m_File.AppendString(FX_BSTRC("\r\nendstream"))) < 0) {
1043     return -1;
1044   }
1045   m_Offset += len;
1046   return 1;
1047 }
1048 int32_t CPDF_Creator::WriteIndirectObj(FX_DWORD objnum,
1049                                        const CPDF_Object* pObj) {
1050   int32_t len = m_File.AppendDWord(objnum);
1051   if (len < 0) {
1052     return -1;
1053   }
1054   m_Offset += len;
1055   if ((len = m_File.AppendString(FX_BSTRC(" 0 obj\r\n"))) < 0) {
1056     return -1;
1057   }
1058   m_Offset += len;
1059   if (pObj->GetType() == PDFOBJ_STREAM) {
1060     CPDF_CryptoHandler* pHandler = NULL;
1061     pHandler =
1062         (pObj == m_pMetadata && !m_bEncryptMetadata) ? NULL : m_pCryptoHandler;
1063     if (WriteStream(pObj, objnum, pHandler) < 0) {
1064       return -1;
1065     }
1066   } else {
1067     if (WriteDirectObj(objnum, pObj) < 0) {
1068       return -1;
1069     }
1070   }
1071   if ((len = m_File.AppendString(FX_BSTRC("\r\nendobj\r\n"))) < 0) {
1072     return -1;
1073   }
1074   m_Offset += len;
1075   if (AppendObjectNumberToXRef(objnum) < 0) {
1076     return -1;
1077   }
1078   return 0;
1079 }
1080 int32_t CPDF_Creator::WriteIndirectObj(const CPDF_Object* pObj) {
1081   int32_t iRet = WriteIndirectObjectToStream(pObj);
1082   if (iRet < 1) {
1083     return iRet;
1084   }
1085   return WriteIndirectObj(pObj->GetObjNum(), pObj);
1086 }
1087 int32_t CPDF_Creator::WriteDirectObj(FX_DWORD objnum,
1088                                      const CPDF_Object* pObj,
1089                                      FX_BOOL bEncrypt) {
1090   int32_t len = 0;
1091   if (pObj == NULL) {
1092     if (m_File.AppendString(FX_BSTRC(" null")) < 0) {
1093       return -1;
1094     }
1095     m_Offset += 5;
1096     return 1;
1097   }
1098   switch (pObj->GetType()) {
1099     case PDFOBJ_NULL:
1100       if (m_File.AppendString(FX_BSTRC(" null")) < 0) {
1101         return -1;
1102       }
1103       m_Offset += 5;
1104       break;
1105     case PDFOBJ_BOOLEAN:
1106     case PDFOBJ_NUMBER:
1107       if (m_File.AppendString(FX_BSTRC(" ")) < 0) {
1108         return -1;
1109       }
1110       if ((len = m_File.AppendString(pObj->GetString())) < 0) {
1111         return -1;
1112       }
1113       m_Offset += len + 1;
1114       break;
1115     case PDFOBJ_STRING: {
1116       CFX_ByteString str = pObj->GetString();
1117       FX_BOOL bHex = ((CPDF_String*)pObj)->IsHex();
1118       if (m_pCryptoHandler == NULL || !bEncrypt) {
1119         CFX_ByteString content = PDF_EncodeString(str, bHex);
1120         if ((len = m_File.AppendString(content)) < 0) {
1121           return -1;
1122         }
1123         m_Offset += len;
1124         break;
1125       }
1126       CPDF_Encryptor encryptor;
1127       encryptor.Initialize(m_pCryptoHandler, objnum, (uint8_t*)str.c_str(),
1128                            str.GetLength());
1129       CFX_ByteString content = PDF_EncodeString(
1130           CFX_ByteString((const FX_CHAR*)encryptor.m_pData, encryptor.m_dwSize),
1131           bHex);
1132       if ((len = m_File.AppendString(content)) < 0) {
1133         return -1;
1134       }
1135       m_Offset += len;
1136       break;
1137     }
1138     case PDFOBJ_STREAM: {
1139       CPDF_FlateEncoder encoder;
1140       encoder.Initialize((CPDF_Stream*)pObj, m_bCompress);
1141       CPDF_Encryptor encryptor;
1142       CPDF_CryptoHandler* pHandler = m_pCryptoHandler;
1143       encryptor.Initialize(pHandler, objnum, encoder.m_pData, encoder.m_dwSize);
1144       if ((FX_DWORD)encoder.m_pDict->GetInteger(FX_BSTRC("Length")) !=
1145           encryptor.m_dwSize) {
1146         encoder.CloneDict();
1147         encoder.m_pDict->SetAtInteger(FX_BSTRC("Length"), encryptor.m_dwSize);
1148       }
1149       if (WriteDirectObj(objnum, encoder.m_pDict) < 0) {
1150         return -1;
1151       }
1152       if ((len = m_File.AppendString(FX_BSTRC("stream\r\n"))) < 0) {
1153         return -1;
1154       }
1155       m_Offset += len;
1156       if (m_File.AppendBlock(encryptor.m_pData, encryptor.m_dwSize) < 0) {
1157         return -1;
1158       }
1159       m_Offset += encryptor.m_dwSize;
1160       if ((len = m_File.AppendString(FX_BSTRC("\r\nendstream"))) < 0) {
1161         return -1;
1162       }
1163       m_Offset += len;
1164       break;
1165     }
1166     case PDFOBJ_NAME: {
1167       if (m_File.AppendString(FX_BSTRC("/")) < 0) {
1168         return -1;
1169       }
1170       CFX_ByteString str = pObj->GetString();
1171       if ((len = m_File.AppendString(PDF_NameEncode(str))) < 0) {
1172         return -1;
1173       }
1174       m_Offset += len + 1;
1175       break;
1176     }
1177     case PDFOBJ_REFERENCE: {
1178       if (m_File.AppendString(FX_BSTRC(" ")) < 0) {
1179         return -1;
1180       }
1181       CPDF_Reference* p = (CPDF_Reference*)pObj;
1182       if ((len = m_File.AppendDWord(p->GetRefObjNum())) < 0) {
1183         return -1;
1184       }
1185       if (m_File.AppendString(FX_BSTRC(" 0 R")) < 0) {
1186         return -1;
1187       }
1188       m_Offset += len + 5;
1189       break;
1190     }
1191     case PDFOBJ_ARRAY: {
1192       if (m_File.AppendString(FX_BSTRC("[")) < 0) {
1193         return -1;
1194       }
1195       m_Offset += 1;
1196       CPDF_Array* p = (CPDF_Array*)pObj;
1197       for (FX_DWORD i = 0; i < p->GetCount(); i++) {
1198         CPDF_Object* pElement = p->GetElement(i);
1199         if (pElement->GetObjNum()) {
1200           if (m_File.AppendString(FX_BSTRC(" ")) < 0) {
1201             return -1;
1202           }
1203           if ((len = m_File.AppendDWord(pElement->GetObjNum())) < 0) {
1204             return -1;
1205           }
1206           if (m_File.AppendString(FX_BSTRC(" 0 R")) < 0) {
1207             return -1;
1208           }
1209           m_Offset += len + 5;
1210         } else {
1211           if (WriteDirectObj(objnum, pElement) < 0) {
1212             return -1;
1213           }
1214         }
1215       }
1216       if (m_File.AppendString(FX_BSTRC("]")) < 0) {
1217         return -1;
1218       }
1219       m_Offset += 1;
1220       break;
1221     }
1222     case PDFOBJ_DICTIONARY: {
1223       if (m_pCryptoHandler == NULL || pObj == m_pEncryptDict) {
1224         return PDF_CreatorAppendObject(pObj, &m_File, m_Offset);
1225       }
1226       if (m_File.AppendString(FX_BSTRC("<<")) < 0) {
1227         return -1;
1228       }
1229       m_Offset += 2;
1230       CPDF_Dictionary* p = (CPDF_Dictionary*)pObj;
1231       FX_BOOL bSignDict = IsSignatureDict(p);
1232       FX_POSITION pos = p->GetStartPos();
1233       while (pos) {
1234         FX_BOOL bSignValue = FALSE;
1235         CFX_ByteString key;
1236         CPDF_Object* pValue = p->GetNextElement(pos, key);
1237         if (m_File.AppendString(FX_BSTRC("/")) < 0) {
1238           return -1;
1239         }
1240         if ((len = m_File.AppendString(PDF_NameEncode(key))) < 0) {
1241           return -1;
1242         }
1243         m_Offset += len + 1;
1244         if (bSignDict && key == FX_BSTRC("Contents")) {
1245           bSignValue = TRUE;
1246         }
1247         if (pValue->GetObjNum()) {
1248           if (m_File.AppendString(FX_BSTRC(" ")) < 0) {
1249             return -1;
1250           }
1251           if ((len = m_File.AppendDWord(pValue->GetObjNum())) < 0) {
1252             return -1;
1253           }
1254           if (m_File.AppendString(FX_BSTRC(" 0 R ")) < 0) {
1255             return -1;
1256           }
1257           m_Offset += len + 6;
1258         } else {
1259           if (WriteDirectObj(objnum, pValue, !bSignValue) < 0) {
1260             return -1;
1261           }
1262         }
1263       }
1264       if (m_File.AppendString(FX_BSTRC(">>")) < 0) {
1265         return -1;
1266       }
1267       m_Offset += 2;
1268       break;
1269     }
1270   }
1271   return 1;
1272 }
1273 int32_t CPDF_Creator::WriteOldIndirectObject(FX_DWORD objnum) {
1274   if (m_pParser->m_V5Type[objnum] == 0 || m_pParser->m_V5Type[objnum] == 255) {
1275     return 0;
1276   }
1277   m_ObjectOffset[objnum] = m_Offset;
1278   void* valuetemp = NULL;
1279   FX_BOOL bExistInMap =
1280       m_pDocument->m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, valuetemp);
1281   FX_BOOL bObjStm =
1282       (m_pParser->m_V5Type[objnum] == 2) && m_pEncryptDict && !m_pXRefStream;
1283   if (m_pParser->m_bVersionUpdated || m_bSecurityChanged || bExistInMap ||
1284       bObjStm) {
1285     CPDF_Object* pObj = m_pDocument->GetIndirectObject(objnum);
1286     if (pObj == NULL) {
1287       m_ObjectOffset[objnum] = 0;
1288       m_ObjectSize[objnum] = 0;
1289       return 0;
1290     }
1291     if (WriteIndirectObj(pObj)) {
1292       return -1;
1293     }
1294     if (!bExistInMap) {
1295       m_pDocument->ReleaseIndirectObject(objnum);
1296     }
1297   } else {
1298     uint8_t* pBuffer;
1299     FX_DWORD size;
1300     m_pParser->GetIndirectBinary(objnum, pBuffer, size);
1301     if (pBuffer == NULL) {
1302       return 0;
1303     }
1304     if (m_pParser->m_V5Type[objnum] == 2) {
1305       if (m_pXRefStream) {
1306         if (WriteIndirectObjectToStream(objnum, pBuffer, size) < 0) {
1307           FX_Free(pBuffer);
1308           return -1;
1309         }
1310       } else {
1311         int32_t len = m_File.AppendDWord(objnum);
1312         if (len < 0) {
1313           return -1;
1314         }
1315         if (m_File.AppendString(FX_BSTRC(" 0 obj ")) < 0) {
1316           return -1;
1317         }
1318         m_Offset += len + 7;
1319         if (m_File.AppendBlock(pBuffer, size) < 0) {
1320           return -1;
1321         }
1322         m_Offset += size;
1323         if (m_File.AppendString(FX_BSTRC("\r\nendobj\r\n")) < 0) {
1324           return -1;
1325         }
1326         m_Offset += 10;
1327       }
1328     } else {
1329       if (m_File.AppendBlock(pBuffer, size) < 0) {
1330         return -1;
1331       }
1332       m_Offset += size;
1333       if (AppendObjectNumberToXRef(objnum) < 0) {
1334         return -1;
1335       }
1336     }
1337     FX_Free(pBuffer);
1338   }
1339   return 1;
1340 }
1341 int32_t CPDF_Creator::WriteOldObjs(IFX_Pause* pPause) {
1342   FX_DWORD nOldSize = m_pParser->m_CrossRef.GetSize();
1343   FX_DWORD objnum = (FX_DWORD)(uintptr_t)m_Pos;
1344   for (; objnum < nOldSize; objnum++) {
1345     int32_t iRet = WriteOldIndirectObject(objnum);
1346     if (!iRet) {
1347       continue;
1348     }
1349     if (iRet < 0) {
1350       return iRet;
1351     }
1352     m_ObjectSize[objnum] = (FX_DWORD)(m_Offset - m_ObjectOffset[objnum]);
1353     if (pPause && pPause->NeedToPauseNow()) {
1354       m_Pos = (void*)(uintptr_t)(objnum + 1);
1355       return 1;
1356     }
1357   }
1358   return 0;
1359 }
1360 int32_t CPDF_Creator::WriteNewObjs(FX_BOOL bIncremental, IFX_Pause* pPause) {
1361   int32_t iCount = m_NewObjNumArray.GetSize();
1362   int32_t index = (int32_t)(uintptr_t)m_Pos;
1363   while (index < iCount) {
1364     FX_DWORD objnum = m_NewObjNumArray.ElementAt(index);
1365     CPDF_Object* pObj = NULL;
1366     m_pDocument->m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, (void*&)pObj);
1367     if (NULL == pObj) {
1368       ++index;
1369       continue;
1370     }
1371     m_ObjectOffset[objnum] = m_Offset;
1372     if (WriteIndirectObj(pObj)) {
1373       return -1;
1374     }
1375     m_ObjectSize[objnum] = (FX_DWORD)(m_Offset - m_ObjectOffset[objnum]);
1376     index++;
1377     if (pPause && pPause->NeedToPauseNow()) {
1378       m_Pos = (FX_POSITION)(uintptr_t)index;
1379       return 1;
1380     }
1381   }
1382   return 0;
1383 }
1384 void CPDF_Creator::InitOldObjNumOffsets() {
1385   if (!m_pParser) {
1386     return;
1387   }
1388   FX_DWORD j = 0;
1389   FX_DWORD dwStart = 0;
1390   FX_DWORD dwEnd = m_pParser->GetLastObjNum();
1391   while (dwStart <= dwEnd) {
1392     while (dwStart <= dwEnd && (m_pParser->m_V5Type[dwStart] == 0 ||
1393                                 m_pParser->m_V5Type[dwStart] == 255)) {
1394       dwStart++;
1395     }
1396     if (dwStart > dwEnd) {
1397       break;
1398     }
1399     j = dwStart;
1400     while (j <= dwEnd && m_pParser->m_V5Type[j] != 0 &&
1401            m_pParser->m_V5Type[j] != 255) {
1402       j++;
1403     }
1404     m_ObjectOffset.Add(dwStart, j - dwStart);
1405     m_ObjectSize.Add(dwStart, j - dwStart);
1406     dwStart = j;
1407   }
1408 }
1409 void CPDF_Creator::InitNewObjNumOffsets() {
1410   FX_BOOL bIncremental = (m_dwFlags & FPDFCREATE_INCREMENTAL) != 0;
1411   FX_BOOL bNoOriginal = (m_dwFlags & FPDFCREATE_NO_ORIGINAL) != 0;
1412   FX_DWORD nOldSize = m_pParser ? m_pParser->m_CrossRef.GetSize() : 0;
1413   FX_POSITION pos = m_pDocument->m_IndirectObjs.GetStartPosition();
1414   while (pos) {
1415     size_t key = 0;
1416     CPDF_Object* pObj;
1417     m_pDocument->m_IndirectObjs.GetNextAssoc(pos, (void*&)key, (void*&)pObj);
1418     FX_DWORD objnum = (FX_DWORD)key;
1419     if (pObj->GetObjNum() == -1) {
1420       continue;
1421     }
1422     if (bIncremental) {
1423       if (!pObj->IsModified()) {
1424         continue;
1425       }
1426     } else {
1427       if (objnum < nOldSize && m_pParser->m_V5Type[objnum] != 0) {
1428         continue;
1429       }
1430     }
1431     AppendNewObjNum(objnum);
1432   }
1433   int32_t iCount = m_NewObjNumArray.GetSize();
1434   if (iCount == 0) {
1435     return;
1436   }
1437   int32_t i = 0;
1438   FX_DWORD dwStartObjNum = 0;
1439   FX_BOOL bCrossRefValid = m_pParser && m_pParser->GetLastXRefOffset() > 0;
1440   while (i < iCount) {
1441     dwStartObjNum = m_NewObjNumArray.ElementAt(i);
1442     if ((bIncremental && (bNoOriginal || bCrossRefValid)) ||
1443         !m_ObjectOffset.GetPtrAt(dwStartObjNum)) {
1444       break;
1445     }
1446     i++;
1447   }
1448   if (i >= iCount) {
1449     return;
1450   }
1451   FX_DWORD dwLastObjNum = dwStartObjNum;
1452   i++;
1453   FX_BOOL bNewStart = FALSE;
1454   for (; i < iCount; i++) {
1455     FX_DWORD dwCurObjNum = m_NewObjNumArray.ElementAt(i);
1456     FX_BOOL bExist = (dwCurObjNum < nOldSize &&
1457                       m_ObjectOffset.GetPtrAt(dwCurObjNum) != NULL);
1458     if (bExist || dwCurObjNum - dwLastObjNum > 1) {
1459       if (!bNewStart) {
1460         m_ObjectOffset.Add(dwStartObjNum, dwLastObjNum - dwStartObjNum + 1);
1461         m_ObjectSize.Add(dwStartObjNum, dwLastObjNum - dwStartObjNum + 1);
1462       }
1463       dwStartObjNum = dwCurObjNum;
1464     }
1465     if (bNewStart) {
1466       dwStartObjNum = dwCurObjNum;
1467     }
1468     bNewStart = bExist;
1469     dwLastObjNum = dwCurObjNum;
1470   }
1471   m_ObjectOffset.Add(dwStartObjNum, dwLastObjNum - dwStartObjNum + 1);
1472   m_ObjectSize.Add(dwStartObjNum, dwLastObjNum - dwStartObjNum + 1);
1473 }
1474 void CPDF_Creator::AppendNewObjNum(FX_DWORD objbum) {
1475   int32_t iStart = 0, iFind = 0;
1476   int32_t iEnd = m_NewObjNumArray.GetUpperBound();
1477   while (iStart <= iEnd) {
1478     int32_t iMid = (iStart + iEnd) / 2;
1479     FX_DWORD dwMid = m_NewObjNumArray.ElementAt(iMid);
1480     if (objbum < dwMid) {
1481       iEnd = iMid - 1;
1482     } else {
1483       if (iMid == iEnd) {
1484         iFind = iMid + 1;
1485         break;
1486       }
1487       FX_DWORD dwNext = m_NewObjNumArray.ElementAt(iMid + 1);
1488       if (objbum < dwNext) {
1489         iFind = iMid + 1;
1490         break;
1491       }
1492       iStart = iMid + 1;
1493     }
1494   }
1495   m_NewObjNumArray.InsertAt(iFind, objbum);
1496 }
1497 int32_t CPDF_Creator::WriteDoc_Stage1(IFX_Pause* pPause) {
1498   FXSYS_assert(m_iStage > -1 || m_iStage < 20);
1499   if (m_iStage == 0) {
1500     if (m_pParser == NULL) {
1501       m_dwFlags &= ~FPDFCREATE_INCREMENTAL;
1502     }
1503     if (m_bSecurityChanged && (m_dwFlags & FPDFCREATE_NO_ORIGINAL) == 0) {
1504       m_dwFlags &= ~FPDFCREATE_INCREMENTAL;
1505     }
1506     CPDF_Dictionary* pDict = m_pDocument->GetRoot();
1507     m_pMetadata = pDict ? pDict->GetElementValue(FX_BSTRC("Metadata")) : NULL;
1508     if (m_dwFlags & FPDFCREATE_OBJECTSTREAM) {
1509       m_pXRefStream = new CPDF_XRefStream;
1510       m_pXRefStream->Start();
1511       if ((m_dwFlags & FPDFCREATE_INCREMENTAL) != 0 && m_pParser) {
1512         FX_FILESIZE prev = m_pParser->GetLastXRefOffset();
1513         m_pXRefStream->m_PrevOffset = prev;
1514       }
1515     }
1516     m_iStage = 10;
1517   }
1518   if (m_iStage == 10) {
1519     if ((m_dwFlags & FPDFCREATE_INCREMENTAL) == 0) {
1520       if (m_File.AppendString(FX_BSTRC("%PDF-1.")) < 0) {
1521         return -1;
1522       }
1523       m_Offset += 7;
1524       int32_t version = 7;
1525       if (m_FileVersion) {
1526         version = m_FileVersion;
1527       } else if (m_pParser) {
1528         version = m_pParser->GetFileVersion();
1529       }
1530       int32_t len = m_File.AppendDWord(version % 10);
1531       if (len < 0) {
1532         return -1;
1533       }
1534       m_Offset += len;
1535       if ((len = m_File.AppendString(FX_BSTRC("\r\n%\xA1\xB3\xC5\xD7\r\n"))) <
1536           0) {
1537         return -1;
1538       }
1539       m_Offset += len;
1540       InitOldObjNumOffsets();
1541       m_iStage = 20;
1542     } else {
1543       IFX_FileRead* pSrcFile = m_pParser->GetFileAccess();
1544       m_Offset = pSrcFile->GetSize();
1545       m_Pos = (void*)(uintptr_t)m_Offset;
1546       m_iStage = 15;
1547     }
1548   }
1549   if (m_iStage == 15) {
1550     if ((m_dwFlags & FPDFCREATE_NO_ORIGINAL) == 0 && m_Pos) {
1551       IFX_FileRead* pSrcFile = m_pParser->GetFileAccess();
1552       uint8_t buffer[4096];
1553       FX_DWORD src_size = (FX_DWORD)(uintptr_t)m_Pos;
1554       while (src_size) {
1555         FX_DWORD block_size = src_size > 4096 ? 4096 : src_size;
1556         if (!pSrcFile->ReadBlock(buffer, m_Offset - src_size, block_size)) {
1557           return -1;
1558         }
1559         if (m_File.AppendBlock(buffer, block_size) < 0) {
1560           return -1;
1561         }
1562         src_size -= block_size;
1563         if (pPause && pPause->NeedToPauseNow()) {
1564           m_Pos = (void*)(uintptr_t)src_size;
1565           return 1;
1566         }
1567       }
1568     }
1569     if ((m_dwFlags & FPDFCREATE_NO_ORIGINAL) == 0 &&
1570         m_pParser->GetLastXRefOffset() == 0) {
1571       InitOldObjNumOffsets();
1572       FX_DWORD dwEnd = m_pParser->GetLastObjNum();
1573       FX_BOOL bObjStm = (m_dwFlags & FPDFCREATE_OBJECTSTREAM) != 0;
1574       for (FX_DWORD objnum = 0; objnum <= dwEnd; objnum++) {
1575         if (m_pParser->m_V5Type[objnum] == 0 ||
1576             m_pParser->m_V5Type[objnum] == 255) {
1577           continue;
1578         }
1579         m_ObjectOffset[objnum] = m_pParser->m_CrossRef[objnum];
1580         if (bObjStm) {
1581           m_pXRefStream->AddObjectNumberToIndexArray(objnum);
1582         }
1583       }
1584       if (bObjStm) {
1585         m_pXRefStream->EndXRefStream(this);
1586         m_pXRefStream->Start();
1587       }
1588     }
1589     m_iStage = 20;
1590   }
1591   InitNewObjNumOffsets();
1592   return m_iStage;
1593 }
1594 int32_t CPDF_Creator::WriteDoc_Stage2(IFX_Pause* pPause) {
1595   FXSYS_assert(m_iStage >= 20 || m_iStage < 30);
1596   if (m_iStage == 20) {
1597     if ((m_dwFlags & FPDFCREATE_INCREMENTAL) == 0 && m_pParser) {
1598       m_Pos = (void*)(uintptr_t)0;
1599       m_iStage = 21;
1600     } else {
1601       m_iStage = 25;
1602     }
1603   }
1604   if (m_iStage == 21) {
1605     int32_t iRet = WriteOldObjs(pPause);
1606     if (iRet) {
1607       return iRet;
1608     }
1609     m_iStage = 25;
1610   }
1611   if (m_iStage == 25) {
1612     m_Pos = (void*)(uintptr_t)0;
1613     m_iStage = 26;
1614   }
1615   if (m_iStage == 26) {
1616     int32_t iRet =
1617         WriteNewObjs((m_dwFlags & FPDFCREATE_INCREMENTAL) != 0, pPause);
1618     if (iRet) {
1619       return iRet;
1620     }
1621     m_iStage = 27;
1622   }
1623   if (m_iStage == 27) {
1624     if (NULL != m_pEncryptDict && 0 == m_pEncryptDict->GetObjNum()) {
1625       m_dwLastObjNum += 1;
1626       FX_FILESIZE saveOffset = m_Offset;
1627       if (WriteIndirectObj(m_dwLastObjNum, m_pEncryptDict) < 0) {
1628         return -1;
1629       }
1630       m_ObjectOffset.Add(m_dwLastObjNum, 1);
1631       m_ObjectOffset[m_dwLastObjNum] = saveOffset;
1632       m_ObjectSize.Add(m_dwLastObjNum, 1);
1633       m_ObjectSize[m_dwLastObjNum] = m_Offset - saveOffset;
1634       m_dwEnryptObjNum = m_dwLastObjNum;
1635       if (m_dwFlags & FPDFCREATE_INCREMENTAL) {
1636         m_NewObjNumArray.Add(m_dwLastObjNum);
1637       }
1638     }
1639     m_iStage = 80;
1640   }
1641   return m_iStage;
1642 }
1643 int32_t CPDF_Creator::WriteDoc_Stage3(IFX_Pause* pPause) {
1644   FXSYS_assert(m_iStage >= 80 || m_iStage < 90);
1645   FX_DWORD dwLastObjNum = m_dwLastObjNum;
1646   if (m_iStage == 80) {
1647     m_XrefStart = m_Offset;
1648     if (m_dwFlags & FPDFCREATE_OBJECTSTREAM) {
1649       m_pXRefStream->End(this, TRUE);
1650       m_XrefStart = m_pXRefStream->m_PrevOffset;
1651       m_iStage = 90;
1652     } else if ((m_dwFlags & FPDFCREATE_INCREMENTAL) == 0 ||
1653                !m_pParser->IsXRefStream()) {
1654       if ((m_dwFlags & FPDFCREATE_INCREMENTAL) == 0 ||
1655           m_pParser->GetLastXRefOffset() == 0) {
1656         CFX_ByteString str;
1657         str = m_ObjectOffset.GetPtrAt(1)
1658                   ? FX_BSTRC("xref\r\n")
1659                   : FX_BSTRC("xref\r\n0 1\r\n0000000000 65536 f\r\n");
1660         if (m_File.AppendString(str) < 0) {
1661           return -1;
1662         }
1663         m_Pos = (void*)(uintptr_t)1;
1664         m_iStage = 81;
1665       } else {
1666         if (m_File.AppendString(FX_BSTRC("xref\r\n")) < 0) {
1667           return -1;
1668         }
1669         m_Pos = (void*)(uintptr_t)0;
1670         m_iStage = 82;
1671       }
1672     } else {
1673       m_iStage = 90;
1674     }
1675   }
1676   if (m_iStage == 81) {
1677     CFX_ByteString str;
1678     FX_DWORD i = (FX_DWORD)(uintptr_t)m_Pos, j;
1679     while (i <= dwLastObjNum) {
1680       while (i <= dwLastObjNum && !m_ObjectOffset.GetPtrAt(i)) {
1681         i++;
1682       }
1683       if (i > dwLastObjNum) {
1684         break;
1685       }
1686       j = i;
1687       while (j <= dwLastObjNum && m_ObjectOffset.GetPtrAt(j)) {
1688         j++;
1689       }
1690       if (i == 1) {
1691         str.Format("0 %d\r\n0000000000 65536 f\r\n", j);
1692       } else {
1693         str.Format("%d %d\r\n", i, j - i);
1694       }
1695       if (m_File.AppendBlock(str.c_str(), str.GetLength()) < 0) {
1696         return -1;
1697       }
1698       while (i < j) {
1699         str.Format("%010d 00000 n\r\n", m_ObjectOffset[i++]);
1700         if (m_File.AppendBlock(str.c_str(), str.GetLength()) < 0) {
1701           return -1;
1702         }
1703       }
1704       if (i > dwLastObjNum) {
1705         break;
1706       }
1707       if (pPause && pPause->NeedToPauseNow()) {
1708         m_Pos = (void*)(uintptr_t)i;
1709         return 1;
1710       }
1711     }
1712     m_iStage = 90;
1713   }
1714   if (m_iStage == 82) {
1715     CFX_ByteString str;
1716     int32_t iCount = m_NewObjNumArray.GetSize();
1717     int32_t i = (int32_t)(uintptr_t)m_Pos;
1718     while (i < iCount) {
1719       int32_t j = i;
1720       FX_DWORD objnum = m_NewObjNumArray.ElementAt(i);
1721       while (j < iCount) {
1722         if (++j == iCount) {
1723           break;
1724         }
1725         FX_DWORD dwCurrent = m_NewObjNumArray.ElementAt(j);
1726         if (dwCurrent - objnum > 1) {
1727           break;
1728         }
1729         objnum = dwCurrent;
1730       }
1731       objnum = m_NewObjNumArray.ElementAt(i);
1732       if (objnum == 1) {
1733         str.Format("0 %d\r\n0000000000 65536 f\r\n", j - i + 1);
1734       } else {
1735         str.Format("%d %d\r\n", objnum, j - i);
1736       }
1737       if (m_File.AppendBlock(str.c_str(), str.GetLength()) < 0) {
1738         return -1;
1739       }
1740       while (i < j) {
1741         objnum = m_NewObjNumArray.ElementAt(i++);
1742         str.Format("%010d 00000 n\r\n", m_ObjectOffset[objnum]);
1743         if (m_File.AppendBlock(str.c_str(), str.GetLength()) < 0) {
1744           return -1;
1745         }
1746       }
1747       if (pPause && (i % 100) == 0 && pPause->NeedToPauseNow()) {
1748         m_Pos = (void*)(uintptr_t)i;
1749         return 1;
1750       }
1751     }
1752     m_iStage = 90;
1753   }
1754   return m_iStage;
1755 }
1756 static int32_t _OutPutIndex(CFX_FileBufferArchive* pFile, FX_FILESIZE offset) {
1757   FXSYS_assert(pFile);
1758   if (sizeof(offset) > 4) {
1759     if (FX_GETBYTEOFFSET32(offset)) {
1760       if (pFile->AppendByte(FX_GETBYTEOFFSET56(offset)) < 0) {
1761         return -1;
1762       }
1763       if (pFile->AppendByte(FX_GETBYTEOFFSET48(offset)) < 0) {
1764         return -1;
1765       }
1766       if (pFile->AppendByte(FX_GETBYTEOFFSET40(offset)) < 0) {
1767         return -1;
1768       }
1769       if (pFile->AppendByte(FX_GETBYTEOFFSET32(offset)) < 0) {
1770         return -1;
1771       }
1772     }
1773   }
1774   if (pFile->AppendByte(FX_GETBYTEOFFSET24(offset)) < 0) {
1775     return -1;
1776   }
1777   if (pFile->AppendByte(FX_GETBYTEOFFSET16(offset)) < 0) {
1778     return -1;
1779   }
1780   if (pFile->AppendByte(FX_GETBYTEOFFSET8(offset)) < 0) {
1781     return -1;
1782   }
1783   if (pFile->AppendByte(FX_GETBYTEOFFSET0(offset)) < 0) {
1784     return -1;
1785   }
1786   if (pFile->AppendByte(0) < 0) {
1787     return -1;
1788   }
1789   return 0;
1790 }
1791 int32_t CPDF_Creator::WriteDoc_Stage4(IFX_Pause* pPause) {
1792   FXSYS_assert(m_iStage >= 90);
1793   if ((m_dwFlags & FPDFCREATE_OBJECTSTREAM) == 0) {
1794     FX_BOOL bXRefStream =
1795         (m_dwFlags & FPDFCREATE_INCREMENTAL) != 0 && m_pParser->IsXRefStream();
1796     if (!bXRefStream) {
1797       if (m_File.AppendString(FX_BSTRC("trailer\r\n<<")) < 0) {
1798         return -1;
1799       }
1800     } else {
1801       if (m_File.AppendDWord(m_pDocument->m_LastObjNum + 1) < 0) {
1802         return -1;
1803       }
1804       if (m_File.AppendString(FX_BSTRC(" 0 obj <<")) < 0) {
1805         return -1;
1806       }
1807     }
1808     if (m_pParser) {
1809       CPDF_Dictionary* p = m_pParser->m_pTrailer;
1810       FX_POSITION pos = p->GetStartPos();
1811       while (pos) {
1812         CFX_ByteString key;
1813         CPDF_Object* pValue = p->GetNextElement(pos, key);
1814         if (key == FX_BSTRC("Encrypt") || key == FX_BSTRC("Size") ||
1815             key == FX_BSTRC("Filter") || key == FX_BSTRC("Index") ||
1816             key == FX_BSTRC("Length") || key == FX_BSTRC("Prev") ||
1817             key == FX_BSTRC("W") || key == FX_BSTRC("XRefStm") ||
1818             key == FX_BSTRC("ID")) {
1819           continue;
1820         }
1821         if (m_File.AppendString((FX_BSTRC("/"))) < 0) {
1822           return -1;
1823         }
1824         if (m_File.AppendString(PDF_NameEncode(key)) < 0) {
1825           return -1;
1826         }
1827         if (pValue->GetObjNum()) {
1828           if (m_File.AppendString(FX_BSTRC(" ")) < 0) {
1829             return -1;
1830           }
1831           if (m_File.AppendDWord(pValue->GetObjNum()) < 0) {
1832             return -1;
1833           }
1834           if (m_File.AppendString(FX_BSTRC(" 0 R ")) < 0) {
1835             return -1;
1836           }
1837         } else {
1838           FX_FILESIZE offset = 0;
1839           if (PDF_CreatorAppendObject(pValue, &m_File, offset) < 0) {
1840             return -1;
1841           }
1842         }
1843       }
1844     } else {
1845       if (m_File.AppendString(FX_BSTRC("\r\n/Root ")) < 0) {
1846         return -1;
1847       }
1848       if (m_File.AppendDWord(m_pDocument->m_pRootDict->GetObjNum()) < 0) {
1849         return -1;
1850       }
1851       if (m_File.AppendString(FX_BSTRC(" 0 R\r\n")) < 0) {
1852         return -1;
1853       }
1854       if (m_pDocument->m_pInfoDict) {
1855         if (m_File.AppendString(FX_BSTRC("/Info ")) < 0) {
1856           return -1;
1857         }
1858         if (m_File.AppendDWord(m_pDocument->m_pInfoDict->GetObjNum()) < 0) {
1859           return -1;
1860         }
1861         if (m_File.AppendString(FX_BSTRC(" 0 R\r\n")) < 0) {
1862           return -1;
1863         }
1864       }
1865     }
1866     if (m_pEncryptDict) {
1867       if (m_File.AppendString(FX_BSTRC("/Encrypt")) < 0) {
1868         return -1;
1869       }
1870       FX_DWORD dwObjNum = m_pEncryptDict->GetObjNum();
1871       if (dwObjNum == 0) {
1872         dwObjNum = m_pDocument->GetLastObjNum() + 1;
1873       }
1874       if (m_File.AppendString(FX_BSTRC(" ")) < 0) {
1875         return -1;
1876       }
1877       if (m_File.AppendDWord(dwObjNum) < 0) {
1878         return -1;
1879       }
1880       if (m_File.AppendString(FX_BSTRC(" 0 R ")) < 0) {
1881         return -1;
1882       }
1883     }
1884     if (m_File.AppendString(FX_BSTRC("/Size ")) < 0) {
1885       return -1;
1886     }
1887     if (m_File.AppendDWord(m_dwLastObjNum + (bXRefStream ? 2 : 1)) < 0) {
1888       return -1;
1889     }
1890     if ((m_dwFlags & FPDFCREATE_INCREMENTAL) != 0) {
1891       FX_FILESIZE prev = m_pParser->GetLastXRefOffset();
1892       if (prev) {
1893         if (m_File.AppendString(FX_BSTRC("/Prev ")) < 0) {
1894           return -1;
1895         }
1896         FX_CHAR offset_buf[20];
1897         FXSYS_memset(offset_buf, 0, sizeof(offset_buf));
1898         FXSYS_i64toa(prev, offset_buf, 10);
1899         if (m_File.AppendBlock(offset_buf, FXSYS_strlen(offset_buf)) < 0) {
1900           return -1;
1901         }
1902       }
1903     }
1904     if (m_pIDArray) {
1905       if (m_File.AppendString((FX_BSTRC("/ID"))) < 0) {
1906         return -1;
1907       }
1908       FX_FILESIZE offset = 0;
1909       if (PDF_CreatorAppendObject(m_pIDArray, &m_File, offset) < 0) {
1910         return -1;
1911       }
1912     }
1913     if (!bXRefStream) {
1914       if (m_File.AppendString(FX_BSTRC(">>")) < 0) {
1915         return -1;
1916       }
1917     } else {
1918       if (m_File.AppendString(FX_BSTRC("/W[0 4 1]/Index[")) < 0) {
1919         return -1;
1920       }
1921       if ((m_dwFlags & FPDFCREATE_INCREMENTAL) != 0 && m_pParser &&
1922           m_pParser->GetLastXRefOffset() == 0) {
1923         FX_DWORD i = 0;
1924         for (i = 0; i < m_dwLastObjNum; i++) {
1925           if (!m_ObjectOffset.GetPtrAt(i)) {
1926             continue;
1927           }
1928           if (m_File.AppendDWord(i) < 0) {
1929             return -1;
1930           }
1931           if (m_File.AppendString(FX_BSTRC(" 1 ")) < 0) {
1932             return -1;
1933           }
1934         }
1935         if (m_File.AppendString(FX_BSTRC("]/Length ")) < 0) {
1936           return -1;
1937         }
1938         if (m_File.AppendDWord(m_dwLastObjNum * 5) < 0) {
1939           return -1;
1940         }
1941         if (m_File.AppendString(FX_BSTRC(">>stream\r\n")) < 0) {
1942           return -1;
1943         }
1944         for (i = 0; i < m_dwLastObjNum; i++) {
1945           FX_FILESIZE* offset = m_ObjectOffset.GetPtrAt(i);
1946           if (!offset) {
1947             continue;
1948           }
1949           _OutPutIndex(&m_File, *offset);
1950         }
1951       } else {
1952         int count = m_NewObjNumArray.GetSize();
1953         int32_t i = 0;
1954         for (i = 0; i < count; i++) {
1955           FX_DWORD objnum = m_NewObjNumArray.ElementAt(i);
1956           if (m_File.AppendDWord(objnum) < 0) {
1957             return -1;
1958           }
1959           if (m_File.AppendString(FX_BSTRC(" 1 ")) < 0) {
1960             return -1;
1961           }
1962         }
1963         if (m_File.AppendString(FX_BSTRC("]/Length ")) < 0) {
1964           return -1;
1965         }
1966         if (m_File.AppendDWord(count * 5) < 0) {
1967           return -1;
1968         }
1969         if (m_File.AppendString(FX_BSTRC(">>stream\r\n")) < 0) {
1970           return -1;
1971         }
1972         for (i = 0; i < count; i++) {
1973           FX_DWORD objnum = m_NewObjNumArray.ElementAt(i);
1974           FX_FILESIZE offset = m_ObjectOffset[objnum];
1975           _OutPutIndex(&m_File, offset);
1976         }
1977       }
1978       if (m_File.AppendString(FX_BSTRC("\r\nendstream")) < 0) {
1979         return -1;
1980       }
1981     }
1982   }
1983   if (m_File.AppendString(FX_BSTRC("\r\nstartxref\r\n")) < 0) {
1984     return -1;
1985   }
1986   FX_CHAR offset_buf[20];
1987   FXSYS_memset(offset_buf, 0, sizeof(offset_buf));
1988   FXSYS_i64toa(m_XrefStart, offset_buf, 10);
1989   if (m_File.AppendBlock(offset_buf, FXSYS_strlen(offset_buf)) < 0) {
1990     return -1;
1991   }
1992   if (m_File.AppendString(FX_BSTRC("\r\n%%EOF\r\n")) < 0) {
1993     return -1;
1994   }
1995   m_File.Flush();
1996   return m_iStage = 100;
1997 }
1998 void CPDF_Creator::Clear() {
1999   delete m_pXRefStream;
2000   m_pXRefStream = NULL;
2001   m_File.Clear();
2002   m_NewObjNumArray.RemoveAll();
2003   if (m_pIDArray) {
2004     m_pIDArray->Release();
2005     m_pIDArray = NULL;
2006   }
2007 }
2008 FX_BOOL CPDF_Creator::Create(IFX_StreamWrite* pFile, FX_DWORD flags) {
2009   if (!pFile) {
2010     return FALSE;
2011   }
2012   if (!m_File.AttachFile(pFile, FALSE)) {
2013     return FALSE;
2014   }
2015   return Create(flags);
2016 }
2017 FX_BOOL CPDF_Creator::Create(FX_DWORD flags) {
2018   m_dwFlags = flags;
2019   m_iStage = 0;
2020   m_Offset = 0;
2021   m_dwLastObjNum = m_pDocument->GetLastObjNum();
2022   m_ObjectOffset.Clear();
2023   m_ObjectSize.Clear();
2024   m_NewObjNumArray.RemoveAll();
2025   InitID();
2026   if (flags & FPDFCREATE_PROGRESSIVE) {
2027     return TRUE;
2028   }
2029   return Continue(NULL) > -1;
2030 }
2031 void CPDF_Creator::InitID(FX_BOOL bDefault) {
2032   CPDF_Array* pOldIDArray = m_pParser ? m_pParser->GetIDArray() : NULL;
2033   FX_BOOL bNewId = !m_pIDArray;
2034   if (!m_pIDArray) {
2035     FX_DWORD* pBuffer = NULL;
2036     m_pIDArray = CPDF_Array::Create();
2037     CPDF_Object* pID1 = pOldIDArray ? pOldIDArray->GetElement(0) : NULL;
2038     if (pID1) {
2039       m_pIDArray->Add(pID1->Clone());
2040     } else {
2041       pBuffer = FX_Alloc(FX_DWORD, 4);
2042       PDF_GenerateFileID((FX_DWORD)(uintptr_t) this, m_dwLastObjNum, pBuffer);
2043       CFX_ByteStringC bsBuffer((const uint8_t*)pBuffer, 4 * sizeof(FX_DWORD));
2044       m_pIDArray->Add(CPDF_String::Create(bsBuffer, TRUE), m_pDocument);
2045     }
2046     FX_Free(pBuffer);
2047   }
2048   if (!bDefault) {
2049     return;
2050   }
2051   if (pOldIDArray) {
2052     CPDF_Object* pID2 = pOldIDArray->GetElement(1);
2053     if ((m_dwFlags & FPDFCREATE_INCREMENTAL) && m_pEncryptDict && pID2) {
2054       m_pIDArray->Add(pID2->Clone());
2055       return;
2056     }
2057     FX_DWORD* pBuffer = FX_Alloc(FX_DWORD, 4);
2058     PDF_GenerateFileID((FX_DWORD)(uintptr_t) this, m_dwLastObjNum, pBuffer);
2059     CFX_ByteStringC bsBuffer((const uint8_t*)pBuffer, 4 * sizeof(FX_DWORD));
2060     m_pIDArray->Add(CPDF_String::Create(bsBuffer, TRUE), m_pDocument);
2061     FX_Free(pBuffer);
2062     return;
2063   }
2064   m_pIDArray->Add(m_pIDArray->GetElement(0)->Clone());
2065   if (m_pEncryptDict && !pOldIDArray && m_pParser && bNewId) {
2066     if (m_pEncryptDict->GetString(FX_BSTRC("Filter")) == FX_BSTRC("Standard")) {
2067       CPDF_StandardSecurityHandler handler;
2068       CFX_ByteString user_pass = m_pParser->GetPassword();
2069       FX_DWORD flag = PDF_ENCRYPT_CONTENT;
2070       handler.OnCreate(m_pEncryptDict, m_pIDArray, (const uint8_t*)user_pass,
2071                        user_pass.GetLength(), flag);
2072       if (m_bNewCrypto) {
2073         delete m_pCryptoHandler;
2074       }
2075       m_pCryptoHandler = new CPDF_StandardCryptoHandler;
2076       m_pCryptoHandler->Init(m_pEncryptDict, &handler);
2077       m_bNewCrypto = TRUE;
2078       m_bSecurityChanged = TRUE;
2079     }
2080   }
2081 }
2082 int32_t CPDF_Creator::Continue(IFX_Pause* pPause) {
2083   if (m_iStage < 0) {
2084     return m_iStage;
2085   }
2086   int32_t iRet = 0;
2087   while (m_iStage < 100) {
2088     if (m_iStage < 20) {
2089       iRet = WriteDoc_Stage1(pPause);
2090     } else if (m_iStage < 30) {
2091       iRet = WriteDoc_Stage2(pPause);
2092     } else if (m_iStage < 90) {
2093       iRet = WriteDoc_Stage3(pPause);
2094     } else {
2095       iRet = WriteDoc_Stage4(pPause);
2096     }
2097     if (iRet < m_iStage) {
2098       break;
2099     }
2100   }
2101   if (iRet < 1 || m_iStage == 100) {
2102     m_iStage = -1;
2103     Clear();
2104     return iRet > 99 ? 0 : (iRet < 1 ? -1 : iRet);
2105   }
2106   return m_iStage;
2107 }
2108 FX_BOOL CPDF_Creator::SetFileVersion(int32_t fileVersion) {
2109   if (fileVersion < 10 || fileVersion > 17) {
2110     return FALSE;
2111   }
2112   m_FileVersion = fileVersion;
2113   return TRUE;
2114 }
2115 void CPDF_Creator::RemoveSecurity() {
2116   ResetStandardSecurity();
2117   m_bSecurityChanged = TRUE;
2118   m_pEncryptDict = NULL;
2119   m_pCryptoHandler = NULL;
2120 }
2121 void CPDF_Creator::ResetStandardSecurity() {
2122   if (m_bStandardSecurity || m_bNewCrypto) {
2123     delete m_pCryptoHandler;
2124     m_pCryptoHandler = NULL;
2125   }
2126   m_bNewCrypto = FALSE;
2127   if (!m_bStandardSecurity) {
2128     return;
2129   }
2130   if (m_pEncryptDict) {
2131     m_pEncryptDict->Release();
2132     m_pEncryptDict = NULL;
2133   }
2134   m_bStandardSecurity = FALSE;
2135 }