Clean up CPDF_AnnotList.
[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 =
248             static_cast<CPDF_Object*>(pThis->m_Objects.GetAt(i));
249         pCopy->m_Objects.Add(value->CloneInternal(bDirect, visited));
250       }
251       return pCopy;
252     }
253     case PDFOBJ_DICTIONARY: {
254       CPDF_Dictionary* pCopy = new CPDF_Dictionary();
255       const CPDF_Dictionary* pThis = AsDictionary();
256       FX_POSITION pos = pThis->m_Map.GetStartPosition();
257       while (pos) {
258         CFX_ByteString key;
259         CPDF_Object* value;
260         pThis->m_Map.GetNextAssoc(pos, key, (void*&)value);
261         pCopy->m_Map.SetAt(key, value->CloneInternal(bDirect, visited));
262       }
263       return pCopy;
264     }
265     case PDFOBJ_NULL: {
266       return new CPDF_Null;
267     }
268     case PDFOBJ_STREAM: {
269       const CPDF_Stream* pThis = AsStream();
270       CPDF_StreamAcc acc;
271       acc.LoadAllData(pThis, TRUE);
272       FX_DWORD streamSize = acc.GetSize();
273       CPDF_Dictionary* pDict = pThis->GetDict();
274       if (pDict) {
275         pDict = ToDictionary(pDict->CloneInternal(bDirect, visited));
276       }
277       return new CPDF_Stream(acc.DetachData(), streamSize, pDict);
278     }
279     case PDFOBJ_REFERENCE: {
280       const CPDF_Reference* pRef = AsReference();
281       FX_DWORD obj_num = pRef->GetRefObjNum();
282       if (bDirect && !visited->GetValueAt((void*)(uintptr_t)obj_num)) {
283         visited->SetAt((void*)(uintptr_t)obj_num, (void*)1);
284         if (!pRef->GetDirect())
285           return nullptr;
286
287         return pRef->GetDirect()->CloneInternal(TRUE, visited);
288       }
289       return new CPDF_Reference(pRef->m_pObjList, obj_num);
290     }
291   }
292   return NULL;
293 }
294 CPDF_Object* CPDF_Object::CloneRef(CPDF_IndirectObjects* pDoc) const {
295   if (m_ObjNum) {
296     return new CPDF_Reference(pDoc, m_ObjNum);
297   }
298   return Clone();
299 }
300 CFX_WideString CPDF_Object::GetUnicodeText(CFX_CharMap* pCharMap) const {
301   if (const CPDF_String* pString = AsString())
302     return PDF_DecodeText(pString->m_String, pCharMap);
303
304   if (const CPDF_Stream* pStream = AsStream()) {
305     CPDF_StreamAcc stream;
306     stream.LoadAllData(pStream, FALSE);
307     CFX_WideString result =
308         PDF_DecodeText(stream.GetData(), stream.GetSize(), pCharMap);
309     return result;
310   }
311   if (const CPDF_Name* pName = AsName())
312     return PDF_DecodeText(pName->m_Name, pCharMap);
313   return CFX_WideString();
314 }
315 void CPDF_Object::SetUnicodeText(const FX_WCHAR* pUnicodes, int len) {
316   if (CPDF_String* pString = AsString()) {
317     pString->m_String = PDF_EncodeText(pUnicodes, len);
318   } else if (CPDF_Stream* pStream = AsStream()) {
319     CFX_ByteString result = PDF_EncodeText(pUnicodes, len);
320     pStream->SetData((uint8_t*)result.c_str(), result.GetLength(), FALSE,
321                      FALSE);
322   }
323 }
324
325 CPDF_Array* CPDF_Object::AsArray() {
326   return IsArray() ? static_cast<CPDF_Array*>(this) : nullptr;
327 }
328
329 const CPDF_Array* CPDF_Object::AsArray() const {
330   return IsArray() ? static_cast<const CPDF_Array*>(this) : nullptr;
331 }
332
333 CPDF_Boolean* CPDF_Object::AsBoolean() {
334   return IsBoolean() ? static_cast<CPDF_Boolean*>(this) : nullptr;
335 }
336
337 const CPDF_Boolean* CPDF_Object::AsBoolean() const {
338   return IsBoolean() ? static_cast<const CPDF_Boolean*>(this) : nullptr;
339 }
340
341 CPDF_Dictionary* CPDF_Object::AsDictionary() {
342   return IsDictionary() ? static_cast<CPDF_Dictionary*>(this) : nullptr;
343 }
344
345 const CPDF_Dictionary* CPDF_Object::AsDictionary() const {
346   return IsDictionary() ? static_cast<const CPDF_Dictionary*>(this) : nullptr;
347 }
348
349 CPDF_Name* CPDF_Object::AsName() {
350   return IsName() ? static_cast<CPDF_Name*>(this) : nullptr;
351 }
352
353 const CPDF_Name* CPDF_Object::AsName() const {
354   return IsName() ? static_cast<const CPDF_Name*>(this) : nullptr;
355 }
356
357 CPDF_Number* CPDF_Object::AsNumber() {
358   return IsNumber() ? static_cast<CPDF_Number*>(this) : nullptr;
359 }
360
361 const CPDF_Number* CPDF_Object::AsNumber() const {
362   return IsNumber() ? static_cast<const CPDF_Number*>(this) : nullptr;
363 }
364
365 CPDF_Reference* CPDF_Object::AsReference() {
366   return IsReference() ? static_cast<CPDF_Reference*>(this) : nullptr;
367 }
368
369 const CPDF_Reference* CPDF_Object::AsReference() const {
370   return IsReference() ? static_cast<const CPDF_Reference*>(this) : nullptr;
371 }
372
373 CPDF_Stream* CPDF_Object::AsStream() {
374   return IsStream() ? static_cast<CPDF_Stream*>(this) : nullptr;
375 }
376
377 const CPDF_Stream* CPDF_Object::AsStream() const {
378   return IsStream() ? static_cast<const CPDF_Stream*>(this) : nullptr;
379 }
380
381 CPDF_String* CPDF_Object::AsString() {
382   return IsString() ? static_cast<CPDF_String*>(this) : nullptr;
383 }
384
385 const CPDF_String* CPDF_Object::AsString() const {
386   return IsString() ? static_cast<const CPDF_String*>(this) : nullptr;
387 }
388
389 CPDF_Number::CPDF_Number(int value)
390     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(TRUE), m_Integer(value) {}
391
392 CPDF_Number::CPDF_Number(FX_FLOAT value)
393     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(FALSE), m_Float(value) {}
394
395 CPDF_Number::CPDF_Number(const CFX_ByteStringC& str)
396     : CPDF_Object(PDFOBJ_NUMBER) {
397   FX_atonum(str, m_bInteger, &m_Integer);
398 }
399
400 void CPDF_Number::SetString(const CFX_ByteStringC& str) {
401   FX_atonum(str, m_bInteger, &m_Integer);
402 }
403 FX_BOOL CPDF_Number::Identical(CPDF_Number* pOther) const {
404   return m_bInteger == pOther->m_bInteger && m_Integer == pOther->m_Integer;
405 }
406 CFX_ByteString CPDF_Number::GetString() const {
407   return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED)
408                     : CFX_ByteString::FormatFloat(m_Float);
409 }
410 void CPDF_Number::SetNumber(FX_FLOAT value) {
411   m_bInteger = FALSE;
412   m_Float = value;
413 }
414 CPDF_String::CPDF_String(const CFX_WideString& str)
415     : CPDF_Object(PDFOBJ_STRING), m_bHex(FALSE) {
416   m_String = PDF_EncodeText(str);
417 }
418 CPDF_Array::~CPDF_Array() {
419   int size = m_Objects.GetSize();
420   CPDF_Object** pList = (CPDF_Object**)m_Objects.GetData();
421   for (int i = 0; i < size; i++) {
422     if (pList[i])
423       pList[i]->Release();
424   }
425 }
426 CFX_FloatRect CPDF_Array::GetRect() {
427   CFX_FloatRect rect;
428   if (!IsArray() || m_Objects.GetSize() != 4)
429     return rect;
430
431   rect.left = GetNumber(0);
432   rect.bottom = GetNumber(1);
433   rect.right = GetNumber(2);
434   rect.top = GetNumber(3);
435   return rect;
436 }
437 CFX_AffineMatrix CPDF_Array::GetMatrix() {
438   CFX_AffineMatrix matrix;
439   if (!IsArray() || m_Objects.GetSize() != 6)
440     return matrix;
441
442   matrix.Set(GetNumber(0), GetNumber(1), GetNumber(2), GetNumber(3),
443              GetNumber(4), GetNumber(5));
444   return matrix;
445 }
446 CPDF_Object* CPDF_Array::GetElement(FX_DWORD i) const {
447   if (i >= (FX_DWORD)m_Objects.GetSize())
448     return nullptr;
449   return static_cast<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 nullptr;
454   return static_cast<CPDF_Object*>(m_Objects.GetAt(i))->GetDirect();
455 }
456 CFX_ByteString CPDF_Array::GetString(FX_DWORD i) const {
457   if (i < (FX_DWORD)m_Objects.GetSize())
458     return static_cast<CPDF_Object*>(m_Objects.GetAt(i))->GetString();
459   return CFX_ByteString();
460 }
461 CFX_ByteStringC CPDF_Array::GetConstString(FX_DWORD i) const {
462   if (i < (FX_DWORD)m_Objects.GetSize())
463     return static_cast<CPDF_Object*>(m_Objects.GetAt(i))->GetConstString();
464   return CFX_ByteStringC();
465 }
466 int CPDF_Array::GetInteger(FX_DWORD i) const {
467   if (i >= (FX_DWORD)m_Objects.GetSize())
468     return 0;
469   return static_cast<CPDF_Object*>(m_Objects.GetAt(i))->GetInteger();
470 }
471 FX_FLOAT CPDF_Array::GetNumber(FX_DWORD i) const {
472   if (i >= (FX_DWORD)m_Objects.GetSize())
473     return 0;
474   return static_cast<CPDF_Object*>(m_Objects.GetAt(i))->GetNumber();
475 }
476 CPDF_Dictionary* CPDF_Array::GetDict(FX_DWORD i) const {
477   CPDF_Object* p = GetElementValue(i);
478   if (!p)
479     return NULL;
480   if (CPDF_Dictionary* pDict = p->AsDictionary())
481     return pDict;
482   if (CPDF_Stream* pStream = p->AsStream())
483     return pStream->GetDict();
484   return NULL;
485 }
486 CPDF_Stream* CPDF_Array::GetStream(FX_DWORD i) const {
487   return ToStream(GetElementValue(i));
488 }
489 CPDF_Array* CPDF_Array::GetArray(FX_DWORD i) const {
490   return ToArray(GetElementValue(i));
491 }
492 void CPDF_Array::RemoveAt(FX_DWORD i) {
493   ASSERT(IsArray());
494   if (i >= (FX_DWORD)m_Objects.GetSize())
495     return;
496   if (CPDF_Object* p = static_cast<CPDF_Object*>(m_Objects.GetAt(i)))
497     p->Release();
498   m_Objects.RemoveAt(i);
499 }
500 void CPDF_Array::SetAt(FX_DWORD i,
501                        CPDF_Object* pObj,
502                        CPDF_IndirectObjects* pObjs) {
503   ASSERT(IsArray());
504   ASSERT(i < (FX_DWORD)m_Objects.GetSize());
505   if (i >= (FX_DWORD)m_Objects.GetSize())
506     return;
507   if (CPDF_Object* pOld = static_cast<CPDF_Object*>(m_Objects.GetAt(i)))
508     pOld->Release();
509   if (pObj->GetObjNum()) {
510     ASSERT(pObjs);
511     pObj = new CPDF_Reference(pObjs, pObj->GetObjNum());
512   }
513   m_Objects.SetAt(i, pObj);
514 }
515 void CPDF_Array::InsertAt(FX_DWORD index,
516                           CPDF_Object* pObj,
517                           CPDF_IndirectObjects* pObjs) {
518   ASSERT(pObj != NULL);
519   if (pObj->GetObjNum()) {
520     ASSERT(pObjs != NULL);
521     pObj = new CPDF_Reference(pObjs, pObj->GetObjNum());
522   }
523   m_Objects.InsertAt(index, pObj);
524 }
525 void CPDF_Array::Add(CPDF_Object* pObj, CPDF_IndirectObjects* pObjs) {
526   ASSERT(pObj != NULL);
527   if (pObj->GetObjNum()) {
528     ASSERT(pObjs != NULL);
529     pObj = new CPDF_Reference(pObjs, pObj->GetObjNum());
530   }
531   m_Objects.Add(pObj);
532 }
533 void CPDF_Array::AddName(const CFX_ByteString& str) {
534   ASSERT(IsArray());
535   Add(new CPDF_Name(str));
536 }
537 void CPDF_Array::AddString(const CFX_ByteString& str) {
538   ASSERT(IsArray());
539   Add(new CPDF_String(str));
540 }
541 void CPDF_Array::AddInteger(int i) {
542   ASSERT(IsArray());
543   Add(new CPDF_Number(i));
544 }
545 void CPDF_Array::AddNumber(FX_FLOAT f) {
546   ASSERT(IsArray());
547   CPDF_Number* pNumber = new CPDF_Number;
548   pNumber->SetNumber(f);
549   Add(pNumber);
550 }
551 void CPDF_Array::AddReference(CPDF_IndirectObjects* pDoc, FX_DWORD objnum) {
552   ASSERT(IsArray());
553   Add(new CPDF_Reference(pDoc, objnum));
554 }
555 FX_BOOL CPDF_Array::Identical(CPDF_Array* pOther) const {
556   if (m_Objects.GetSize() != pOther->m_Objects.GetSize()) {
557     return FALSE;
558   }
559   for (int i = 0; i < m_Objects.GetSize(); i++)
560     if (!static_cast<CPDF_Object*>(m_Objects[i])
561              ->IsIdentical(static_cast<CPDF_Object*>(pOther->m_Objects[i]))) {
562       return FALSE;
563     }
564   return TRUE;
565 }
566 CPDF_Dictionary::~CPDF_Dictionary() {
567   FX_POSITION pos = m_Map.GetStartPosition();
568   while (pos) {
569     if (CPDF_Object* value = static_cast<CPDF_Object*>(m_Map.GetNextValue(pos)))
570       value->Release();
571   }
572 }
573 FX_POSITION CPDF_Dictionary::GetStartPos() const {
574   return m_Map.GetStartPosition();
575 }
576 CPDF_Object* CPDF_Dictionary::GetNextElement(FX_POSITION& pos,
577                                              CFX_ByteString& key) const {
578   if (pos == NULL) {
579     return NULL;
580   }
581   CPDF_Object* p;
582   m_Map.GetNextAssoc(pos, key, (void*&)p);
583   return p;
584 }
585 CPDF_Object* CPDF_Dictionary::GetElement(const CFX_ByteStringC& key) const {
586   CPDF_Object* p = NULL;
587   m_Map.Lookup(key, (void*&)p);
588   return p;
589 }
590 CPDF_Object* CPDF_Dictionary::GetElementValue(
591     const CFX_ByteStringC& key) const {
592   CPDF_Object* p = NULL;
593   m_Map.Lookup(key, (void*&)p);
594   return p ? p->GetDirect() : NULL;
595 }
596 CFX_ByteString CPDF_Dictionary::GetString(const CFX_ByteStringC& key) const {
597   CPDF_Object* p = NULL;
598   m_Map.Lookup(key, (void*&)p);
599   if (p) {
600     return p->GetString();
601   }
602   return CFX_ByteString();
603 }
604 CFX_ByteStringC CPDF_Dictionary::GetConstString(
605     const CFX_ByteStringC& key) const {
606   CPDF_Object* p = NULL;
607   m_Map.Lookup(key, (void*&)p);
608   if (p) {
609     return p->GetConstString();
610   }
611   return CFX_ByteStringC();
612 }
613 CFX_WideString CPDF_Dictionary::GetUnicodeText(const CFX_ByteStringC& key,
614                                                CFX_CharMap* pCharMap) const {
615   CPDF_Object* p = NULL;
616   m_Map.Lookup(key, (void*&)p);
617   if (CPDF_Reference* pRef = ToReference(p))
618     p = pRef->GetDirect();
619   return p ? p->GetUnicodeText(pCharMap) : CFX_WideString();
620 }
621 CFX_ByteString CPDF_Dictionary::GetString(const CFX_ByteStringC& key,
622                                           const CFX_ByteStringC& def) const {
623   CPDF_Object* p = NULL;
624   m_Map.Lookup(key, (void*&)p);
625   if (p) {
626     return p->GetString();
627   }
628   return CFX_ByteString(def);
629 }
630 CFX_ByteStringC CPDF_Dictionary::GetConstString(
631     const CFX_ByteStringC& key,
632     const CFX_ByteStringC& def) const {
633   CPDF_Object* p = NULL;
634   m_Map.Lookup(key, (void*&)p);
635   if (p) {
636     return p->GetConstString();
637   }
638   return CFX_ByteStringC(def);
639 }
640 int CPDF_Dictionary::GetInteger(const CFX_ByteStringC& key) const {
641   CPDF_Object* p = NULL;
642   m_Map.Lookup(key, (void*&)p);
643   if (p) {
644     return p->GetInteger();
645   }
646   return 0;
647 }
648 int CPDF_Dictionary::GetInteger(const CFX_ByteStringC& key, int def) const {
649   CPDF_Object* p = NULL;
650   m_Map.Lookup(key, (void*&)p);
651   if (p) {
652     return p->GetInteger();
653   }
654   return def;
655 }
656 FX_FLOAT CPDF_Dictionary::GetNumber(const CFX_ByteStringC& key) const {
657   CPDF_Object* p = NULL;
658   m_Map.Lookup(key, (void*&)p);
659   if (p) {
660     return p->GetNumber();
661   }
662   return 0;
663 }
664 FX_BOOL CPDF_Dictionary::GetBoolean(const CFX_ByteStringC& key,
665                                     FX_BOOL bDefault) const {
666   CPDF_Object* p = NULL;
667   m_Map.Lookup(key, (void*&)p);
668   if (ToBoolean(p))
669     return p->GetInteger();
670   return bDefault;
671 }
672 CPDF_Dictionary* CPDF_Dictionary::GetDict(const CFX_ByteStringC& key) const {
673   CPDF_Object* p = GetElementValue(key);
674   if (!p)
675     return nullptr;
676   if (CPDF_Dictionary* pDict = p->AsDictionary())
677     return pDict;
678   if (CPDF_Stream* pStream = p->AsStream())
679     return pStream->GetDict();
680   return nullptr;
681 }
682 CPDF_Array* CPDF_Dictionary::GetArray(const CFX_ByteStringC& key) const {
683   return ToArray(GetElementValue(key));
684 }
685 CPDF_Stream* CPDF_Dictionary::GetStream(const CFX_ByteStringC& key) const {
686   return ToStream(GetElementValue(key));
687 }
688 CFX_FloatRect CPDF_Dictionary::GetRect(const CFX_ByteStringC& key) const {
689   CFX_FloatRect rect;
690   CPDF_Array* pArray = GetArray(key);
691   if (pArray)
692     rect = pArray->GetRect();
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   return matrix;
701 }
702 FX_BOOL CPDF_Dictionary::KeyExist(const CFX_ByteStringC& key) const {
703   void* value;
704   return m_Map.Lookup(key, value);
705 }
706
707 void CPDF_Dictionary::SetAt(const CFX_ByteStringC& key, CPDF_Object* pObj) {
708   ASSERT(IsDictionary());
709   void* pValue = nullptr;
710   m_Map.Lookup(key, pValue);
711   CPDF_Object* pExisting = static_cast<CPDF_Object*>(pValue);
712   if (pExisting == pObj)
713     return;
714
715   if (pExisting)
716     pExisting->Release();
717
718   if (pObj)
719     m_Map.SetAt(key, pObj);
720   else
721     m_Map.RemoveKey(key);
722 }
723
724 void CPDF_Dictionary::AddValue(const CFX_ByteStringC& key, CPDF_Object* pObj) {
725   ASSERT(m_Type == PDFOBJ_DICTIONARY);
726   m_Map.AddValue(key, pObj);
727 }
728 void CPDF_Dictionary::RemoveAt(const CFX_ByteStringC& key) {
729   ASSERT(m_Type == PDFOBJ_DICTIONARY);
730   CPDF_Object* p = NULL;
731   m_Map.Lookup(key, (void*&)p);
732   if (p == NULL) {
733     return;
734   }
735   p->Release();
736   m_Map.RemoveKey(key);
737 }
738 void CPDF_Dictionary::ReplaceKey(const CFX_ByteStringC& oldkey,
739                                  const CFX_ByteStringC& newkey) {
740   ASSERT(m_Type == PDFOBJ_DICTIONARY);
741   CPDF_Object* p = NULL;
742   m_Map.Lookup(oldkey, (void*&)p);
743   if (p == NULL) {
744     return;
745   }
746   m_Map.RemoveKey(oldkey);
747   m_Map.SetAt(newkey, p);
748 }
749 FX_BOOL CPDF_Dictionary::Identical(CPDF_Dictionary* pOther) const {
750   if (pOther == NULL) {
751     return FALSE;
752   }
753   if (m_Map.GetCount() != pOther->m_Map.GetCount()) {
754     return FALSE;
755   }
756   FX_POSITION pos = m_Map.GetStartPosition();
757   while (pos) {
758     CFX_ByteString key;
759     void* value;
760     m_Map.GetNextAssoc(pos, key, value);
761     if (!value)
762       return FALSE;
763     if (!static_cast<CPDF_Object*>(value)->IsIdentical(pOther->GetElement(key)))
764       return FALSE;
765   }
766   return TRUE;
767 }
768 void CPDF_Dictionary::SetAtInteger(const CFX_ByteStringC& key, int i) {
769   SetAt(key, new CPDF_Number(i));
770 }
771 void CPDF_Dictionary::SetAtName(const CFX_ByteStringC& key,
772                                 const CFX_ByteString& name) {
773   SetAt(key, new CPDF_Name(name));
774 }
775 void CPDF_Dictionary::SetAtString(const CFX_ByteStringC& key,
776                                   const CFX_ByteString& str) {
777   SetAt(key, new CPDF_String(str));
778 }
779 void CPDF_Dictionary::SetAtReference(const CFX_ByteStringC& key,
780                                      CPDF_IndirectObjects* pDoc,
781                                      FX_DWORD objnum) {
782   SetAt(key, new CPDF_Reference(pDoc, objnum));
783 }
784 void CPDF_Dictionary::AddReference(const CFX_ByteStringC& key,
785                                    CPDF_IndirectObjects* pDoc,
786                                    FX_DWORD objnum) {
787   AddValue(key, new CPDF_Reference(pDoc, objnum));
788 }
789 void CPDF_Dictionary::SetAtNumber(const CFX_ByteStringC& key, FX_FLOAT f) {
790   CPDF_Number* pNumber = new CPDF_Number;
791   pNumber->SetNumber(f);
792   SetAt(key, pNumber);
793 }
794 void CPDF_Dictionary::SetAtBoolean(const CFX_ByteStringC& key, FX_BOOL bValue) {
795   SetAt(key, new CPDF_Boolean(bValue));
796 }
797 void CPDF_Dictionary::SetAtRect(const CFX_ByteStringC& key,
798                                 const CFX_FloatRect& rect) {
799   CPDF_Array* pArray = new CPDF_Array;
800   pArray->AddNumber(rect.left);
801   pArray->AddNumber(rect.bottom);
802   pArray->AddNumber(rect.right);
803   pArray->AddNumber(rect.top);
804   SetAt(key, pArray);
805 }
806 void CPDF_Dictionary::SetAtMatrix(const CFX_ByteStringC& key,
807                                   const CFX_AffineMatrix& matrix) {
808   CPDF_Array* pArray = new CPDF_Array;
809   pArray->AddNumber16(matrix.a);
810   pArray->AddNumber16(matrix.b);
811   pArray->AddNumber16(matrix.c);
812   pArray->AddNumber16(matrix.d);
813   pArray->AddNumber(matrix.e);
814   pArray->AddNumber(matrix.f);
815   SetAt(key, pArray);
816 }
817 CPDF_Stream::CPDF_Stream(uint8_t* pData, FX_DWORD size, CPDF_Dictionary* pDict)
818     : CPDF_Object(PDFOBJ_STREAM) {
819   m_pDict = pDict;
820   m_dwSize = size;
821   m_GenNum = (FX_DWORD)-1;
822   m_pDataBuf = pData;
823   m_pCryptoHandler = NULL;
824 }
825 CPDF_Stream::~CPDF_Stream() {
826   if (m_GenNum == (FX_DWORD)-1) {
827     FX_Free(m_pDataBuf);
828   }
829   if (m_pDict) {
830     m_pDict->Release();
831   }
832 }
833 void CPDF_Stream::InitStream(CPDF_Dictionary* pDict) {
834   if (pDict) {
835     if (m_pDict) {
836       m_pDict->Release();
837     }
838     m_pDict = pDict;
839   }
840   if (m_GenNum == (FX_DWORD)-1) {
841     FX_Free(m_pDataBuf);
842   }
843   m_GenNum = 0;
844   m_pFile = NULL;
845   m_pCryptoHandler = NULL;
846   m_FileOffset = 0;
847 }
848 void CPDF_Stream::InitStream(uint8_t* pData,
849                              FX_DWORD size,
850                              CPDF_Dictionary* pDict) {
851   InitStream(pDict);
852   m_GenNum = (FX_DWORD)-1;
853   m_pDataBuf = FX_Alloc(uint8_t, size);
854   if (pData) {
855     FXSYS_memcpy(m_pDataBuf, pData, size);
856   }
857   m_dwSize = size;
858   if (m_pDict) {
859     m_pDict->SetAtInteger(FX_BSTRC("Length"), size);
860   }
861 }
862 void CPDF_Stream::SetData(const uint8_t* pData,
863                           FX_DWORD size,
864                           FX_BOOL bCompressed,
865                           FX_BOOL bKeepBuf) {
866   if (m_GenNum == (FX_DWORD)-1) {
867     FX_Free(m_pDataBuf);
868   } else {
869     m_GenNum = (FX_DWORD)-1;
870     m_pCryptoHandler = NULL;
871   }
872   if (bKeepBuf) {
873     m_pDataBuf = (uint8_t*)pData;
874   } else {
875     m_pDataBuf = FX_Alloc(uint8_t, size);
876     if (pData) {
877       FXSYS_memcpy(m_pDataBuf, pData, size);
878     }
879   }
880   m_dwSize = size;
881   if (m_pDict == NULL) {
882     m_pDict = new CPDF_Dictionary;
883   }
884   m_pDict->SetAtInteger(FX_BSTRC("Length"), size);
885   if (!bCompressed) {
886     m_pDict->RemoveAt(FX_BSTRC("Filter"));
887     m_pDict->RemoveAt(FX_BSTRC("DecodeParms"));
888   }
889 }
890 FX_BOOL CPDF_Stream::ReadRawData(FX_FILESIZE offset,
891                                  uint8_t* buf,
892                                  FX_DWORD size) const {
893   if ((m_GenNum != (FX_DWORD)-1) && m_pFile) {
894     return m_pFile->ReadBlock(buf, m_FileOffset + offset, size);
895   }
896   if (m_pDataBuf) {
897     FXSYS_memcpy(buf, m_pDataBuf + offset, size);
898   }
899   return TRUE;
900 }
901 void CPDF_Stream::InitStream(IFX_FileRead* pFile, CPDF_Dictionary* pDict) {
902   InitStream(pDict);
903   m_pFile = pFile;
904   m_dwSize = (FX_DWORD)pFile->GetSize();
905   if (m_pDict) {
906     m_pDict->SetAtInteger(FX_BSTRC("Length"), m_dwSize);
907   }
908 }
909
910 FX_BOOL CPDF_Stream::Identical(CPDF_Stream* pOther) const {
911   if (!m_pDict)
912     return pOther->m_pDict ? FALSE : TRUE;
913
914   if (!m_pDict->Identical(pOther->m_pDict)) {
915     return FALSE;
916   }
917   if (m_dwSize != pOther->m_dwSize) {
918     return FALSE;
919   }
920   if (m_GenNum != (FX_DWORD)-1 && pOther->m_GenNum != (FX_DWORD)-1) {
921     if (m_pFile == pOther->m_pFile && m_pFile == NULL) {
922       return TRUE;
923     }
924     if (!m_pFile || !pOther->m_pFile) {
925       return FALSE;
926     }
927     uint8_t srcBuf[1024];
928     uint8_t destBuf[1024];
929     FX_DWORD size = m_dwSize;
930     FX_DWORD srcOffset = m_FileOffset;
931     FX_DWORD destOffset = pOther->m_FileOffset;
932     if (m_pFile == pOther->m_pFile && srcOffset == destOffset) {
933       return TRUE;
934     }
935     while (size > 0) {
936       FX_DWORD actualSize = size > 1024 ? 1024 : size;
937       m_pFile->ReadBlock(srcBuf, srcOffset, actualSize);
938       pOther->m_pFile->ReadBlock(destBuf, destOffset, actualSize);
939       if (FXSYS_memcmp(srcBuf, destBuf, actualSize) != 0) {
940         return FALSE;
941       }
942       size -= actualSize;
943       srcOffset += actualSize;
944       destOffset += actualSize;
945     }
946     return TRUE;
947   }
948   if (m_GenNum != (FX_DWORD)-1 || pOther->m_GenNum != (FX_DWORD)-1) {
949     IFX_FileRead* pFile = NULL;
950     uint8_t* pBuf = NULL;
951     FX_DWORD offset = 0;
952     if (pOther->m_GenNum != (FX_DWORD)-1) {
953       pFile = pOther->m_pFile;
954       pBuf = m_pDataBuf;
955       offset = pOther->m_FileOffset;
956     } else if (m_GenNum != (FX_DWORD)-1) {
957       pFile = m_pFile;
958       pBuf = pOther->m_pDataBuf;
959       offset = m_FileOffset;
960     }
961     if (NULL == pBuf) {
962       return FALSE;
963     }
964     uint8_t srcBuf[1024];
965     FX_DWORD size = m_dwSize;
966     while (size > 0) {
967       FX_DWORD actualSize = std::min(size, 1024U);
968       pFile->ReadBlock(srcBuf, offset, actualSize);
969       if (FXSYS_memcmp(srcBuf, pBuf, actualSize) != 0) {
970         return FALSE;
971       }
972       pBuf += actualSize;
973       size -= actualSize;
974       offset += actualSize;
975     }
976     return TRUE;
977   }
978   return FXSYS_memcmp(m_pDataBuf, pOther->m_pDataBuf, m_dwSize) == 0;
979 }
980
981 CPDF_StreamAcc::CPDF_StreamAcc() {
982   m_bNewBuf = FALSE;
983   m_pData = NULL;
984   m_dwSize = 0;
985   m_pImageParam = NULL;
986   m_pStream = NULL;
987   m_pSrcData = NULL;
988 }
989 void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream,
990                                  FX_BOOL bRawAccess,
991                                  FX_DWORD estimated_size,
992                                  FX_BOOL bImageAcc) {
993   if (!pStream)
994     return;
995
996   m_pStream = pStream;
997   if (pStream->IsMemoryBased() &&
998       (!pStream->GetDict()->KeyExist(FX_BSTRC("Filter")) || bRawAccess)) {
999     m_dwSize = pStream->m_dwSize;
1000     m_pData = (uint8_t*)pStream->m_pDataBuf;
1001     return;
1002   }
1003   uint8_t* pSrcData;
1004   FX_DWORD dwSrcSize = pStream->m_dwSize;
1005   if (dwSrcSize == 0)
1006     return;
1007
1008   if (!pStream->IsMemoryBased()) {
1009     pSrcData = m_pSrcData = FX_Alloc(uint8_t, dwSrcSize);
1010     if (!pStream->ReadRawData(0, pSrcData, dwSrcSize))
1011       return;
1012   } else {
1013     pSrcData = pStream->m_pDataBuf;
1014   }
1015   uint8_t* pDecryptedData;
1016   FX_DWORD dwDecryptedSize;
1017   if (pStream->m_pCryptoHandler) {
1018     CFX_BinaryBuf dest_buf;
1019     dest_buf.EstimateSize(pStream->m_pCryptoHandler->DecryptGetSize(dwSrcSize));
1020     void* context = pStream->m_pCryptoHandler->DecryptStart(
1021         pStream->GetObjNum(), pStream->m_GenNum);
1022     pStream->m_pCryptoHandler->DecryptStream(context, pSrcData, dwSrcSize,
1023                                              dest_buf);
1024     pStream->m_pCryptoHandler->DecryptFinish(context, dest_buf);
1025     pDecryptedData = dest_buf.GetBuffer();
1026     dwDecryptedSize = dest_buf.GetSize();
1027     dest_buf.DetachBuffer();
1028   } else {
1029     pDecryptedData = pSrcData;
1030     dwDecryptedSize = dwSrcSize;
1031   }
1032   if (!pStream->GetDict()->KeyExist(FX_BSTRC("Filter")) || bRawAccess) {
1033     m_pData = pDecryptedData;
1034     m_dwSize = dwDecryptedSize;
1035   } else {
1036     FX_BOOL bRet = PDF_DataDecode(
1037         pDecryptedData, dwDecryptedSize, m_pStream->GetDict(), m_pData,
1038         m_dwSize, m_ImageDecoder, m_pImageParam, estimated_size, bImageAcc);
1039     if (!bRet) {
1040       m_pData = pDecryptedData;
1041       m_dwSize = dwDecryptedSize;
1042     }
1043   }
1044   if (pSrcData != pStream->m_pDataBuf && pSrcData != m_pData) {
1045     FX_Free(pSrcData);
1046   }
1047   if (pDecryptedData != pSrcData && pDecryptedData != m_pData) {
1048     FX_Free(pDecryptedData);
1049   }
1050   m_pSrcData = NULL;
1051   m_bNewBuf = m_pData != pStream->m_pDataBuf;
1052 }
1053 CPDF_StreamAcc::~CPDF_StreamAcc() {
1054   if (m_bNewBuf) {
1055     FX_Free(m_pData);
1056   }
1057   FX_Free(m_pSrcData);
1058 }
1059 const uint8_t* CPDF_StreamAcc::GetData() const {
1060   if (m_bNewBuf) {
1061     return m_pData;
1062   }
1063   if (!m_pStream) {
1064     return NULL;
1065   }
1066   return m_pStream->m_pDataBuf;
1067 }
1068 FX_DWORD CPDF_StreamAcc::GetSize() const {
1069   if (m_bNewBuf) {
1070     return m_dwSize;
1071   }
1072   if (!m_pStream) {
1073     return 0;
1074   }
1075   return m_pStream->m_dwSize;
1076 }
1077 uint8_t* CPDF_StreamAcc::DetachData() {
1078   if (m_bNewBuf) {
1079     uint8_t* p = m_pData;
1080     m_pData = NULL;
1081     m_dwSize = 0;
1082     return p;
1083   }
1084   uint8_t* p = FX_Alloc(uint8_t, m_dwSize);
1085   FXSYS_memcpy(p, m_pData, m_dwSize);
1086   return p;
1087 }
1088 void CPDF_Reference::SetRef(CPDF_IndirectObjects* pDoc, FX_DWORD objnum) {
1089   m_pObjList = pDoc;
1090   m_RefObjNum = objnum;
1091 }
1092 CPDF_IndirectObjects::CPDF_IndirectObjects(CPDF_Parser* pParser) {
1093   m_pParser = pParser;
1094   m_IndirectObjs.InitHashTable(1013);
1095   if (pParser) {
1096     m_LastObjNum = m_pParser->GetLastObjNum();
1097   } else {
1098     m_LastObjNum = 0;
1099   }
1100 }
1101 CPDF_IndirectObjects::~CPDF_IndirectObjects() {
1102   FX_POSITION pos = m_IndirectObjs.GetStartPosition();
1103   while (pos) {
1104     void* key;
1105     void* value;
1106     m_IndirectObjs.GetNextAssoc(pos, key, value);
1107     static_cast<CPDF_Object*>(value)->Destroy();
1108   }
1109 }
1110 CPDF_Object* CPDF_IndirectObjects::GetIndirectObject(
1111     FX_DWORD objnum,
1112     struct PARSE_CONTEXT* pContext) {
1113   if (objnum == 0)
1114     return nullptr;
1115   void* value;
1116   if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1117     CPDF_Object* pValue = static_cast<CPDF_Object*>(value);
1118     if (pValue->GetObjNum() == -1)
1119       return nullptr;
1120     return pValue;
1121   }
1122
1123   CPDF_Object* pObj = nullptr;
1124   if (m_pParser)
1125     pObj = m_pParser->ParseIndirectObject(this, objnum, pContext);
1126   if (!pObj)
1127     return nullptr;
1128
1129   pObj->m_ObjNum = objnum;
1130   if (m_LastObjNum < objnum) {
1131     m_LastObjNum = objnum;
1132   }
1133   if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1134     if (value)
1135       static_cast<CPDF_Object*>(value)->Destroy();
1136   }
1137   m_IndirectObjs.SetAt((void*)(uintptr_t)objnum, pObj);
1138   return pObj;
1139 }
1140 int CPDF_IndirectObjects::GetIndirectType(FX_DWORD objnum) {
1141   void* value;
1142   if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value))
1143     return static_cast<CPDF_Object*>(value)->GetType();
1144
1145   if (m_pParser) {
1146     PARSE_CONTEXT context;
1147     FXSYS_memset(&context, 0, sizeof(PARSE_CONTEXT));
1148     context.m_Flags = PDFPARSE_TYPEONLY;
1149     return (int)(uintptr_t)m_pParser->ParseIndirectObject(this, objnum,
1150                                                           &context);
1151   }
1152   return 0;
1153 }
1154 FX_DWORD CPDF_IndirectObjects::AddIndirectObject(CPDF_Object* pObj) {
1155   if (pObj->m_ObjNum) {
1156     return pObj->m_ObjNum;
1157   }
1158   m_LastObjNum++;
1159   m_IndirectObjs.SetAt((void*)(uintptr_t)m_LastObjNum, pObj);
1160   pObj->m_ObjNum = m_LastObjNum;
1161   return m_LastObjNum;
1162 }
1163 void CPDF_IndirectObjects::ReleaseIndirectObject(FX_DWORD objnum) {
1164   void* value;
1165   if (!m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value))
1166     return;
1167   CPDF_Object* pValue = static_cast<CPDF_Object*>(value);
1168   if (pValue->GetObjNum() == -1)
1169     return;
1170   pValue->Destroy();
1171   m_IndirectObjs.RemoveKey((void*)(uintptr_t)objnum);
1172 }
1173 void CPDF_IndirectObjects::InsertIndirectObject(FX_DWORD objnum,
1174                                                 CPDF_Object* pObj) {
1175   if (objnum == 0 || pObj == NULL) {
1176     return;
1177   }
1178   void* value = NULL;
1179   if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, value)) {
1180     if (value) {
1181       CPDF_Object* pValue = static_cast<CPDF_Object*>(value);
1182       if (pObj->GetGenNum() <= pValue->GetGenNum())
1183         return;
1184       pValue->Destroy();
1185     }
1186   }
1187   pObj->m_ObjNum = objnum;
1188   m_IndirectObjs.SetAt((void*)(uintptr_t)objnum, pObj);
1189   if (m_LastObjNum < objnum) {
1190     m_LastObjNum = objnum;
1191   }
1192 }
1193 FX_DWORD CPDF_IndirectObjects::GetLastObjNum() const {
1194   return m_LastObjNum;
1195 }