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