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