Use stdint.h types throughout PDFium.
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_objects.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../../include/fpdfapi/fpdf_parser.h"
8 #include "../../../include/fxcrt/fx_string.h"
9
10 //static
11 int CPDF_Object::s_nCurRefDepth = 0;
12
13 void CPDF_Object::Release()
14 {
15     if (m_ObjNum) {
16         return;
17     }
18     Destroy();
19 }
20 void 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 }
42 CFX_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 }
67 CFX_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 }
88 FX_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 }
107 FX_FLOAT CPDF_Object::GetNumber16() const
108 {
109     return GetNumber();
110 }
111 int 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 }
138 CPDF_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 }
159 CPDF_Array* CPDF_Object::GetArray() const
160 {
161     if (m_Type == PDFOBJ_ARRAY)
162         return (CPDF_Array*)this;
163     else
164         return NULL;
165 }
166 void 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 }
185 int 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 }
193 FX_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 }
231 CPDF_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 }
242 CPDF_Object* CPDF_Object::Clone(FX_BOOL bDirect) const
243 {
244     CFX_MapPtrToPtr visited;
245     return CloneInternal(bDirect, &visited);
246 }
247 CPDF_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*)(uintptr_t)obj_num)) {
299                     visited->SetAt((void*)(uintptr_t)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 }
313 CPDF_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 }
320 CFX_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 }
334 void 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
344 CPDF_Number::CPDF_Number(int value)
345     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(TRUE), m_Integer(value) {
346 }
347
348 CPDF_Number::CPDF_Number(FX_FLOAT value)
349     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(FALSE), m_Float(value) {
350 }
351
352 CPDF_Number::CPDF_Number(FX_BOOL bInteger, void* pData)
353     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(bInteger), m_Integer(*(int*)pData) {
354 }
355
356 CPDF_Number::CPDF_Number(FX_BSTR str) : CPDF_Object(PDFOBJ_NUMBER) {
357     FX_atonum(str, m_bInteger, &m_Integer);
358 }
359
360 void CPDF_Number::SetString(FX_BSTR str)
361 {
362     FX_atonum(str, m_bInteger, &m_Integer);
363 }
364 FX_BOOL CPDF_Number::Identical(CPDF_Number* pOther) const
365 {
366     return m_bInteger == pOther->m_bInteger && m_Integer == pOther->m_Integer;
367 }
368 CFX_ByteString CPDF_Number::GetString() const
369 {
370     return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED) : CFX_ByteString::FormatFloat(m_Float);
371 }
372 void CPDF_Number::SetNumber(FX_FLOAT value)
373 {
374     m_bInteger = FALSE;
375     m_Float = value;
376 }
377 CPDF_String::CPDF_String(const CFX_WideString& str) : CPDF_Object(PDFOBJ_STRING), m_bHex(FALSE) {
378     m_String = PDF_EncodeText(str);
379 }
380 CPDF_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 }
389 CFX_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 }
401 CFX_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 }
410 CPDF_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 }
417 CPDF_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 }
424 CFX_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 }
433 CFX_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 }
442 int 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 }
450 FX_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 }
458 CPDF_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 }
470 CPDF_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 }
478 CPDF_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 }
486 void 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 }
497 void 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 }
513 void 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 }
522 void 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 }
531 void CPDF_Array::AddName(const CFX_ByteString& str)
532 {
533     ASSERT(m_Type == PDFOBJ_ARRAY);
534     Add(new CPDF_Name(str));
535 }
536 void CPDF_Array::AddString(const CFX_ByteString& str)
537 {
538     ASSERT(m_Type == PDFOBJ_ARRAY);
539     Add(new CPDF_String(str));
540 }
541 void CPDF_Array::AddInteger(int i)
542 {
543     ASSERT(m_Type == PDFOBJ_ARRAY);
544     Add(new CPDF_Number(i));
545 }
546 void 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 }
553 void CPDF_Array::AddReference(CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
554 {
555     ASSERT(m_Type == PDFOBJ_ARRAY);
556     Add(new CPDF_Reference(pDoc, objnum));
557 }
558 FX_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 }
569 CPDF_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 }
578 FX_POSITION CPDF_Dictionary::GetStartPos() const
579 {
580     return m_Map.GetStartPosition();
581 }
582 CPDF_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 }
591 CPDF_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 }
597 CPDF_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 }
603 CFX_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 }
612 CFX_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 }
621 CFX_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 }
637 CFX_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 }
646 CFX_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 }
655 int 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 }
664 int 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 }
673 FX_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 }
682 FX_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 }
691 CPDF_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 }
703 CPDF_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 }
711 CPDF_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 }
719 CFX_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 }
728 CFX_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 }
737 FX_BOOL CPDF_Dictionary::KeyExist(FX_BSTR key) const
738 {
739     FX_LPVOID value;
740     return m_Map.Lookup(key, value);
741 }
742 void 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 }
762 void CPDF_Dictionary::AddValue(FX_BSTR key, CPDF_Object* pObj)
763 {
764     ASSERT(m_Type == PDFOBJ_DICTIONARY);
765     m_Map.AddValue(key, pObj);
766 }
767 void 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 }
778 void 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 }
789 FX_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 }
810 void CPDF_Dictionary::SetAtInteger(FX_BSTR key, int i)
811 {
812     SetAt(key, new CPDF_Number(i));
813 }
814 void CPDF_Dictionary::SetAtName(FX_BSTR key, const CFX_ByteString& name)
815 {
816     SetAt(key, new CPDF_Name(name));
817 }
818 void CPDF_Dictionary::SetAtString(FX_BSTR key, const CFX_ByteString& str)
819 {
820     SetAt(key, new CPDF_String(str));
821 }
822 void CPDF_Dictionary::SetAtReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
823 {
824     SetAt(key, new CPDF_Reference(pDoc, objnum));
825 }
826 void CPDF_Dictionary::AddReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
827 {
828     AddValue(key, new CPDF_Reference(pDoc, objnum));
829 }
830 void 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 }
836 void CPDF_Dictionary::SetAtBoolean(FX_BSTR key, FX_BOOL bValue)
837 {
838     SetAt(key, new CPDF_Boolean(bValue));
839 }
840 void 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 }
849 void 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 }
860 CPDF_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 }
868 CPDF_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 }
877 void 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 }
895 void 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(uint8_t, 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 }
908 void 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(uint8_t, 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 }
936 FX_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 }
946 void 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 }
955 FX_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         uint8_t srcBuf[1024];
974         uint8_t 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         uint8_t 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 }
1026 CPDF_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(uint8_t, 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 }
1057 extern 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);
1060 CPDF_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 }
1069 void 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(uint8_t, 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 }
1130 CPDF_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 }
1139 FX_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 }
1149 FX_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 }
1159 FX_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(uint8_t, m_dwSize);
1168     FXSYS_memcpy32(p, m_pData, m_dwSize);
1169     return p;
1170 }
1171 void CPDF_Reference::SetRef(CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
1172 {
1173     m_pObjList = pDoc;
1174     m_RefObjNum = objnum;
1175 }
1176 CPDF_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 }
1186 CPDF_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 }
1195 CPDF_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)(uintptr_t)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)(uintptr_t)objnum, value)) {
1221         if (value) {
1222             ((CPDF_Object *)value)->Destroy();
1223         }
1224     }
1225     m_IndirectObjs.SetAt((FX_LPVOID)(uintptr_t)objnum, pObj);
1226     return pObj;
1227 }
1228 int CPDF_IndirectObjects::GetIndirectType(FX_DWORD objnum)
1229 {
1230     FX_LPVOID value;
1231     if (m_IndirectObjs.Lookup((FX_LPVOID)(uintptr_t)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)(uintptr_t)m_pParser->ParseIndirectObject(this, objnum, &context);
1239     }
1240     return 0;
1241 }
1242 FX_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)(uintptr_t)m_LastObjNum, pObj);
1249     pObj->m_ObjNum = m_LastObjNum;
1250     return m_LastObjNum;
1251 }
1252 void CPDF_IndirectObjects::ReleaseIndirectObject(FX_DWORD objnum)
1253 {
1254     FX_LPVOID value;
1255     if (!m_IndirectObjs.Lookup((FX_LPVOID)(uintptr_t)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)(uintptr_t)objnum);
1263 }
1264 void 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)(uintptr_t)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)(uintptr_t)objnum, pObj);
1281     if (m_LastObjNum < objnum) {
1282         m_LastObjNum = objnum;
1283     }
1284 }
1285 FX_DWORD CPDF_IndirectObjects::GetLastObjNum() const
1286 {
1287     return m_LastObjNum;
1288 }