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_parser.h"
8void CPDF_Object::Release()
9{
10    if (this == NULL) {
11        return;
12    }
13    if (m_ObjNum) {
14        return;
15    }
16    Destroy();
17}
18void CPDF_Object::Destroy()
19{
20    switch (m_Type) {
21        case PDFOBJ_STRING:
22            delete (CPDF_String*)this;
23            break;
24        case PDFOBJ_NAME:
25            delete (CPDF_Name*)this;
26            break;
27        case PDFOBJ_ARRAY:
28            delete (CPDF_Array*)this;
29            break;
30        case PDFOBJ_DICTIONARY:
31            delete (CPDF_Dictionary*)this;
32            break;
33        case PDFOBJ_STREAM:
34            delete (CPDF_Stream*)this;
35            break;
36        default:
37            delete this;
38    }
39}
40CFX_ByteString CPDF_Object::GetString() const
41{
42    if (this == NULL) {
43        return CFX_ByteString();
44    }
45    switch (m_Type) {
46        case PDFOBJ_BOOLEAN:
47            return ((CPDF_Boolean*)this)->m_bValue ? "true" : "false";
48        case PDFOBJ_NUMBER:
49            return ((CPDF_Number*)this)->GetString();
50        case PDFOBJ_STRING:
51            return ((CPDF_String*)this)->m_String;
52        case PDFOBJ_NAME:
53            return ((CPDF_Name*)this)->m_Name;
54        case PDFOBJ_REFERENCE: {
55                CPDF_Reference* pRef = (CPDF_Reference*)(FX_LPVOID)this;
56                if (pRef->m_pObjList == NULL) {
57                    break;
58                }
59                CPDF_Object* pObj = pRef->m_pObjList->GetIndirectObject(pRef->m_RefObjNum);
60                if (pObj == NULL) {
61                    return CFX_ByteString();
62                }
63                return pObj->GetString();
64            }
65    }
66    return CFX_ByteString();
67}
68CFX_ByteStringC CPDF_Object::GetConstString() const
69{
70    if (this == NULL) {
71        return CFX_ByteStringC();
72    }
73    switch (m_Type) {
74        case PDFOBJ_STRING:
75            return CFX_ByteStringC((FX_LPCBYTE)((CPDF_String*)this)->m_String, ((CPDF_String*)this)->m_String.GetLength());
76        case PDFOBJ_NAME:
77            return CFX_ByteStringC((FX_LPCBYTE)((CPDF_Name*)this)->m_Name, ((CPDF_Name*)this)->m_Name.GetLength());
78        case PDFOBJ_REFERENCE: {
79                CPDF_Reference* pRef = (CPDF_Reference*)(FX_LPVOID)this;
80                if (pRef->m_pObjList == NULL) {
81                    break;
82                }
83                CPDF_Object* pObj = pRef->m_pObjList->GetIndirectObject(pRef->m_RefObjNum);
84                if (pObj == NULL) {
85                    return CFX_ByteStringC();
86                }
87                return pObj->GetConstString();
88            }
89    }
90    return CFX_ByteStringC();
91}
92FX_FLOAT CPDF_Object::GetNumber() const
93{
94    if (this == NULL) {
95        return 0;
96    }
97    switch (m_Type) {
98        case PDFOBJ_NUMBER:
99            return ((CPDF_Number*)this)->GetNumber();
100        case PDFOBJ_REFERENCE: {
101                CPDF_Reference* pRef = (CPDF_Reference*)(FX_LPVOID)this;
102                if (pRef->m_pObjList == NULL) {
103                    break;
104                }
105                CPDF_Object* pObj = pRef->m_pObjList->GetIndirectObject(pRef->m_RefObjNum);
106                if (pObj == NULL) {
107                    return 0;
108                }
109                return pObj->GetNumber();
110            }
111    }
112    return 0;
113}
114FX_FLOAT CPDF_Object::GetNumber16() const
115{
116    return GetNumber();
117}
118int CPDF_Object::GetInteger() const
119{
120    if (this == NULL) {
121        return 0;
122    }
123    switch (m_Type) {
124        case PDFOBJ_BOOLEAN:
125            return ((CPDF_Boolean*)this)->m_bValue;
126        case PDFOBJ_NUMBER:
127            return ((CPDF_Number*)this)->GetInteger();
128        case PDFOBJ_REFERENCE: {
129                CPDF_Reference* pRef = (CPDF_Reference*)(FX_LPVOID)this;
130                PARSE_CONTEXT context;
131                FXSYS_memset32(&context, 0, sizeof(PARSE_CONTEXT));
132                if (pRef->m_pObjList == NULL) {
133                    return 0;
134                }
135                CPDF_Object* pObj = pRef->m_pObjList->GetIndirectObject(pRef->m_RefObjNum, &context);
136                if (pObj == NULL) {
137                    return 0;
138                }
139                return pObj->GetInteger();
140            }
141    }
142    return 0;
143}
144CPDF_Dictionary* CPDF_Object::GetDict() const
145{
146    if (this == NULL) {
147        return NULL;
148    }
149    switch (m_Type) {
150        case PDFOBJ_DICTIONARY:
151            return (CPDF_Dictionary*)this;
152        case PDFOBJ_STREAM:
153            return ((CPDF_Stream*)this)->GetDict();
154        case PDFOBJ_REFERENCE: {
155                CPDF_Reference* pRef = (CPDF_Reference*)this;
156                if (pRef->m_pObjList == NULL) {
157                    break;
158                }
159                CPDF_Object* pObj = pRef->m_pObjList->GetIndirectObject(pRef->m_RefObjNum);
160                if (pObj == NULL) {
161                    return NULL;
162                }
163                return pObj->GetDict();
164            }
165    }
166    return NULL;
167}
168CPDF_Array* CPDF_Object::GetArray() const
169{
170    if (this == NULL) {
171        return NULL;
172    }
173    if (m_Type == PDFOBJ_ARRAY) {
174        return (CPDF_Array*)this;
175    }
176    return NULL;
177}
178void CPDF_Object::SetString(const CFX_ByteString& str)
179{
180    ASSERT(this != NULL);
181    switch (m_Type) {
182        case PDFOBJ_BOOLEAN:
183            ((CPDF_Boolean*)this)->m_bValue = str == FX_BSTRC("true") ? 1 : 0;
184            return;
185        case PDFOBJ_NUMBER:
186            ((CPDF_Number*)this)->SetString(str);
187            return;
188        case PDFOBJ_STRING:
189            ((CPDF_String*)this)->m_String = str;
190            return;
191        case PDFOBJ_NAME:
192            ((CPDF_Name*)this)->m_Name = str;
193            return;
194    }
195    ASSERT(FALSE);
196}
197int CPDF_Object::GetDirectType() const
198{
199    if (m_Type != PDFOBJ_REFERENCE) {
200        return m_Type;
201    }
202    CPDF_Reference* pRef = (CPDF_Reference*)this;
203    return pRef->m_pObjList->GetIndirectType(pRef->m_RefObjNum);
204}
205FX_BOOL CPDF_Object::IsIdentical(CPDF_Object* pOther) const
206{
207    if (this == pOther) {
208        return TRUE;
209    }
210    if (this == NULL || pOther == NULL) {
211        return FALSE;
212    }
213    if (pOther->m_Type != m_Type) {
214        if (m_Type == PDFOBJ_REFERENCE) {
215            return GetDirect()->IsIdentical(pOther);
216        } else if (pOther->m_Type == PDFOBJ_REFERENCE) {
217            return IsIdentical(pOther->GetDirect());
218        }
219        return FALSE;
220    }
221    switch (m_Type) {
222        case PDFOBJ_BOOLEAN:
223            return (((CPDF_Boolean*)this)->Identical((CPDF_Boolean*)pOther));
224        case PDFOBJ_NUMBER:
225            return (((CPDF_Number*)this)->Identical((CPDF_Number*)pOther));
226        case PDFOBJ_STRING:
227            return (((CPDF_String*)this)->Identical((CPDF_String*)pOther));
228        case PDFOBJ_NAME:
229            return (((CPDF_Name*)this)->Identical((CPDF_Name*)pOther));
230        case PDFOBJ_ARRAY:
231            return (((CPDF_Array*)this)->Identical((CPDF_Array*)pOther));
232        case PDFOBJ_DICTIONARY:
233            return (((CPDF_Dictionary*)this)->Identical((CPDF_Dictionary*)pOther));
234        case PDFOBJ_NULL:
235            return TRUE;
236        case PDFOBJ_STREAM:
237            return (((CPDF_Stream*)this)->Identical((CPDF_Stream*)pOther));
238        case PDFOBJ_REFERENCE:
239            return (((CPDF_Reference*)this)->Identical((CPDF_Reference*)pOther));
240    }
241    return FALSE;
242}
243CPDF_Object* CPDF_Object::GetDirect() const
244{
245    if (this == NULL) {
246        return NULL;
247    }
248    if (m_Type != PDFOBJ_REFERENCE) {
249        return (CPDF_Object*)this;
250    }
251    CPDF_Reference* pRef = (CPDF_Reference*)(FX_LPVOID)this;
252    if (pRef->m_pObjList == NULL) {
253        return NULL;
254    }
255    return pRef->m_pObjList->GetIndirectObject(pRef->m_RefObjNum);
256}
257CPDF_Object* CPDF_Object::Clone(FX_BOOL bDirect) const
258{
259    CFX_MapPtrToPtr visited;
260    return CloneInternal(bDirect, &visited);
261}
262CPDF_Object* CPDF_Object::CloneInternal(FX_BOOL bDirect, CFX_MapPtrToPtr* visited) const
263{
264    if (this == NULL) {
265        return NULL;
266    }
267    switch (m_Type) {
268        case PDFOBJ_BOOLEAN:
269            return FX_NEW CPDF_Boolean(((CPDF_Boolean*)this)->m_bValue);
270        case PDFOBJ_NUMBER:
271            return FX_NEW CPDF_Number(((CPDF_Number*)this)->m_bInteger, &((CPDF_Number*)this)->m_Integer);
272        case PDFOBJ_STRING:
273            return FX_NEW CPDF_String(((CPDF_String*)this)->m_String, ((CPDF_String*)this)->IsHex());
274        case PDFOBJ_NAME:
275            return FX_NEW CPDF_Name(((CPDF_Name*)this)->m_Name);
276        case PDFOBJ_ARRAY: {
277                CPDF_Array* pCopy = FX_NEW CPDF_Array();
278                CPDF_Array* pThis = (CPDF_Array*)this;
279                int n = pThis->GetCount();
280                for (int i = 0; i < n; i ++) {
281                    CPDF_Object* value = (CPDF_Object*)pThis->m_Objects.GetAt(i);
282                    pCopy->m_Objects.Add(value->CloneInternal(bDirect, visited));
283                }
284                return pCopy;
285            }
286        case PDFOBJ_DICTIONARY: {
287                CPDF_Dictionary* pCopy = FX_NEW CPDF_Dictionary();
288                CPDF_Dictionary* pThis = (CPDF_Dictionary*)this;
289                FX_POSITION pos = pThis->m_Map.GetStartPosition();
290                while (pos) {
291                    CFX_ByteString key;
292                    CPDF_Object* value;
293                    pThis->m_Map.GetNextAssoc(pos, key, (void*&)value);
294                    pCopy->m_Map.SetAt(key, value->CloneInternal(bDirect, visited));
295                }
296                return pCopy;
297            }
298        case PDFOBJ_NULL: {
299                return FX_NEW CPDF_Null;
300            }
301        case PDFOBJ_STREAM: {
302                CPDF_Stream* pThis = (CPDF_Stream*)this;
303                CPDF_StreamAcc acc;
304                acc.LoadAllData(pThis, TRUE);
305                FX_DWORD streamSize = acc.GetSize();
306                CPDF_Stream* pObj = FX_NEW CPDF_Stream(acc.DetachData(), streamSize, (CPDF_Dictionary*)((CPDF_Object*)pThis->GetDict())->CloneInternal(bDirect, visited));
307                return pObj;
308            }
309        case PDFOBJ_REFERENCE: {
310                CPDF_Reference* pRef = (CPDF_Reference*)this;
311                FX_DWORD obj_num = pRef->m_RefObjNum;
312                if (bDirect && !visited->GetValueAt((void*)(FX_UINTPTR)obj_num)) {
313                    visited->SetAt((void*)(FX_UINTPTR)obj_num, (void*)1);
314                    CPDF_Object* ret = pRef->GetDirect()->CloneInternal(TRUE, visited);
315                    return ret;
316                } else {
317                    return FX_NEW CPDF_Reference(pRef->m_pObjList, obj_num);
318                }
319            }
320    }
321    return NULL;
322}
323CPDF_Object* CPDF_Object::CloneRef(CPDF_IndirectObjects* pDoc) const
324{
325    if (this == NULL) {
326        return NULL;
327    }
328    if (m_ObjNum) {
329        return FX_NEW CPDF_Reference(pDoc, m_ObjNum);
330    }
331    return Clone();
332}
333CFX_WideString CPDF_Object::GetUnicodeText(CFX_CharMap* pCharMap) const
334{
335    if (this == NULL) {
336        return CFX_WideString();
337    }
338    if (m_Type == PDFOBJ_STRING) {
339        return PDF_DecodeText(((CPDF_String*)this)->m_String, pCharMap);
340    } else if (m_Type == PDFOBJ_STREAM) {
341        CPDF_StreamAcc stream;
342        stream.LoadAllData((CPDF_Stream*)this, FALSE);
343        CFX_WideString result = PDF_DecodeText(stream.GetData(), stream.GetSize(), pCharMap);
344        return result;
345    } else if (m_Type == PDFOBJ_NAME) {
346        return PDF_DecodeText(((CPDF_Name*)this)->m_Name, pCharMap);
347    }
348    return CFX_WideString();
349}
350void CPDF_Object::SetUnicodeText(FX_LPCWSTR pUnicodes, int len)
351{
352    if (this == NULL) {
353        return;
354    }
355    if (m_Type == PDFOBJ_STRING) {
356        ((CPDF_String*)this)->m_String = PDF_EncodeText(pUnicodes, len);
357    } else if (m_Type == PDFOBJ_STREAM) {
358        CFX_ByteString result = PDF_EncodeText(pUnicodes, len);
359        ((CPDF_Stream*)this)->SetData((FX_LPBYTE)(FX_LPCSTR)result, result.GetLength(), FALSE, FALSE);
360    }
361}
362CPDF_Number::CPDF_Number(int value)
363{
364    m_Type = PDFOBJ_NUMBER;
365    m_bInteger = TRUE;
366    m_Integer = value;
367}
368CPDF_Number::CPDF_Number(FX_FLOAT value)
369{
370    m_Type = PDFOBJ_NUMBER;
371    m_bInteger = FALSE;
372    m_Float = value;
373}
374CPDF_Number::CPDF_Number(FX_BOOL bInteger, void* pData)
375{
376    m_Type = PDFOBJ_NUMBER;
377    m_bInteger = bInteger;
378    m_Integer = *(int*)pData;
379}
380extern void FX_atonum(FX_BSTR, FX_BOOL&, void*);
381CPDF_Number::CPDF_Number(FX_BSTR str)
382{
383    m_Type = PDFOBJ_NUMBER;
384    FX_atonum(str, m_bInteger, &m_Integer);
385}
386void CPDF_Number::SetString(FX_BSTR str)
387{
388    FX_atonum(str, m_bInteger, &m_Integer);
389}
390FX_BOOL CPDF_Number::Identical(CPDF_Number* pOther) const
391{
392    return m_bInteger == pOther->m_bInteger && m_Integer == pOther->m_Integer;
393}
394CFX_ByteString CPDF_Number::GetString() const
395{
396    return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED) : CFX_ByteString::FormatFloat(m_Float);
397}
398void CPDF_Number::SetNumber(FX_FLOAT value)
399{
400    m_bInteger = FALSE;
401    m_Float = value;
402}
403CPDF_String::CPDF_String(const CFX_WideString& str)
404{
405    m_Type = PDFOBJ_STRING;
406    m_String = PDF_EncodeText(str, str.GetLength());
407    m_bHex = FALSE;
408}
409CPDF_Array::~CPDF_Array()
410{
411    int size = m_Objects.GetSize();
412    CPDF_Object** pList = (CPDF_Object**)m_Objects.GetData();
413    for (int i = 0; i < size; i ++) {
414        pList[i]->Release();
415    }
416}
417CFX_FloatRect CPDF_Array::GetRect()
418{
419    CFX_FloatRect rect;
420    if (this == NULL || m_Type != PDFOBJ_ARRAY || m_Objects.GetSize() != 4) {
421        return rect;
422    }
423    rect.left = GetNumber(0);
424    rect.bottom = GetNumber(1);
425    rect.right = GetNumber(2);
426    rect.top = GetNumber(3);
427    return rect;
428}
429CFX_AffineMatrix CPDF_Array::GetMatrix()
430{
431    CFX_AffineMatrix matrix;
432    if (this == NULL || m_Type != PDFOBJ_ARRAY || m_Objects.GetSize() != 6) {
433        return matrix;
434    }
435    matrix.Set(GetNumber(0), GetNumber(1), GetNumber(2), GetNumber(3), GetNumber(4), GetNumber(5));
436    return matrix;
437}
438CPDF_Object* CPDF_Array::GetElement(FX_DWORD i) const
439{
440    if (this == NULL) {
441        return NULL;
442    }
443    if (i >= (FX_DWORD)m_Objects.GetSize()) {
444        return NULL;
445    }
446    return (CPDF_Object*)m_Objects.GetAt(i);
447}
448CPDF_Object* CPDF_Array::GetElementValue(FX_DWORD i) const
449{
450    if (this == NULL) {
451        return NULL;
452    }
453    if (i >= (FX_DWORD)m_Objects.GetSize()) {
454        return NULL;
455    }
456    return ((CPDF_Object*)m_Objects.GetAt(i))->GetDirect();
457}
458CFX_ByteString CPDF_Array::GetString(FX_DWORD i) const
459{
460    if (this && i < (FX_DWORD)m_Objects.GetSize()) {
461        CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
462        return p->GetString();
463    }
464    return CFX_ByteString();
465}
466CFX_ByteStringC CPDF_Array::GetConstString(FX_DWORD i) const
467{
468    if (this && i < (FX_DWORD)m_Objects.GetSize()) {
469        CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
470        return p->GetConstString();
471    }
472    return CFX_ByteStringC();
473}
474int CPDF_Array::GetInteger(FX_DWORD i) const
475{
476    if (this == NULL || i >= (FX_DWORD)m_Objects.GetSize()) {
477        return 0;
478    }
479    CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
480    return p->GetInteger();
481}
482FX_FLOAT CPDF_Array::GetNumber(FX_DWORD i) const
483{
484    if (this == NULL || i >= (FX_DWORD)m_Objects.GetSize()) {
485        return 0;
486    }
487    CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
488    return p->GetNumber();
489}
490CPDF_Dictionary* CPDF_Array::GetDict(FX_DWORD i) const
491{
492    CPDF_Object* p = GetElementValue(i);
493    if (p == NULL) {
494        return NULL;
495    } else if (p->GetType() == PDFOBJ_DICTIONARY) {
496        return (CPDF_Dictionary*)p;
497    } else if (p->GetType() == PDFOBJ_STREAM) {
498        return ((CPDF_Stream*)p)->GetDict();
499    }
500    return NULL;
501}
502CPDF_Stream* CPDF_Array::GetStream(FX_DWORD i) const
503{
504    CPDF_Object* p = GetElementValue(i);
505    if (p == NULL || p->GetType() != PDFOBJ_STREAM) {
506        return NULL;
507    }
508    return (CPDF_Stream*)p;
509}
510CPDF_Array* CPDF_Array::GetArray(FX_DWORD i) const
511{
512    CPDF_Object* p = GetElementValue(i);
513    if (p == NULL || p->GetType() != PDFOBJ_ARRAY) {
514        return NULL;
515    }
516    return (CPDF_Array*)p;
517}
518void CPDF_Array::RemoveAt(FX_DWORD i)
519{
520    ASSERT(this != NULL && m_Type == PDFOBJ_ARRAY);
521    if (i >= (FX_DWORD)m_Objects.GetSize()) {
522        return;
523    }
524    CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
525    p->Release();
526    m_Objects.RemoveAt(i);
527}
528void CPDF_Array::SetAt(FX_DWORD i, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs)
529{
530    ASSERT(this != NULL && m_Type == PDFOBJ_ARRAY);
531    ASSERT(i < (FX_DWORD)m_Objects.GetSize());
532    if (i >= (FX_DWORD)m_Objects.GetSize()) {
533        return;
534    }
535    CPDF_Object* pOld = (CPDF_Object*)m_Objects.GetAt(i);
536    pOld->Release();
537    if (pObj->GetObjNum()) {
538        ASSERT(pObjs != NULL);
539        pObj = CPDF_Reference::Create(pObjs, pObj->GetObjNum());
540    }
541    m_Objects.SetAt(i, pObj);
542}
543void CPDF_Array::InsertAt(FX_DWORD index, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs)
544{
545    ASSERT(pObj != NULL);
546    if (pObj->GetObjNum()) {
547        ASSERT(pObjs != NULL);
548        pObj = CPDF_Reference::Create(pObjs, pObj->GetObjNum());
549    }
550    m_Objects.InsertAt(index, pObj);
551}
552void CPDF_Array::Add(CPDF_Object* pObj, CPDF_IndirectObjects* pObjs)
553{
554    ASSERT(pObj != NULL);
555    if (pObj->GetObjNum()) {
556        ASSERT(pObjs != NULL);
557        pObj = CPDF_Reference::Create(pObjs, pObj->GetObjNum());
558    }
559    m_Objects.Add(pObj);
560}
561void CPDF_Array::AddName(const CFX_ByteString& str)
562{
563    ASSERT(this != NULL && m_Type == PDFOBJ_ARRAY);
564    Add(FX_NEW CPDF_Name(str));
565}
566void CPDF_Array::AddString(const CFX_ByteString& str)
567{
568    ASSERT(this != NULL && m_Type == PDFOBJ_ARRAY);
569    Add(FX_NEW CPDF_String(str));
570}
571void CPDF_Array::AddInteger(int i)
572{
573    ASSERT(this != NULL && m_Type == PDFOBJ_ARRAY);
574    Add(FX_NEW CPDF_Number(i));
575}
576void CPDF_Array::AddNumber(FX_FLOAT f)
577{
578    ASSERT(this != NULL && m_Type == PDFOBJ_ARRAY);
579    CPDF_Number* pNumber = FX_NEW CPDF_Number;
580    pNumber->SetNumber(f);
581    Add(pNumber);
582}
583void CPDF_Array::AddReference(CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
584{
585    ASSERT(this != NULL && m_Type == PDFOBJ_ARRAY);
586    Add(FX_NEW CPDF_Reference(pDoc, objnum));
587}
588FX_BOOL CPDF_Array::Identical(CPDF_Array* pOther) const
589{
590    if (m_Objects.GetSize() != pOther->m_Objects.GetSize()) {
591        return FALSE;
592    }
593    for (int i = 0; i < m_Objects.GetSize(); i ++)
594        if (!((CPDF_Object*)m_Objects[i])->IsIdentical((CPDF_Object*)pOther->m_Objects[i])) {
595            return FALSE;
596        }
597    return TRUE;
598}
599CPDF_Dictionary::~CPDF_Dictionary()
600{
601    FX_POSITION pos = m_Map.GetStartPosition();
602    while (pos) {
603        FX_LPVOID value = m_Map.GetNextValue(pos);
604        ((CPDF_Object*)value)->Release();
605    }
606}
607FX_POSITION CPDF_Dictionary::GetStartPos() const
608{
609    return m_Map.GetStartPosition();
610}
611CPDF_Object* CPDF_Dictionary::GetNextElement(FX_POSITION& pos, CFX_ByteString& key) const
612{
613    if (pos == NULL) {
614        return NULL;
615    }
616    CPDF_Object* p;
617    m_Map.GetNextAssoc(pos, key, (FX_LPVOID&)p);
618    return p;
619}
620CPDF_Object* CPDF_Dictionary::GetElement(FX_BSTR key) const
621{
622    if (this == NULL) {
623        return NULL;
624    }
625    CPDF_Object* p = NULL;
626    m_Map.Lookup(key, (void*&)p);
627    return p;
628}
629CPDF_Object* CPDF_Dictionary::GetElementValue(FX_BSTR key) const
630{
631    if (this == NULL) {
632        return NULL;
633    }
634    CPDF_Object* p = NULL;
635    m_Map.Lookup(key, (void*&)p);
636    return p->GetDirect();
637}
638CFX_ByteString CPDF_Dictionary::GetString(FX_BSTR key) const
639{
640    if (this) {
641        CPDF_Object* p = NULL;
642        m_Map.Lookup(key, (void*&)p);
643        if (p) {
644            return p->GetString();
645        }
646    }
647    return CFX_ByteString();
648}
649CFX_ByteStringC CPDF_Dictionary::GetConstString(FX_BSTR key) const
650{
651    if (this) {
652        CPDF_Object* p = NULL;
653        m_Map.Lookup(key, (void*&)p);
654        if (p) {
655            return p->GetConstString();
656        }
657    }
658    return CFX_ByteStringC();
659}
660CFX_WideString CPDF_Dictionary::GetUnicodeText(FX_BSTR key, CFX_CharMap* pCharMap) const
661{
662    if (this) {
663        CPDF_Object* p = NULL;
664        m_Map.Lookup(key, (void*&)p);
665        if (p) {
666            if(p->GetType() == PDFOBJ_REFERENCE) {
667                p = ((CPDF_Reference*)p)->GetDirect();
668                return p->GetUnicodeText(pCharMap);
669            } else {
670                return p->GetUnicodeText(pCharMap);
671            }
672        }
673    }
674    return CFX_WideString();
675}
676CFX_ByteString CPDF_Dictionary::GetString(FX_BSTR key, FX_BSTR def) const
677{
678    if (this) {
679        CPDF_Object* p = NULL;
680        m_Map.Lookup(key, (void*&)p);
681        if (p) {
682            return p->GetString();
683        }
684    }
685    return CFX_ByteString(def);
686}
687CFX_ByteStringC CPDF_Dictionary::GetConstString(FX_BSTR key, FX_BSTR def) const
688{
689    if (this) {
690        CPDF_Object* p = NULL;
691        m_Map.Lookup(key, (void*&)p);
692        if (p) {
693            return p->GetConstString();
694        }
695    }
696    return CFX_ByteStringC(def);
697}
698int CPDF_Dictionary::GetInteger(FX_BSTR key) const
699{
700    if (this) {
701        CPDF_Object* p = NULL;
702        m_Map.Lookup(key, (void*&)p);
703        if (p) {
704            return p->GetInteger();
705        }
706    }
707    return 0;
708}
709int CPDF_Dictionary::GetInteger(FX_BSTR key, int def) const
710{
711    if (this) {
712        CPDF_Object* p = NULL;
713        m_Map.Lookup(key, (void*&)p);
714        if (p) {
715            return p->GetInteger();
716        }
717    }
718    return def;
719}
720FX_FLOAT CPDF_Dictionary::GetNumber(FX_BSTR key) const
721{
722    if (this) {
723        CPDF_Object* p = NULL;
724        m_Map.Lookup(key, (void*&)p);
725        if (p) {
726            return p->GetNumber();
727        }
728    }
729    return 0;
730}
731FX_BOOL CPDF_Dictionary::GetBoolean(FX_BSTR key, FX_BOOL bDefault) const
732{
733    if (this) {
734        CPDF_Object* p = NULL;
735        m_Map.Lookup(key, (void*&)p);
736        if (p && p->GetType() == PDFOBJ_BOOLEAN) {
737            return p->GetInteger();
738        }
739    }
740    return bDefault;
741}
742CPDF_Dictionary* CPDF_Dictionary::GetDict(FX_BSTR key) const
743{
744    CPDF_Object* p = GetElementValue(key);
745    if (p == NULL) {
746        return NULL;
747    } else if (p->GetType() == PDFOBJ_DICTIONARY) {
748        return (CPDF_Dictionary*)p;
749    } else if (p->GetType() == PDFOBJ_STREAM) {
750        return ((CPDF_Stream*)p)->GetDict();
751    }
752    return NULL;
753}
754CPDF_Array* CPDF_Dictionary::GetArray(FX_BSTR key) const
755{
756    CPDF_Object* p = GetElementValue(key);
757    if (p == NULL || p->GetType() != PDFOBJ_ARRAY) {
758        return NULL;
759    }
760    return (CPDF_Array*)p;
761}
762CPDF_Stream* CPDF_Dictionary::GetStream(FX_BSTR key) const
763{
764    CPDF_Object* p = GetElementValue(key);
765    if (p == NULL || p->GetType() != PDFOBJ_STREAM) {
766        return NULL;
767    }
768    return (CPDF_Stream*)p;
769}
770CFX_FloatRect CPDF_Dictionary::GetRect(FX_BSTR key) const
771{
772    CFX_FloatRect rect;
773    CPDF_Array* pArray = GetArray(key);
774    if (pArray) {
775        rect = pArray->GetRect();
776    }
777    return rect;
778}
779CFX_AffineMatrix CPDF_Dictionary::GetMatrix(FX_BSTR key) const
780{
781    CFX_AffineMatrix matrix;
782    CPDF_Array* pArray = GetArray(key);
783    if (pArray) {
784        matrix = pArray->GetMatrix();
785    }
786    return matrix;
787}
788FX_BOOL CPDF_Dictionary::KeyExist(FX_BSTR key) const
789{
790    if (this == NULL) {
791        return FALSE;
792    }
793    FX_LPVOID value;
794    return m_Map.Lookup(key, value);
795}
796void CPDF_Dictionary::SetAt(FX_BSTR key, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs)
797{
798    ASSERT(this != NULL && m_Type == PDFOBJ_DICTIONARY);
799    CPDF_Object* p = NULL;
800    m_Map.Lookup(key, (void*&)p);
801    if (p == pObj) {
802        return;
803    }
804    if (p) {
805        p->Release();
806    }
807    if (pObj) {
808        if (pObj->GetObjNum()) {
809            ASSERT(pObjs != NULL);
810            pObj = CPDF_Reference::Create(pObjs, pObj->GetObjNum());
811        }
812        m_Map.SetAt(key, pObj);
813    } else {
814        m_Map.RemoveKey(key);
815    }
816}
817void CPDF_Dictionary::AddValue(FX_BSTR key, CPDF_Object* pObj)
818{
819    ASSERT(this != NULL && m_Type == PDFOBJ_DICTIONARY);
820    m_Map.AddValue(key, pObj);
821}
822void CPDF_Dictionary::RemoveAt(FX_BSTR key)
823{
824    ASSERT(this != NULL && m_Type == PDFOBJ_DICTIONARY);
825    CPDF_Object* p = NULL;
826    m_Map.Lookup(key, (void*&)p);
827    if (p == NULL) {
828        return;
829    }
830    p->Release();
831    m_Map.RemoveKey(key);
832}
833void CPDF_Dictionary::ReplaceKey(FX_BSTR oldkey, FX_BSTR newkey)
834{
835    ASSERT(this != NULL && m_Type == PDFOBJ_DICTIONARY);
836    CPDF_Object* p = NULL;
837    m_Map.Lookup(oldkey, (void*&)p);
838    if (p == NULL) {
839        return;
840    }
841    m_Map.RemoveKey(oldkey);
842    m_Map.SetAt(newkey, p);
843}
844FX_BOOL CPDF_Dictionary::Identical(CPDF_Dictionary* pOther) const
845{
846    if (this == NULL) {
847        if (pOther == NULL) {
848            return TRUE;
849        }
850        return FALSE;
851    }
852    if (pOther == NULL) {
853        return FALSE;
854    }
855    if (m_Map.GetCount() != pOther->m_Map.GetCount()) {
856        return FALSE;
857    }
858    FX_POSITION pos = m_Map.GetStartPosition();
859    while (pos) {
860        CFX_ByteString key;
861        FX_LPVOID value;
862        m_Map.GetNextAssoc(pos, key, value);
863        if (!((CPDF_Object*)value)->IsIdentical(pOther->GetElement(key))) {
864            return FALSE;
865        }
866    }
867    return TRUE;
868}
869void CPDF_Dictionary::SetAtInteger(FX_BSTR key, int i)
870{
871    SetAt(key, FX_NEW CPDF_Number(i));
872}
873void CPDF_Dictionary::SetAtName(FX_BSTR key, const CFX_ByteString& name)
874{
875    SetAt(key, FX_NEW CPDF_Name(name));
876}
877void CPDF_Dictionary::SetAtString(FX_BSTR key, const CFX_ByteString& str)
878{
879    SetAt(key, FX_NEW CPDF_String(str));
880}
881void CPDF_Dictionary::SetAtReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
882{
883    SetAt(key, FX_NEW CPDF_Reference(pDoc, objnum));
884}
885void CPDF_Dictionary::AddReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
886{
887    AddValue(key, FX_NEW CPDF_Reference(pDoc, objnum));
888}
889void CPDF_Dictionary::SetAtNumber(FX_BSTR key, FX_FLOAT f)
890{
891    CPDF_Number* pNumber = FX_NEW CPDF_Number;
892    pNumber->SetNumber(f);
893    SetAt(key, pNumber);
894}
895void CPDF_Dictionary::SetAtBoolean(FX_BSTR key, FX_BOOL bValue)
896{
897    SetAt(key, FX_NEW CPDF_Boolean(bValue));
898}
899void CPDF_Dictionary::SetAtRect(FX_BSTR key, const CFX_FloatRect& rect)
900{
901    CPDF_Array* pArray = FX_NEW CPDF_Array;
902    pArray->AddNumber(rect.left);
903    pArray->AddNumber(rect.bottom);
904    pArray->AddNumber(rect.right);
905    pArray->AddNumber(rect.top);
906    SetAt(key, pArray);
907}
908void CPDF_Dictionary::SetAtMatrix(FX_BSTR key, const CFX_AffineMatrix& matrix)
909{
910    CPDF_Array* pArray = FX_NEW CPDF_Array;
911    pArray->AddNumber16(matrix.a);
912    pArray->AddNumber16(matrix.b);
913    pArray->AddNumber16(matrix.c);
914    pArray->AddNumber16(matrix.d);
915    pArray->AddNumber(matrix.e);
916    pArray->AddNumber(matrix.f);
917    SetAt(key, pArray);
918}
919CPDF_Stream::CPDF_Stream(FX_LPBYTE pData, FX_DWORD size, CPDF_Dictionary* pDict)
920{
921    m_Type = PDFOBJ_STREAM;
922    m_pDict = pDict;
923    m_dwSize = size;
924    m_GenNum = (FX_DWORD) - 1;
925    m_pDataBuf = pData;
926    m_pCryptoHandler = NULL;
927}
928CPDF_Stream::~CPDF_Stream()
929{
930    if (m_GenNum == (FX_DWORD) - 1 && m_pDataBuf != NULL) {
931        FX_Free(m_pDataBuf);
932    }
933    if (m_pDict) {
934        m_pDict->Release();
935    }
936}
937void CPDF_Stream::InitStream(CPDF_Dictionary* pDict)
938{
939    if (pDict) {
940        if (m_pDict) {
941            m_pDict->Release();
942        }
943        m_pDict = pDict;
944    }
945    if (m_GenNum == (FX_DWORD) - 1) {
946        if (m_pDataBuf) {
947            FX_Free(m_pDataBuf);
948        }
949    }
950    m_GenNum = 0;
951    m_pFile = NULL;
952    m_pCryptoHandler = NULL;
953    m_FileOffset = 0;
954}
955void CPDF_Stream::InitStream(FX_LPBYTE pData, FX_DWORD size, CPDF_Dictionary* pDict)
956{
957    InitStream(pDict);
958    m_GenNum = (FX_DWORD) - 1;
959    m_pDataBuf = FX_Alloc(FX_BYTE, size);
960    if (pData) {
961        FXSYS_memcpy32(m_pDataBuf, pData, size);
962    }
963    m_dwSize = size;
964    if (m_pDict) {
965        m_pDict->SetAtInteger(FX_BSTRC("Length"), size);
966    }
967}
968void CPDF_Stream::SetData(FX_LPCBYTE pData, FX_DWORD size, FX_BOOL bCompressed, FX_BOOL bKeepBuf)
969{
970    if (m_GenNum == (FX_DWORD) - 1) {
971        if (m_pDataBuf) {
972            FX_Free(m_pDataBuf);
973        }
974    } else {
975        m_GenNum = (FX_DWORD) - 1;
976        m_pCryptoHandler = NULL;
977    }
978    if (bKeepBuf) {
979        m_pDataBuf = (FX_LPBYTE)pData;
980    } else {
981        m_pDataBuf = FX_Alloc(FX_BYTE, size);
982        if (pData) {
983            FXSYS_memcpy32(m_pDataBuf, pData, size);
984        }
985    }
986    m_dwSize = size;
987    if (m_pDict == NULL) {
988        m_pDict = FX_NEW CPDF_Dictionary;
989    }
990    m_pDict->SetAtInteger(FX_BSTRC("Length"), size);
991    if (!bCompressed) {
992        m_pDict->RemoveAt(FX_BSTRC("Filter"));
993        m_pDict->RemoveAt(FX_BSTRC("DecodeParms"));
994    }
995}
996FX_BOOL CPDF_Stream::ReadRawData(FX_FILESIZE offset, FX_LPBYTE buf, FX_DWORD size) const
997{
998    if ((m_GenNum != (FX_DWORD) - 1) && m_pFile) {
999        return m_pFile->ReadBlock(buf, m_FileOffset + offset, size);
1000    }
1001    if (m_pDataBuf) {
1002        FXSYS_memcpy32(buf, m_pDataBuf + offset, size);
1003    }
1004    return TRUE;
1005}
1006void CPDF_Stream::InitStream(IFX_FileRead *pFile, CPDF_Dictionary* pDict)
1007{
1008    InitStream(pDict);
1009    m_pFile = pFile;
1010    m_dwSize = (FX_DWORD)pFile->GetSize();
1011    if (m_pDict) {
1012        m_pDict->SetAtInteger(FX_BSTRC("Length"), m_dwSize);
1013    }
1014}
1015FX_BOOL CPDF_Stream::Identical(CPDF_Stream* pOther) const
1016{
1017    if (!m_pDict->Identical(pOther->m_pDict)) {
1018        return FALSE;
1019    }
1020    if (m_dwSize != pOther->m_dwSize) {
1021        return FALSE;
1022    }
1023    if (m_GenNum != (FX_DWORD) - 1 && pOther->m_GenNum != (FX_DWORD) - 1) {
1024        if (m_pFile == pOther->m_pFile && m_pFile == NULL) {
1025            return TRUE;
1026        }
1027        if (!m_pFile || !pOther->m_pFile) {
1028            return FALSE;
1029        }
1030        FX_BYTE srcBuf[1024];
1031        FX_BYTE destBuf[1024];
1032        FX_DWORD size = m_dwSize;
1033        FX_DWORD srcOffset = m_FileOffset;
1034        FX_DWORD destOffset = pOther->m_FileOffset;
1035        if (m_pFile == pOther->m_pFile && srcOffset == destOffset) {
1036            return TRUE;
1037        }
1038        while (size > 0) {
1039            FX_DWORD actualSize = size > 1024 ? 1024 : size;
1040            m_pFile->ReadBlock(srcBuf, srcOffset, actualSize);
1041            pOther->m_pFile->ReadBlock(destBuf, destOffset, actualSize);
1042            if (FXSYS_memcmp32(srcBuf, destBuf, actualSize) != 0) {
1043                return FALSE;
1044            }
1045            size -= actualSize;
1046            srcOffset += actualSize;
1047            destOffset += actualSize;
1048        }
1049        return TRUE;
1050    }
1051    if (m_GenNum != (FX_DWORD) - 1 || pOther->m_GenNum != (FX_DWORD) - 1) {
1052        IFX_FileRead* pFile = NULL;
1053        FX_LPBYTE pBuf = NULL;
1054        FX_DWORD offset = 0;
1055        if (m_GenNum != (FX_DWORD) - 1) {
1056            pFile = m_pFile;
1057            pBuf = pOther->m_pDataBuf;
1058            offset = m_FileOffset;
1059        }
1060        if (pOther->m_GenNum != (FX_DWORD) - 1) {
1061            pFile = pOther->m_pFile;
1062            pBuf = m_pDataBuf;
1063            offset = pOther->m_FileOffset;
1064        }
1065        if (NULL == pBuf) {
1066            return FALSE;
1067        }
1068        FX_BYTE srcBuf[1024];
1069        FX_DWORD size = m_dwSize;
1070        while (size > 0) {
1071            FX_DWORD actualSize = size > 1024 ? 1024 : size;
1072            m_pFile->ReadBlock(srcBuf, offset, actualSize);
1073            if (FXSYS_memcmp32(srcBuf, pBuf, actualSize) != 0) {
1074                return FALSE;
1075            }
1076            pBuf += actualSize;
1077            size -= actualSize;
1078            offset += actualSize;
1079        }
1080        return TRUE;
1081    }
1082    return FXSYS_memcmp32(m_pDataBuf, pOther->m_pDataBuf, m_dwSize) == 0;
1083}
1084CPDF_Stream* CPDF_Stream::Clone(FX_BOOL bDirect, FPDF_LPFCloneStreamCallback lpfCallback, FX_LPVOID pUserData) const
1085{
1086    CPDF_Dictionary *pCloneDict = (CPDF_Dictionary*)m_pDict->Clone(bDirect);
1087    IFX_FileStream *pFS = NULL;
1088    if (lpfCallback) {
1089        pFS = lpfCallback((CPDF_Stream*)this, pUserData);
1090    }
1091    if (!pFS) {
1092        CPDF_StreamAcc acc;
1093        acc.LoadAllData(this, TRUE);
1094        FX_DWORD streamSize = acc.GetSize();
1095        CPDF_Stream* pObj = FX_NEW CPDF_Stream(acc.DetachData(), streamSize, pCloneDict);
1096        return pObj;
1097    }
1098    CPDF_Stream* pObj = FX_NEW CPDF_Stream(NULL, 0, NULL);
1099    CPDF_StreamFilter *pSF = GetStreamFilter(TRUE);
1100    if (pSF) {
1101        FX_LPBYTE pBuf = FX_Alloc(FX_BYTE, 4096);
1102        FX_DWORD dwRead;
1103        do {
1104            dwRead = pSF->ReadBlock(pBuf, 4096);
1105            if (dwRead) {
1106                pFS->WriteBlock(pBuf, dwRead);
1107            }
1108        } while (dwRead == 4096);
1109        pFS->Flush();
1110        FX_Free(pBuf);
1111        delete pSF;
1112    }
1113    pObj->InitStream((IFX_FileRead*)pFS, pCloneDict);
1114    return pObj;
1115}
1116extern FX_BOOL PDF_DataDecode(FX_LPCBYTE src_buf, FX_DWORD src_size, const CPDF_Dictionary* pDict,
1117                              FX_LPBYTE& dest_buf, FX_DWORD& dest_size, CFX_ByteString& ImageEncoding,
1118                              CPDF_Dictionary*& pImageParms, FX_DWORD estimated_size, FX_BOOL bImageAcc);
1119CPDF_StreamAcc::CPDF_StreamAcc()
1120{
1121    m_bNewBuf = FALSE;
1122    m_pData = NULL;
1123    m_dwSize = 0;
1124    m_pImageParam = NULL;
1125    m_pStream = NULL;
1126    m_pSrcData = NULL;
1127}
1128void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream, FX_BOOL bRawAccess, FX_DWORD estimated_size,
1129                                 FX_BOOL bImageAcc)
1130{
1131    if (pStream == NULL || pStream->GetType() != PDFOBJ_STREAM) {
1132        return;
1133    }
1134    m_pStream = pStream;
1135    if (pStream->IsMemoryBased() &&
1136            (!pStream->GetDict()->KeyExist(FX_BSTRC("Filter")) || bRawAccess)) {
1137        m_dwSize = pStream->m_dwSize;
1138        m_pData = (FX_LPBYTE)pStream->m_pDataBuf;
1139        return;
1140    }
1141    FX_LPBYTE pSrcData;
1142    FX_DWORD dwSrcSize = pStream->m_dwSize;
1143    if (dwSrcSize == 0) {
1144        return;
1145    }
1146    if (!pStream->IsMemoryBased()) {
1147        pSrcData = m_pSrcData = FX_Alloc(FX_BYTE, dwSrcSize);
1148        if (!pSrcData || !pStream->ReadRawData(0, pSrcData, dwSrcSize)) {
1149            return;
1150        }
1151    } else {
1152        pSrcData = pStream->m_pDataBuf;
1153    }
1154    FX_LPBYTE pDecryptedData;
1155    FX_DWORD dwDecryptedSize;
1156    if (pStream->m_pCryptoHandler) {
1157        CFX_BinaryBuf dest_buf;
1158        dest_buf.EstimateSize(pStream->m_pCryptoHandler->DecryptGetSize(dwSrcSize));
1159        FX_LPVOID context = pStream->m_pCryptoHandler->DecryptStart(pStream->GetObjNum(), pStream->m_GenNum);
1160        pStream->m_pCryptoHandler->DecryptStream(context, pSrcData, dwSrcSize, dest_buf);
1161        pStream->m_pCryptoHandler->DecryptFinish(context, dest_buf);
1162        pDecryptedData = dest_buf.GetBuffer();
1163        dwDecryptedSize = dest_buf.GetSize();
1164        dest_buf.DetachBuffer();
1165    } else {
1166        pDecryptedData = pSrcData;
1167        dwDecryptedSize = dwSrcSize;
1168    }
1169    if (!pStream->GetDict()->KeyExist(FX_BSTRC("Filter")) || bRawAccess) {
1170        m_pData = pDecryptedData;
1171        m_dwSize = dwDecryptedSize;
1172    } else {
1173        FX_BOOL bRet = PDF_DataDecode(pDecryptedData, dwDecryptedSize, m_pStream->GetDict(),
1174                                      m_pData, m_dwSize, m_ImageDecoder, m_pImageParam, estimated_size, bImageAcc);
1175        if (!bRet) {
1176            m_pData = pDecryptedData;
1177            m_dwSize = dwDecryptedSize;
1178        }
1179    }
1180    if (pSrcData != pStream->m_pDataBuf && pSrcData != m_pData) {
1181        FX_Free(pSrcData);
1182    }
1183    if (pDecryptedData != pSrcData && pDecryptedData != m_pData) {
1184        FX_Free(pDecryptedData);
1185    }
1186    m_pSrcData = NULL;
1187    m_bNewBuf = m_pData != pStream->m_pDataBuf;
1188}
1189CPDF_StreamAcc::~CPDF_StreamAcc()
1190{
1191    if (m_bNewBuf && m_pData) {
1192        FX_Free(m_pData);
1193    }
1194    if (m_pSrcData) {
1195        FX_Free(m_pSrcData);
1196    }
1197}
1198FX_LPCBYTE CPDF_StreamAcc::GetData() const
1199{
1200    if (m_bNewBuf) {
1201        return m_pData;
1202    }
1203    if (!m_pStream) {
1204        return NULL;
1205    }
1206    return m_pStream->m_pDataBuf;
1207}
1208FX_DWORD CPDF_StreamAcc::GetSize() const
1209{
1210    if (m_bNewBuf) {
1211        return m_dwSize;
1212    }
1213    if (!m_pStream) {
1214        return 0;
1215    }
1216    return m_pStream->m_dwSize;
1217}
1218FX_LPBYTE CPDF_StreamAcc::DetachData()
1219{
1220    if (m_bNewBuf) {
1221        FX_LPBYTE p = m_pData;
1222        m_pData = NULL;
1223        m_dwSize = 0;
1224        return p;
1225    }
1226    FX_LPBYTE p = FX_Alloc(FX_BYTE, m_dwSize);
1227    if (p == NULL) {
1228        return NULL;
1229    }
1230    FXSYS_memcpy32(p, m_pData, m_dwSize);
1231    return p;
1232}
1233void CPDF_Reference::SetRef(CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
1234{
1235    m_pObjList = pDoc;
1236    m_RefObjNum = objnum;
1237}
1238CPDF_IndirectObjects::CPDF_IndirectObjects(IPDF_DocParser* pParser)
1239{
1240    m_pParser = pParser;
1241    m_IndirectObjs.InitHashTable(1013);
1242    if (pParser) {
1243        m_LastObjNum = m_pParser->GetLastObjNum();
1244    } else {
1245        m_LastObjNum = 0;
1246    }
1247}
1248CPDF_IndirectObjects::~CPDF_IndirectObjects()
1249{
1250    FX_POSITION pos = m_IndirectObjs.GetStartPosition();
1251    while (pos) {
1252        FX_LPVOID key, value;
1253        m_IndirectObjs.GetNextAssoc(pos, key, value);
1254        ((CPDF_Object*)value)->Destroy();
1255    }
1256}
1257CPDF_Object* CPDF_IndirectObjects::GetIndirectObject(FX_DWORD objnum, struct PARSE_CONTEXT* pContext)
1258{
1259    if (objnum == 0) {
1260        return NULL;
1261    }
1262    FX_LPVOID value;
1263    {
1264        if (m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, value)) {
1265            if (((CPDF_Object*)value)->GetObjNum() == -1) {
1266                return NULL;
1267            }
1268            return (CPDF_Object*)value;
1269        }
1270    }
1271    CPDF_Object* pObj = NULL;
1272    if (m_pParser) {
1273        pObj = m_pParser->ParseIndirectObject(this, objnum, pContext);
1274    }
1275    if (pObj == NULL) {
1276        return NULL;
1277    }
1278    pObj->m_ObjNum = objnum;
1279    if (m_LastObjNum < objnum) {
1280        m_LastObjNum = objnum;
1281    }
1282    if (m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, value)) {
1283        if (value) {
1284            ((CPDF_Object *)value)->Destroy();
1285        }
1286    }
1287    m_IndirectObjs.SetAt((FX_LPVOID)(FX_UINTPTR)objnum, pObj);
1288    return pObj;
1289}
1290int CPDF_IndirectObjects::GetIndirectType(FX_DWORD objnum)
1291{
1292    FX_LPVOID value;
1293    if (m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, value)) {
1294        return ((CPDF_Object*)value)->GetType();
1295    }
1296    if (m_pParser) {
1297        PARSE_CONTEXT context;
1298        FXSYS_memset32(&context, 0, sizeof(PARSE_CONTEXT));
1299        context.m_Flags = PDFPARSE_TYPEONLY;
1300        return (int)(FX_UINTPTR)m_pParser->ParseIndirectObject(this, objnum, &context);
1301    }
1302    return 0;
1303}
1304FX_DWORD CPDF_IndirectObjects::AddIndirectObject(CPDF_Object* pObj)
1305{
1306    if (pObj->m_ObjNum) {
1307        return pObj->m_ObjNum;
1308    }
1309    m_LastObjNum ++;
1310    m_IndirectObjs.SetAt((FX_LPVOID)(FX_UINTPTR)m_LastObjNum, pObj);
1311    pObj->m_ObjNum = m_LastObjNum;
1312    return m_LastObjNum;
1313}
1314void CPDF_IndirectObjects::ReleaseIndirectObject(FX_DWORD objnum)
1315{
1316    FX_LPVOID value;
1317    if (!m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, value)) {
1318        return;
1319    }
1320    if (((CPDF_Object*)value)->GetObjNum() == -1) {
1321        return;
1322    }
1323    ((CPDF_Object*)value)->Destroy();
1324    m_IndirectObjs.RemoveKey((FX_LPVOID)(FX_UINTPTR)objnum);
1325}
1326void CPDF_IndirectObjects::InsertIndirectObject(FX_DWORD objnum, CPDF_Object* pObj)
1327{
1328    if (objnum == 0 || pObj == NULL) {
1329        return;
1330    }
1331    FX_LPVOID value;
1332    if (m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, value)) {
1333        ((CPDF_Object*)value)->Destroy();
1334    }
1335    pObj->m_ObjNum = objnum;
1336    m_IndirectObjs.SetAt((FX_LPVOID)(FX_UINTPTR)objnum, pObj);
1337    if (m_LastObjNum < objnum) {
1338        m_LastObjNum = objnum;
1339    }
1340}
1341FX_DWORD CPDF_IndirectObjects::GetLastObjNum() const
1342{
1343    return m_LastObjNum;
1344}
1345