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