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