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