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