Remove default argument from CPDF_Dictionary::SetAt().
[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
721 void CPDF_Dictionary::SetAt(const CFX_ByteStringC& key, CPDF_Object* pObj) {
722   ASSERT(IsDictionary());
723   void* pValue = nullptr;
724   m_Map.Lookup(key, pValue);
725   CPDF_Object* pExisting = static_cast<CPDF_Object*>(pValue);
726   if (pExisting == pObj)
727     return;
728
729   if (pExisting)
730     pExisting->Release();
731
732   if (pObj)
733     m_Map.SetAt(key, pObj);
734   else
735     m_Map.RemoveKey(key);
736 }
737
738 void CPDF_Dictionary::AddValue(const CFX_ByteStringC& key, CPDF_Object* pObj) {
739   ASSERT(m_Type == PDFOBJ_DICTIONARY);
740   m_Map.AddValue(key, pObj);
741 }
742 void CPDF_Dictionary::RemoveAt(const CFX_ByteStringC& key) {
743   ASSERT(m_Type == PDFOBJ_DICTIONARY);
744   CPDF_Object* p = NULL;
745   m_Map.Lookup(key, (void*&)p);
746   if (p == NULL) {
747     return;
748   }
749   p->Release();
750   m_Map.RemoveKey(key);
751 }
752 void CPDF_Dictionary::ReplaceKey(const CFX_ByteStringC& oldkey,
753                                  const CFX_ByteStringC& newkey) {
754   ASSERT(m_Type == PDFOBJ_DICTIONARY);
755   CPDF_Object* p = NULL;
756   m_Map.Lookup(oldkey, (void*&)p);
757   if (p == NULL) {
758     return;
759   }
760   m_Map.RemoveKey(oldkey);
761   m_Map.SetAt(newkey, p);
762 }
763 FX_BOOL CPDF_Dictionary::Identical(CPDF_Dictionary* pOther) const {
764   if (pOther == NULL) {
765     return FALSE;
766   }
767   if (m_Map.GetCount() != pOther->m_Map.GetCount()) {
768     return FALSE;
769   }
770   FX_POSITION pos = m_Map.GetStartPosition();
771   while (pos) {
772     CFX_ByteString key;
773     void* value;
774     m_Map.GetNextAssoc(pos, key, value);
775     if (!value)
776       return FALSE;
777     if (!((CPDF_Object*)value)->IsIdentical(pOther->GetElement(key))) {
778       return FALSE;
779     }
780   }
781   return TRUE;
782 }
783 void CPDF_Dictionary::SetAtInteger(const CFX_ByteStringC& key, int i) {
784   SetAt(key, new CPDF_Number(i));
785 }
786 void CPDF_Dictionary::SetAtName(const CFX_ByteStringC& key,
787                                 const CFX_ByteString& name) {
788   SetAt(key, new CPDF_Name(name));
789 }
790 void CPDF_Dictionary::SetAtString(const CFX_ByteStringC& key,
791                                   const CFX_ByteString& str) {
792   SetAt(key, new CPDF_String(str));
793 }
794 void CPDF_Dictionary::SetAtReference(const CFX_ByteStringC& key,
795                                      CPDF_IndirectObjects* pDoc,
796                                      FX_DWORD objnum) {
797   SetAt(key, new CPDF_Reference(pDoc, objnum));
798 }
799 void CPDF_Dictionary::AddReference(const CFX_ByteStringC& key,
800                                    CPDF_IndirectObjects* pDoc,
801                                    FX_DWORD objnum) {
802   AddValue(key, new CPDF_Reference(pDoc, objnum));
803 }
804 void CPDF_Dictionary::SetAtNumber(const CFX_ByteStringC& key, FX_FLOAT f) {
805   CPDF_Number* pNumber = new CPDF_Number;
806   pNumber->SetNumber(f);
807   SetAt(key, pNumber);
808 }
809 void CPDF_Dictionary::SetAtBoolean(const CFX_ByteStringC& key, FX_BOOL bValue) {
810   SetAt(key, new CPDF_Boolean(bValue));
811 }
812 void CPDF_Dictionary::SetAtRect(const CFX_ByteStringC& key,
813                                 const CFX_FloatRect& rect) {
814   CPDF_Array* pArray = new CPDF_Array;
815   pArray->AddNumber(rect.left);
816   pArray->AddNumber(rect.bottom);
817   pArray->AddNumber(rect.right);
818   pArray->AddNumber(rect.top);
819   SetAt(key, pArray);
820 }
821 void CPDF_Dictionary::SetAtMatrix(const CFX_ByteStringC& key,
822                                   const CFX_AffineMatrix& matrix) {
823   CPDF_Array* pArray = new CPDF_Array;
824   pArray->AddNumber16(matrix.a);
825   pArray->AddNumber16(matrix.b);
826   pArray->AddNumber16(matrix.c);
827   pArray->AddNumber16(matrix.d);
828   pArray->AddNumber(matrix.e);
829   pArray->AddNumber(matrix.f);
830   SetAt(key, pArray);
831 }
832 CPDF_Stream::CPDF_Stream(uint8_t* pData, FX_DWORD size, CPDF_Dictionary* pDict)
833     : CPDF_Object(PDFOBJ_STREAM) {
834   m_pDict = pDict;
835   m_dwSize = size;
836   m_GenNum = (FX_DWORD)-1;
837   m_pDataBuf = pData;
838   m_pCryptoHandler = NULL;
839 }
840 CPDF_Stream::~CPDF_Stream() {
841   if (m_GenNum == (FX_DWORD)-1) {
842     FX_Free(m_pDataBuf);
843   }
844   if (m_pDict) {
845     m_pDict->Release();
846   }
847 }
848 void CPDF_Stream::InitStream(CPDF_Dictionary* pDict) {
849   if (pDict) {
850     if (m_pDict) {
851       m_pDict->Release();
852     }
853     m_pDict = pDict;
854   }
855   if (m_GenNum == (FX_DWORD)-1) {
856     FX_Free(m_pDataBuf);
857   }
858   m_GenNum = 0;
859   m_pFile = NULL;
860   m_pCryptoHandler = NULL;
861   m_FileOffset = 0;
862 }
863 void CPDF_Stream::InitStream(uint8_t* pData,
864                              FX_DWORD size,
865                              CPDF_Dictionary* pDict) {
866   InitStream(pDict);
867   m_GenNum = (FX_DWORD)-1;
868   m_pDataBuf = FX_Alloc(uint8_t, size);
869   if (pData) {
870     FXSYS_memcpy(m_pDataBuf, pData, size);
871   }
872   m_dwSize = size;
873   if (m_pDict) {
874     m_pDict->SetAtInteger(FX_BSTRC("Length"), size);
875   }
876 }
877 void CPDF_Stream::SetData(const uint8_t* pData,
878                           FX_DWORD size,
879                           FX_BOOL bCompressed,
880                           FX_BOOL bKeepBuf) {
881   if (m_GenNum == (FX_DWORD)-1) {
882     FX_Free(m_pDataBuf);
883   } else {
884     m_GenNum = (FX_DWORD)-1;
885     m_pCryptoHandler = NULL;
886   }
887   if (bKeepBuf) {
888     m_pDataBuf = (uint8_t*)pData;
889   } else {
890     m_pDataBuf = FX_Alloc(uint8_t, size);
891     if (pData) {
892       FXSYS_memcpy(m_pDataBuf, pData, size);
893     }
894   }
895   m_dwSize = size;
896   if (m_pDict == NULL) {
897     m_pDict = new CPDF_Dictionary;
898   }
899   m_pDict->SetAtInteger(FX_BSTRC("Length"), size);
900   if (!bCompressed) {
901     m_pDict->RemoveAt(FX_BSTRC("Filter"));
902     m_pDict->RemoveAt(FX_BSTRC("DecodeParms"));
903   }
904 }
905 FX_BOOL CPDF_Stream::ReadRawData(FX_FILESIZE offset,
906                                  uint8_t* buf,
907                                  FX_DWORD size) const {
908   if ((m_GenNum != (FX_DWORD)-1) && m_pFile) {
909     return m_pFile->ReadBlock(buf, m_FileOffset + offset, size);
910   }
911   if (m_pDataBuf) {
912     FXSYS_memcpy(buf, m_pDataBuf + offset, size);
913   }
914   return TRUE;
915 }
916 void CPDF_Stream::InitStream(IFX_FileRead* pFile, CPDF_Dictionary* pDict) {
917   InitStream(pDict);
918   m_pFile = pFile;
919   m_dwSize = (FX_DWORD)pFile->GetSize();
920   if (m_pDict) {
921     m_pDict->SetAtInteger(FX_BSTRC("Length"), m_dwSize);
922   }
923 }
924
925 FX_BOOL CPDF_Stream::Identical(CPDF_Stream* pOther) const {
926   if (!m_pDict)
927     return pOther->m_pDict ? FALSE : TRUE;
928
929   if (!m_pDict->Identical(pOther->m_pDict)) {
930     return FALSE;
931   }
932   if (m_dwSize != pOther->m_dwSize) {
933     return FALSE;
934   }
935   if (m_GenNum != (FX_DWORD)-1 && pOther->m_GenNum != (FX_DWORD)-1) {
936     if (m_pFile == pOther->m_pFile && m_pFile == NULL) {
937       return TRUE;
938     }
939     if (!m_pFile || !pOther->m_pFile) {
940       return FALSE;
941     }
942     uint8_t srcBuf[1024];
943     uint8_t destBuf[1024];
944     FX_DWORD size = m_dwSize;
945     FX_DWORD srcOffset = m_FileOffset;
946     FX_DWORD destOffset = pOther->m_FileOffset;
947     if (m_pFile == pOther->m_pFile && srcOffset == destOffset) {
948       return TRUE;
949     }
950     while (size > 0) {
951       FX_DWORD actualSize = size > 1024 ? 1024 : size;
952       m_pFile->ReadBlock(srcBuf, srcOffset, actualSize);
953       pOther->m_pFile->ReadBlock(destBuf, destOffset, actualSize);
954       if (FXSYS_memcmp(srcBuf, destBuf, actualSize) != 0) {
955         return FALSE;
956       }
957       size -= actualSize;
958       srcOffset += actualSize;
959       destOffset += actualSize;
960     }
961     return TRUE;
962   }
963   if (m_GenNum != (FX_DWORD)-1 || pOther->m_GenNum != (FX_DWORD)-1) {
964     IFX_FileRead* pFile = NULL;
965     uint8_t* pBuf = NULL;
966     FX_DWORD offset = 0;
967     if (pOther->m_GenNum != (FX_DWORD)-1) {
968       pFile = pOther->m_pFile;
969       pBuf = m_pDataBuf;
970       offset = pOther->m_FileOffset;
971     } else if (m_GenNum != (FX_DWORD)-1) {
972       pFile = m_pFile;
973       pBuf = pOther->m_pDataBuf;
974       offset = m_FileOffset;
975     }
976     if (NULL == pBuf) {
977       return FALSE;
978     }
979     uint8_t srcBuf[1024];
980     FX_DWORD size = m_dwSize;
981     while (size > 0) {
982       FX_DWORD actualSize = std::min(size, 1024U);
983       pFile->ReadBlock(srcBuf, offset, actualSize);
984       if (FXSYS_memcmp(srcBuf, pBuf, actualSize) != 0) {
985         return FALSE;
986       }
987       pBuf += actualSize;
988       size -= actualSize;
989       offset += actualSize;
990     }
991     return TRUE;
992   }
993   return FXSYS_memcmp(m_pDataBuf, pOther->m_pDataBuf, m_dwSize) == 0;
994 }
995
996 CPDF_StreamAcc::CPDF_StreamAcc() {
997   m_bNewBuf = FALSE;
998   m_pData = NULL;
999   m_dwSize = 0;
1000   m_pImageParam = NULL;
1001   m_pStream = NULL;
1002   m_pSrcData = NULL;
1003 }
1004 void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream,
1005                                  FX_BOOL bRawAccess,
1006                                  FX_DWORD estimated_size,
1007                                  FX_BOOL bImageAcc) {
1008   if (!pStream)
1009     return;
1010
1011   m_pStream = pStream;
1012   if (pStream->IsMemoryBased() &&
1013       (!pStream->GetDict()->KeyExist(FX_BSTRC("Filter")) || bRawAccess)) {
1014     m_dwSize = pStream->m_dwSize;
1015     m_pData = (uint8_t*)pStream->m_pDataBuf;
1016     return;
1017   }
1018   uint8_t* pSrcData;
1019   FX_DWORD dwSrcSize = pStream->m_dwSize;
1020   if (dwSrcSize == 0)
1021     return;
1022
1023   if (!pStream->IsMemoryBased()) {
1024     pSrcData = m_pSrcData = FX_Alloc(uint8_t, dwSrcSize);
1025     if (!pStream->ReadRawData(0, pSrcData, dwSrcSize))
1026       return;
1027   } else {
1028     pSrcData = pStream->m_pDataBuf;
1029   }
1030   uint8_t* pDecryptedData;
1031   FX_DWORD dwDecryptedSize;
1032   if (pStream->m_pCryptoHandler) {
1033     CFX_BinaryBuf dest_buf;
1034     dest_buf.EstimateSize(pStream->m_pCryptoHandler->DecryptGetSize(dwSrcSize));
1035     void* context = pStream->m_pCryptoHandler->DecryptStart(
1036         pStream->GetObjNum(), pStream->m_GenNum);
1037     pStream->m_pCryptoHandler->DecryptStream(context, pSrcData, dwSrcSize,
1038                                              dest_buf);
1039     pStream->m_pCryptoHandler->DecryptFinish(context, dest_buf);
1040     pDecryptedData = dest_buf.GetBuffer();
1041     dwDecryptedSize = dest_buf.GetSize();
1042     dest_buf.DetachBuffer();
1043   } else {
1044     pDecryptedData = pSrcData;
1045     dwDecryptedSize = dwSrcSize;
1046   }
1047   if (!pStream->GetDict()->KeyExist(FX_BSTRC("Filter")) || bRawAccess) {
1048     m_pData = pDecryptedData;
1049     m_dwSize = dwDecryptedSize;
1050   } else {
1051     FX_BOOL bRet = PDF_DataDecode(
1052         pDecryptedData, dwDecryptedSize, m_pStream->GetDict(), m_pData,
1053         m_dwSize, m_ImageDecoder, m_pImageParam, estimated_size, bImageAcc);
1054     if (!bRet) {
1055       m_pData = pDecryptedData;
1056       m_dwSize = dwDecryptedSize;
1057     }
1058   }
1059   if (pSrcData != pStream->m_pDataBuf && pSrcData != m_pData) {
1060     FX_Free(pSrcData);
1061   }
1062   if (pDecryptedData != pSrcData && pDecryptedData != m_pData) {
1063     FX_Free(pDecryptedData);
1064   }
1065   m_pSrcData = NULL;
1066   m_bNewBuf = m_pData != pStream->m_pDataBuf;
1067 }
1068 CPDF_StreamAcc::~CPDF_StreamAcc() {
1069   if (m_bNewBuf) {
1070     FX_Free(m_pData);
1071   }
1072   FX_Free(m_pSrcData);
1073 }
1074 const uint8_t* CPDF_StreamAcc::GetData() const {
1075   if (m_bNewBuf) {
1076     return m_pData;
1077   }
1078   if (!m_pStream) {
1079     return NULL;
1080   }
1081   return m_pStream->m_pDataBuf;
1082 }
1083 FX_DWORD CPDF_StreamAcc::GetSize() const {
1084   if (m_bNewBuf) {
1085     return m_dwSize;
1086   }
1087   if (!m_pStream) {
1088     return 0;
1089   }
1090   return m_pStream->m_dwSize;
1091 }
1092 uint8_t* CPDF_StreamAcc::DetachData() {
1093   if (m_bNewBuf) {
1094     uint8_t* p = m_pData;
1095     m_pData = NULL;
1096     m_dwSize = 0;
1097     return p;
1098   }
1099   uint8_t* p = FX_Alloc(uint8_t, m_dwSize);
1100   FXSYS_memcpy(p, m_pData, m_dwSize);
1101   return p;
1102 }
1103 void CPDF_Reference::SetRef(CPDF_IndirectObjects* pDoc, FX_DWORD objnum) {
1104   m_pObjList = pDoc;
1105   m_RefObjNum = objnum;
1106 }
1107 CPDF_IndirectObjects::CPDF_IndirectObjects(CPDF_Parser* pParser) {
1108   m_pParser = pParser;
1109   m_IndirectObjs.InitHashTable(1013);
1110   if (pParser) {
1111     m_LastObjNum = m_pParser->GetLastObjNum();
1112   } else {
1113     m_LastObjNum = 0;
1114   }
1115 }
1116 CPDF_IndirectObjects::~CPDF_IndirectObjects() {
1117   FX_POSITION pos = m_IndirectObjs.GetStartPosition();
1118   while (pos) {
1119     void* key;
1120     void* value;
1121     m_IndirectObjs.GetNextAssoc(pos, key, value);
1122     ((CPDF_Object*)value)->Destroy();
1123   }
1124 }
1125 CPDF_Object* CPDF_IndirectObjects::GetIndirectObject(
1126     FX_DWORD objnum,
1127     struct PARSE_CONTEXT* pContext) {
1128   if (objnum == 0) {
1129     return NULL;
1130   }
1131   void* value;
1132   {
1133     if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1134       if (((CPDF_Object*)value)->GetObjNum() == -1) {
1135         return NULL;
1136       }
1137       return (CPDF_Object*)value;
1138     }
1139   }
1140   CPDF_Object* pObj = NULL;
1141   if (m_pParser) {
1142     pObj = m_pParser->ParseIndirectObject(this, objnum, pContext);
1143   }
1144   if (pObj == NULL) {
1145     return NULL;
1146   }
1147   pObj->m_ObjNum = objnum;
1148   if (m_LastObjNum < objnum) {
1149     m_LastObjNum = objnum;
1150   }
1151   if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1152     if (value) {
1153       ((CPDF_Object*)value)->Destroy();
1154     }
1155   }
1156   m_IndirectObjs.SetAt((void*)(uintptr_t)objnum, pObj);
1157   return pObj;
1158 }
1159 int CPDF_IndirectObjects::GetIndirectType(FX_DWORD objnum) {
1160   void* value;
1161   if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1162     return ((CPDF_Object*)value)->GetType();
1163   }
1164   if (m_pParser) {
1165     PARSE_CONTEXT context;
1166     FXSYS_memset(&context, 0, sizeof(PARSE_CONTEXT));
1167     context.m_Flags = PDFPARSE_TYPEONLY;
1168     return (int)(uintptr_t)m_pParser->ParseIndirectObject(this, objnum,
1169                                                           &context);
1170   }
1171   return 0;
1172 }
1173 FX_DWORD CPDF_IndirectObjects::AddIndirectObject(CPDF_Object* pObj) {
1174   if (pObj->m_ObjNum) {
1175     return pObj->m_ObjNum;
1176   }
1177   m_LastObjNum++;
1178   m_IndirectObjs.SetAt((void*)(uintptr_t)m_LastObjNum, pObj);
1179   pObj->m_ObjNum = m_LastObjNum;
1180   return m_LastObjNum;
1181 }
1182 void CPDF_IndirectObjects::ReleaseIndirectObject(FX_DWORD objnum) {
1183   void* value;
1184   if (!m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1185     return;
1186   }
1187   if (((CPDF_Object*)value)->GetObjNum() == -1) {
1188     return;
1189   }
1190   ((CPDF_Object*)value)->Destroy();
1191   m_IndirectObjs.RemoveKey((void*)(uintptr_t)objnum);
1192 }
1193 void CPDF_IndirectObjects::InsertIndirectObject(FX_DWORD objnum,
1194                                                 CPDF_Object* pObj) {
1195   if (objnum == 0 || pObj == NULL) {
1196     return;
1197   }
1198   void* value = NULL;
1199   if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1200     if (value) {
1201       if (pObj->GetGenNum() <= ((CPDF_Object*)value)->GetGenNum()) {
1202         return;
1203       }
1204       ((CPDF_Object*)value)->Destroy();
1205     }
1206   }
1207   pObj->m_ObjNum = objnum;
1208   m_IndirectObjs.SetAt((void*)(uintptr_t)objnum, pObj);
1209   if (m_LastObjNum < objnum) {
1210     m_LastObjNum = objnum;
1211   }
1212 }
1213 FX_DWORD CPDF_IndirectObjects::GetLastObjNum() const {
1214   return m_LastObjNum;
1215 }