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