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