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