Revert "FX Bool considered harmful, part 3"
[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*)(void*)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((const uint8_t*)((CPDF_String*)this)->m_String, ((CPDF_String*)this)->m_String.GetLength());
72         case PDFOBJ_NAME:
73             return CFX_ByteStringC((const uint8_t*)((CPDF_Name*)this)->m_Name, ((CPDF_Name*)this)->m_Name.GetLength());
74         case PDFOBJ_REFERENCE: {
75                 CPDF_Reference* pRef = (CPDF_Reference*)(void*)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*)(void*)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*)(void*)this;
124                 PARSE_CONTEXT context;
125                 FXSYS_memset(&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
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         }
205         if (pOther->m_Type == PDFOBJ_REFERENCE) {
206             return IsIdentical(pOther->GetDirect());
207         }
208         return FALSE;
209     }
210     switch (m_Type) {
211         case PDFOBJ_BOOLEAN:
212             return (((CPDF_Boolean*)this)->Identical((CPDF_Boolean*)pOther));
213         case PDFOBJ_NUMBER:
214             return (((CPDF_Number*)this)->Identical((CPDF_Number*)pOther));
215         case PDFOBJ_STRING:
216             return (((CPDF_String*)this)->Identical((CPDF_String*)pOther));
217         case PDFOBJ_NAME:
218             return (((CPDF_Name*)this)->Identical((CPDF_Name*)pOther));
219         case PDFOBJ_ARRAY:
220             return (((CPDF_Array*)this)->Identical((CPDF_Array*)pOther));
221         case PDFOBJ_DICTIONARY:
222             return (((CPDF_Dictionary*)this)->Identical((CPDF_Dictionary*)pOther));
223         case PDFOBJ_NULL:
224             return TRUE;
225         case PDFOBJ_STREAM:
226             return (((CPDF_Stream*)this)->Identical((CPDF_Stream*)pOther));
227         case PDFOBJ_REFERENCE:
228             return (((CPDF_Reference*)this)->Identical((CPDF_Reference*)pOther));
229     }
230     return FALSE;
231 }
232 CPDF_Object* CPDF_Object::GetDirect() const
233 {
234     if (m_Type != PDFOBJ_REFERENCE) {
235         return (CPDF_Object*)this;
236     }
237     CPDF_Reference* pRef = (CPDF_Reference*)(void*)this;
238     if (pRef->m_pObjList == NULL) {
239         return NULL;
240     }
241     return pRef->m_pObjList->GetIndirectObject(pRef->m_RefObjNum);
242 }
243 CPDF_Object* CPDF_Object::Clone(FX_BOOL bDirect) const
244 {
245     CFX_MapPtrToPtr visited;
246     return CloneInternal(bDirect, &visited);
247 }
248 CPDF_Object* CPDF_Object::CloneInternal(FX_BOOL bDirect, CFX_MapPtrToPtr* visited) const
249 {
250     switch (m_Type) {
251         case PDFOBJ_BOOLEAN:
252             return new CPDF_Boolean(((CPDF_Boolean*)this)->m_bValue);
253         case PDFOBJ_NUMBER:
254             return new CPDF_Number(((CPDF_Number*)this)->m_bInteger, &((CPDF_Number*)this)->m_Integer);
255         case PDFOBJ_STRING:
256             return new CPDF_String(((CPDF_String*)this)->m_String, ((CPDF_String*)this)->IsHex());
257         case PDFOBJ_NAME:
258             return new CPDF_Name(((CPDF_Name*)this)->m_Name);
259         case PDFOBJ_ARRAY: {
260                 CPDF_Array* pCopy = new CPDF_Array();
261                 CPDF_Array* pThis = (CPDF_Array*)this;
262                 int n = pThis->GetCount();
263                 for (int i = 0; i < n; i ++) {
264                     CPDF_Object* value = (CPDF_Object*)pThis->m_Objects.GetAt(i);
265                     pCopy->m_Objects.Add(value->CloneInternal(bDirect, visited));
266                 }
267                 return pCopy;
268             }
269         case PDFOBJ_DICTIONARY: {
270                 CPDF_Dictionary* pCopy = new CPDF_Dictionary();
271                 CPDF_Dictionary* pThis = (CPDF_Dictionary*)this;
272                 FX_POSITION pos = pThis->m_Map.GetStartPosition();
273                 while (pos) {
274                     CFX_ByteString key;
275                     CPDF_Object* value;
276                     pThis->m_Map.GetNextAssoc(pos, key, (void*&)value);
277                     pCopy->m_Map.SetAt(key, value->CloneInternal(bDirect, visited));
278                 }
279                 return pCopy;
280             }
281         case PDFOBJ_NULL: {
282                 return new CPDF_Null;
283             }
284         case PDFOBJ_STREAM: {
285                 CPDF_Stream* pThis = (CPDF_Stream*)this;
286                 CPDF_StreamAcc acc;
287                 acc.LoadAllData(pThis, TRUE);
288                 FX_DWORD streamSize = acc.GetSize();
289                 CPDF_Dictionary* pDict = pThis->GetDict();
290                 if (pDict)
291                     pDict = (CPDF_Dictionary*)((CPDF_Object*)pDict)->CloneInternal(bDirect, visited);
292                 return new CPDF_Stream(acc.DetachData(), streamSize, pDict);
293             }
294         case PDFOBJ_REFERENCE: {
295                 CPDF_Reference* pRef = (CPDF_Reference*)this;
296                 FX_DWORD obj_num = pRef->m_RefObjNum;
297                 if (bDirect && !visited->GetValueAt((void*)(uintptr_t)obj_num)) {
298                     visited->SetAt((void*)(uintptr_t)obj_num, (void*)1);
299                     if (!pRef->GetDirect())
300                         return nullptr;
301
302                     return pRef->GetDirect()->CloneInternal(TRUE, visited);
303                 }
304                 return new CPDF_Reference(pRef->m_pObjList, obj_num);
305             }
306     }
307     return NULL;
308 }
309 CPDF_Object* CPDF_Object::CloneRef(CPDF_IndirectObjects* pDoc) const
310 {
311     if (m_ObjNum) {
312         return new CPDF_Reference(pDoc, m_ObjNum);
313     }
314     return Clone();
315 }
316 CFX_WideString CPDF_Object::GetUnicodeText(CFX_CharMap* pCharMap) const
317 {
318     if (m_Type == PDFOBJ_STRING) {
319         return PDF_DecodeText(((CPDF_String*)this)->m_String, pCharMap);
320     }
321     if (m_Type == PDFOBJ_STREAM) {
322         CPDF_StreamAcc stream;
323         stream.LoadAllData((CPDF_Stream*)this, FALSE);
324         CFX_WideString result = PDF_DecodeText(stream.GetData(), stream.GetSize(), pCharMap);
325         return result;
326     }
327     if (m_Type == PDFOBJ_NAME) {
328         return PDF_DecodeText(((CPDF_Name*)this)->m_Name, pCharMap);
329     }
330     return CFX_WideString();
331 }
332 void CPDF_Object::SetUnicodeText(const FX_WCHAR* pUnicodes, int len)
333 {
334     if (m_Type == PDFOBJ_STRING) {
335         ((CPDF_String*)this)->m_String = PDF_EncodeText(pUnicodes, len);
336     } else if (m_Type == PDFOBJ_STREAM) {
337         CFX_ByteString result = PDF_EncodeText(pUnicodes, len);
338         ((CPDF_Stream*)this)->SetData((uint8_t*)result.c_str(), result.GetLength(), FALSE, FALSE);
339     }
340 }
341
342 CPDF_Number::CPDF_Number(int value)
343     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(TRUE), m_Integer(value) {
344 }
345
346 CPDF_Number::CPDF_Number(FX_FLOAT value)
347     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(FALSE), m_Float(value) {
348 }
349
350 CPDF_Number::CPDF_Number(FX_BOOL bInteger, void* pData)
351     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(bInteger), m_Integer(*(int*)pData) {
352 }
353
354 CPDF_Number::CPDF_Number(const CFX_ByteStringC& str) : CPDF_Object(PDFOBJ_NUMBER) {
355     FX_atonum(str, m_bInteger, &m_Integer);
356 }
357
358 void CPDF_Number::SetString(const CFX_ByteStringC& 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) : CPDF_Object(PDFOBJ_STRING), m_bHex(FALSE) {
376     m_String = PDF_EncodeText(str);
377 }
378 CPDF_Array::~CPDF_Array()
379 {
380     int size = m_Objects.GetSize();
381     CPDF_Object** pList = (CPDF_Object**)m_Objects.GetData();
382     for (int i = 0; i < size; i ++) {
383         if (pList[i])
384             pList[i]->Release();
385     }
386 }
387 CFX_FloatRect CPDF_Array::GetRect()
388 {
389     CFX_FloatRect rect;
390     if (m_Type != PDFOBJ_ARRAY || m_Objects.GetSize() != 4) {
391         return rect;
392     }
393     rect.left = GetNumber(0);
394     rect.bottom = GetNumber(1);
395     rect.right = GetNumber(2);
396     rect.top = GetNumber(3);
397     return rect;
398 }
399 CFX_AffineMatrix CPDF_Array::GetMatrix()
400 {
401     CFX_AffineMatrix matrix;
402     if (m_Type != PDFOBJ_ARRAY || m_Objects.GetSize() != 6) {
403         return matrix;
404     }
405     matrix.Set(GetNumber(0), GetNumber(1), GetNumber(2), GetNumber(3), GetNumber(4), GetNumber(5));
406     return matrix;
407 }
408 CPDF_Object* CPDF_Array::GetElement(FX_DWORD i) const
409 {
410     if (i >= (FX_DWORD)m_Objects.GetSize()) {
411         return NULL;
412     }
413     return (CPDF_Object*)m_Objects.GetAt(i);
414 }
415 CPDF_Object* CPDF_Array::GetElementValue(FX_DWORD i) const
416 {
417     if (i >= (FX_DWORD)m_Objects.GetSize()) {
418         return NULL;
419     }
420     return ((CPDF_Object*)m_Objects.GetAt(i))->GetDirect();
421 }
422 CFX_ByteString CPDF_Array::GetString(FX_DWORD i) const
423 {
424     if (i < (FX_DWORD)m_Objects.GetSize()) {
425         CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
426         return p->GetString();
427     }
428     return CFX_ByteString();
429 }
430 CFX_ByteStringC CPDF_Array::GetConstString(FX_DWORD i) const
431 {
432     if (i < (FX_DWORD)m_Objects.GetSize()) {
433         CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
434         return p->GetConstString();
435     }
436     return CFX_ByteStringC();
437 }
438 int CPDF_Array::GetInteger(FX_DWORD i) const
439 {
440     if (i >= (FX_DWORD)m_Objects.GetSize()) {
441         return 0;
442     }
443     CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
444     return p->GetInteger();
445 }
446 FX_FLOAT CPDF_Array::GetNumber(FX_DWORD i) const
447 {
448     if (i >= (FX_DWORD)m_Objects.GetSize()) {
449         return 0;
450     }
451     CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
452     return p->GetNumber();
453 }
454 CPDF_Dictionary* CPDF_Array::GetDict(FX_DWORD i) const
455 {
456     CPDF_Object* p = GetElementValue(i);
457     if (!p) {
458         return NULL;
459     }
460     if (p->GetType() == PDFOBJ_DICTIONARY) {
461         return (CPDF_Dictionary*)p;
462     }
463     if (p->GetType() == PDFOBJ_STREAM) {
464         return ((CPDF_Stream*)p)->GetDict();
465     }
466     return NULL;
467 }
468 CPDF_Stream* CPDF_Array::GetStream(FX_DWORD i) const
469 {
470     CPDF_Object* p = GetElementValue(i);
471     if (p == NULL || p->GetType() != PDFOBJ_STREAM) {
472         return NULL;
473     }
474     return (CPDF_Stream*)p;
475 }
476 CPDF_Array* CPDF_Array::GetArray(FX_DWORD i) const
477 {
478     CPDF_Object* p = GetElementValue(i);
479     if (p == NULL || p->GetType() != PDFOBJ_ARRAY) {
480         return NULL;
481     }
482     return (CPDF_Array*)p;
483 }
484 void CPDF_Array::RemoveAt(FX_DWORD i)
485 {
486     ASSERT(m_Type == PDFOBJ_ARRAY);
487     if (i >= (FX_DWORD)m_Objects.GetSize()) {
488         return;
489     }
490     CPDF_Object* p = (CPDF_Object*)m_Objects.GetAt(i);
491     if (p)
492         p->Release();
493     m_Objects.RemoveAt(i);
494 }
495 void CPDF_Array::SetAt(FX_DWORD i, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs)
496 {
497     ASSERT(m_Type == PDFOBJ_ARRAY);
498     ASSERT(i < (FX_DWORD)m_Objects.GetSize());
499     if (i >= (FX_DWORD)m_Objects.GetSize()) {
500         return;
501     }
502     CPDF_Object* pOld = (CPDF_Object*)m_Objects.GetAt(i);
503     if (pOld)
504         pOld->Release();
505     if (pObj->GetObjNum()) {
506         ASSERT(pObjs != NULL);
507         pObj = new CPDF_Reference(pObjs, pObj->GetObjNum());
508     }
509     m_Objects.SetAt(i, pObj);
510 }
511 void CPDF_Array::InsertAt(FX_DWORD index, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs)
512 {
513     ASSERT(pObj != NULL);
514     if (pObj->GetObjNum()) {
515         ASSERT(pObjs != NULL);
516         pObj = new CPDF_Reference(pObjs, pObj->GetObjNum());
517     }
518     m_Objects.InsertAt(index, pObj);
519 }
520 void CPDF_Array::Add(CPDF_Object* pObj, CPDF_IndirectObjects* pObjs)
521 {
522     ASSERT(pObj != NULL);
523     if (pObj->GetObjNum()) {
524         ASSERT(pObjs != NULL);
525         pObj = new CPDF_Reference(pObjs, pObj->GetObjNum());
526     }
527     m_Objects.Add(pObj);
528 }
529 void CPDF_Array::AddName(const CFX_ByteString& str)
530 {
531     ASSERT(m_Type == PDFOBJ_ARRAY);
532     Add(new CPDF_Name(str));
533 }
534 void CPDF_Array::AddString(const CFX_ByteString& str)
535 {
536     ASSERT(m_Type == PDFOBJ_ARRAY);
537     Add(new CPDF_String(str));
538 }
539 void CPDF_Array::AddInteger(int i)
540 {
541     ASSERT(m_Type == PDFOBJ_ARRAY);
542     Add(new CPDF_Number(i));
543 }
544 void CPDF_Array::AddNumber(FX_FLOAT f)
545 {
546     ASSERT(m_Type == PDFOBJ_ARRAY);
547     CPDF_Number* pNumber = new CPDF_Number;
548     pNumber->SetNumber(f);
549     Add(pNumber);
550 }
551 void CPDF_Array::AddReference(CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
552 {
553     ASSERT(m_Type == PDFOBJ_ARRAY);
554     Add(new CPDF_Reference(pDoc, objnum));
555 }
556 FX_BOOL CPDF_Array::Identical(CPDF_Array* pOther) const
557 {
558     if (m_Objects.GetSize() != pOther->m_Objects.GetSize()) {
559         return FALSE;
560     }
561     for (int i = 0; i < m_Objects.GetSize(); i ++)
562         if (!((CPDF_Object*)m_Objects[i])->IsIdentical((CPDF_Object*)pOther->m_Objects[i])) {
563             return FALSE;
564         }
565     return TRUE;
566 }
567 CPDF_Dictionary::~CPDF_Dictionary()
568 {
569     FX_POSITION pos = m_Map.GetStartPosition();
570     while (pos) {
571         void* value = m_Map.GetNextValue(pos);
572         if (value)
573             ((CPDF_Object*)value)->Release();
574     }
575 }
576 FX_POSITION CPDF_Dictionary::GetStartPos() const
577 {
578     return m_Map.GetStartPosition();
579 }
580 CPDF_Object* CPDF_Dictionary::GetNextElement(FX_POSITION& pos, CFX_ByteString& key) const
581 {
582     if (pos == NULL) {
583         return NULL;
584     }
585     CPDF_Object* p;
586     m_Map.GetNextAssoc(pos, key, (void*&)p);
587     return p;
588 }
589 CPDF_Object* CPDF_Dictionary::GetElement(const CFX_ByteStringC& key) const
590 {
591     CPDF_Object* p = NULL;
592     m_Map.Lookup(key, (void*&)p);
593     return p;
594 }
595 CPDF_Object* CPDF_Dictionary::GetElementValue(const CFX_ByteStringC& key) const
596 {
597     CPDF_Object* p = NULL;
598     m_Map.Lookup(key, (void*&)p);
599     return p ? p->GetDirect() : NULL;
600 }
601 CFX_ByteString CPDF_Dictionary::GetString(const CFX_ByteStringC& key) const
602 {
603     CPDF_Object* p = NULL;
604     m_Map.Lookup(key, (void*&)p);
605     if (p) {
606         return p->GetString();
607     }
608     return CFX_ByteString();
609 }
610 CFX_ByteStringC CPDF_Dictionary::GetConstString(const CFX_ByteStringC& key) const
611 {
612     CPDF_Object* p = NULL;
613     m_Map.Lookup(key, (void*&)p);
614     if (p) {
615         return p->GetConstString();
616     }
617     return CFX_ByteStringC();
618 }
619 CFX_WideString CPDF_Dictionary::GetUnicodeText(const CFX_ByteStringC& key, CFX_CharMap* pCharMap) const
620 {
621     CPDF_Object* p = NULL;
622     m_Map.Lookup(key, (void*&)p);
623     if (p) {
624         if(p->GetType() == PDFOBJ_REFERENCE) {
625             p = ((CPDF_Reference*)p)->GetDirect();
626             if (p) {
627                 return p->GetUnicodeText(pCharMap);
628             }
629         } else {
630             return p->GetUnicodeText(pCharMap);
631         }
632     }
633     return CFX_WideString();
634 }
635 CFX_ByteString CPDF_Dictionary::GetString(const CFX_ByteStringC& key, const CFX_ByteStringC& def) const
636 {
637     CPDF_Object* p = NULL;
638     m_Map.Lookup(key, (void*&)p);
639     if (p) {
640         return p->GetString();
641     }
642     return CFX_ByteString(def);
643 }
644 CFX_ByteStringC CPDF_Dictionary::GetConstString(const CFX_ByteStringC& key, const CFX_ByteStringC& def) const
645 {
646     CPDF_Object* p = NULL;
647     m_Map.Lookup(key, (void*&)p);
648     if (p) {
649         return p->GetConstString();
650     }
651     return CFX_ByteStringC(def);
652 }
653 int CPDF_Dictionary::GetInteger(const CFX_ByteStringC& key) const
654 {
655     CPDF_Object* p = NULL;
656     m_Map.Lookup(key, (void*&)p);
657     if (p) {
658         return p->GetInteger();
659     }
660     return 0;
661 }
662 int CPDF_Dictionary::GetInteger(const CFX_ByteStringC& key, int def) const
663 {
664     CPDF_Object* p = NULL;
665     m_Map.Lookup(key, (void*&)p);
666     if (p) {
667         return p->GetInteger();
668     }
669     return def;
670 }
671 FX_FLOAT CPDF_Dictionary::GetNumber(const CFX_ByteStringC& key) const
672 {
673     CPDF_Object* p = NULL;
674     m_Map.Lookup(key, (void*&)p);
675     if (p) {
676         return p->GetNumber();
677     }
678     return 0;
679 }
680 FX_BOOL CPDF_Dictionary::GetBoolean(const CFX_ByteStringC& key, FX_BOOL bDefault) const
681 {
682     CPDF_Object* p = NULL;
683     m_Map.Lookup(key, (void*&)p);
684     if (p && p->GetType() == PDFOBJ_BOOLEAN) {
685         return p->GetInteger();
686     }
687     return bDefault;
688 }
689 CPDF_Dictionary* CPDF_Dictionary::GetDict(const CFX_ByteStringC& key) const
690 {
691     CPDF_Object* p = GetElementValue(key);
692     if (!p) {
693         return nullptr;
694     }
695     if (p->GetType() == PDFOBJ_DICTIONARY) {
696         return (CPDF_Dictionary*)p;
697     }
698     if (p->GetType() == PDFOBJ_STREAM) {
699         return ((CPDF_Stream*)p)->GetDict();
700     }
701     return nullptr;
702 }
703 CPDF_Array* CPDF_Dictionary::GetArray(const CFX_ByteStringC& 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(const CFX_ByteStringC& 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(const CFX_ByteStringC& 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(const CFX_ByteStringC& 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(const CFX_ByteStringC& key) const
738 {
739     void* value;
740     return m_Map.Lookup(key, value);
741 }
742 void CPDF_Dictionary::SetAt(const CFX_ByteStringC& 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 = new CPDF_Reference(pObjs, pObj->GetObjNum());
756         }
757         m_Map.SetAt(key, pObj);
758     } else {
759         m_Map.RemoveKey(key);
760     }
761 }
762 void CPDF_Dictionary::AddValue(const CFX_ByteStringC& key, CPDF_Object* pObj)
763 {
764     ASSERT(m_Type == PDFOBJ_DICTIONARY);
765     m_Map.AddValue(key, pObj);
766 }
767 void CPDF_Dictionary::RemoveAt(const CFX_ByteStringC& 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(const CFX_ByteStringC& oldkey, const CFX_ByteStringC& 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         void* 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(const CFX_ByteStringC& key, int i)
811 {
812     SetAt(key, new CPDF_Number(i));
813 }
814 void CPDF_Dictionary::SetAtName(const CFX_ByteStringC& key, const CFX_ByteString& name)
815 {
816     SetAt(key, new CPDF_Name(name));
817 }
818 void CPDF_Dictionary::SetAtString(const CFX_ByteStringC& key, const CFX_ByteString& str)
819 {
820     SetAt(key, new CPDF_String(str));
821 }
822 void CPDF_Dictionary::SetAtReference(const CFX_ByteStringC& key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
823 {
824     SetAt(key, new CPDF_Reference(pDoc, objnum));
825 }
826 void CPDF_Dictionary::AddReference(const CFX_ByteStringC& key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum)
827 {
828     AddValue(key, new CPDF_Reference(pDoc, objnum));
829 }
830 void CPDF_Dictionary::SetAtNumber(const CFX_ByteStringC& 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(const CFX_ByteStringC& key, FX_BOOL bValue)
837 {
838     SetAt(key, new CPDF_Boolean(bValue));
839 }
840 void CPDF_Dictionary::SetAtRect(const CFX_ByteStringC& 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(const CFX_ByteStringC& 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(uint8_t* 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(uint8_t* 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_memcpy(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(const uint8_t* 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 = (uint8_t*)pData;
920     } else {
921         m_pDataBuf = FX_Alloc(uint8_t, size);
922         if (pData) {
923             FXSYS_memcpy(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, uint8_t* 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_memcpy(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_memcmp(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         uint8_t* 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_memcmp(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_memcmp(m_pDataBuf, pOther->m_pDataBuf, m_dwSize) == 0;
1025 }
1026 CPDF_Stream* CPDF_Stream::Clone(FX_BOOL bDirect, FPDF_LPFCloneStreamCallback lpfCallback, void* 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         uint8_t* 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(const uint8_t* src_buf, FX_DWORD src_size, const CPDF_Dictionary* pDict,
1058                               uint8_t*& 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 = (uint8_t*)pStream->m_pDataBuf;
1080         return;
1081     }
1082     uint8_t* 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     uint8_t* 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         void* 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 const uint8_t* 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 uint8_t* CPDF_StreamAcc::DetachData()
1160 {
1161     if (m_bNewBuf) {
1162         uint8_t* p = m_pData;
1163         m_pData = NULL;
1164         m_dwSize = 0;
1165         return p;
1166     }
1167     uint8_t* p = FX_Alloc(uint8_t, m_dwSize);
1168     FXSYS_memcpy(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         void* key;
1191         void* value;
1192         m_IndirectObjs.GetNextAssoc(pos, key, value);
1193         ((CPDF_Object*)value)->Destroy();
1194     }
1195 }
1196 CPDF_Object* CPDF_IndirectObjects::GetIndirectObject(FX_DWORD objnum, struct PARSE_CONTEXT* pContext)
1197 {
1198     if (objnum == 0) {
1199         return NULL;
1200     }
1201     void* value;
1202     {
1203         if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1204             if (((CPDF_Object*)value)->GetObjNum() == -1) {
1205                 return NULL;
1206             }
1207             return (CPDF_Object*)value;
1208         }
1209     }
1210     CPDF_Object* pObj = NULL;
1211     if (m_pParser) {
1212         pObj = m_pParser->ParseIndirectObject(this, objnum, pContext);
1213     }
1214     if (pObj == NULL) {
1215         return NULL;
1216     }
1217     pObj->m_ObjNum = objnum;
1218     if (m_LastObjNum < objnum) {
1219         m_LastObjNum = objnum;
1220     }
1221     if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1222         if (value) {
1223             ((CPDF_Object *)value)->Destroy();
1224         }
1225     }
1226     m_IndirectObjs.SetAt((void*)(uintptr_t)objnum, pObj);
1227     return pObj;
1228 }
1229 int CPDF_IndirectObjects::GetIndirectType(FX_DWORD objnum)
1230 {
1231     void* value;
1232     if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1233         return ((CPDF_Object*)value)->GetType();
1234     }
1235     if (m_pParser) {
1236         PARSE_CONTEXT context;
1237         FXSYS_memset(&context, 0, sizeof(PARSE_CONTEXT));
1238         context.m_Flags = PDFPARSE_TYPEONLY;
1239         return (int)(uintptr_t)m_pParser->ParseIndirectObject(this, objnum, &context);
1240     }
1241     return 0;
1242 }
1243 FX_DWORD CPDF_IndirectObjects::AddIndirectObject(CPDF_Object* pObj)
1244 {
1245     if (pObj->m_ObjNum) {
1246         return pObj->m_ObjNum;
1247     }
1248     m_LastObjNum ++;
1249     m_IndirectObjs.SetAt((void*)(uintptr_t)m_LastObjNum, pObj);
1250     pObj->m_ObjNum = m_LastObjNum;
1251     return m_LastObjNum;
1252 }
1253 void CPDF_IndirectObjects::ReleaseIndirectObject(FX_DWORD objnum)
1254 {
1255     void* value;
1256     if (!m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1257         return;
1258     }
1259     if (((CPDF_Object*)value)->GetObjNum() == -1) {
1260         return;
1261     }
1262     ((CPDF_Object*)value)->Destroy();
1263     m_IndirectObjs.RemoveKey((void*)(uintptr_t)objnum);
1264 }
1265 void CPDF_IndirectObjects::InsertIndirectObject(FX_DWORD objnum, CPDF_Object* pObj)
1266 {
1267     if (objnum == 0 || pObj == NULL) {
1268         return;
1269     }
1270     void* value = NULL;
1271     if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1272         if (value) {
1273             if (pObj->GetGenNum() <= ((CPDF_Object*)value)->GetGenNum()) {
1274                 return;
1275             }
1276             ((CPDF_Object*)value)->Destroy();
1277          }
1278     }
1279     pObj->m_ObjNum = objnum;
1280     m_IndirectObjs.SetAt((void*)(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 }