Home | History | Annotate | Download | only in fpdf_parser
      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 
     24 void CPDF_Object::Release() {
     25   if (m_ObjNum) {
     26     return;
     27   }
     28   Destroy();
     29 }
     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 }
     51 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 }
     73 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 
     96 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 
    113 FX_FLOAT CPDF_Object::GetNumber16() const {
    114   return GetNumber();
    115 }
    116 
    117 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 
    142 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 
    166 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 
    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 }
    189 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 }
    195 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 
    230 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 
    239 CPDF_Object* CPDF_Object::Clone(FX_BOOL bDirect) const {
    240   std::set<FX_DWORD> visited;
    241   return CloneInternal(bDirect, &visited);
    242 }
    243 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 }
    305 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 }
    311 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 }
    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 
    336 CPDF_Array* CPDF_Object::AsArray() {
    337   return IsArray() ? static_cast<CPDF_Array*>(this) : nullptr;
    338 }
    339 
    340 const CPDF_Array* CPDF_Object::AsArray() const {
    341   return IsArray() ? static_cast<const CPDF_Array*>(this) : nullptr;
    342 }
    343 
    344 CPDF_Boolean* CPDF_Object::AsBoolean() {
    345   return IsBoolean() ? static_cast<CPDF_Boolean*>(this) : nullptr;
    346 }
    347 
    348 const CPDF_Boolean* CPDF_Object::AsBoolean() const {
    349   return IsBoolean() ? static_cast<const CPDF_Boolean*>(this) : nullptr;
    350 }
    351 
    352 CPDF_Dictionary* CPDF_Object::AsDictionary() {
    353   return IsDictionary() ? static_cast<CPDF_Dictionary*>(this) : nullptr;
    354 }
    355 
    356 const CPDF_Dictionary* CPDF_Object::AsDictionary() const {
    357   return IsDictionary() ? static_cast<const CPDF_Dictionary*>(this) : nullptr;
    358 }
    359 
    360 CPDF_Name* CPDF_Object::AsName() {
    361   return IsName() ? static_cast<CPDF_Name*>(this) : nullptr;
    362 }
    363 
    364 const CPDF_Name* CPDF_Object::AsName() const {
    365   return IsName() ? static_cast<const CPDF_Name*>(this) : nullptr;
    366 }
    367 
    368 CPDF_Number* CPDF_Object::AsNumber() {
    369   return IsNumber() ? static_cast<CPDF_Number*>(this) : nullptr;
    370 }
    371 
    372 const CPDF_Number* CPDF_Object::AsNumber() const {
    373   return IsNumber() ? static_cast<const CPDF_Number*>(this) : nullptr;
    374 }
    375 
    376 CPDF_Reference* CPDF_Object::AsReference() {
    377   return IsReference() ? static_cast<CPDF_Reference*>(this) : nullptr;
    378 }
    379 
    380 const CPDF_Reference* CPDF_Object::AsReference() const {
    381   return IsReference() ? static_cast<const CPDF_Reference*>(this) : nullptr;
    382 }
    383 
    384 CPDF_Stream* CPDF_Object::AsStream() {
    385   return IsStream() ? static_cast<CPDF_Stream*>(this) : nullptr;
    386 }
    387 
    388 const CPDF_Stream* CPDF_Object::AsStream() const {
    389   return IsStream() ? static_cast<const CPDF_Stream*>(this) : nullptr;
    390 }
    391 
    392 CPDF_String* CPDF_Object::AsString() {
    393   return IsString() ? static_cast<CPDF_String*>(this) : nullptr;
    394 }
    395 
    396 const CPDF_String* CPDF_Object::AsString() const {
    397   return IsString() ? static_cast<const CPDF_String*>(this) : nullptr;
    398 }
    399 
    400 CPDF_Number::CPDF_Number(int value)
    401     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(TRUE), m_Integer(value) {}
    402 
    403 CPDF_Number::CPDF_Number(FX_FLOAT value)
    404     : CPDF_Object(PDFOBJ_NUMBER), m_bInteger(FALSE), m_Float(value) {}
    405 
    406 CPDF_Number::CPDF_Number(const CFX_ByteStringC& str)
    407     : CPDF_Object(PDFOBJ_NUMBER) {
    408   FX_atonum(str, m_bInteger, &m_Integer);
    409 }
    410 
    411 void CPDF_Number::SetString(const CFX_ByteStringC& str) {
    412   FX_atonum(str, m_bInteger, &m_Integer);
    413 }
    414 FX_BOOL CPDF_Number::Identical(CPDF_Number* pOther) const {
    415   return m_bInteger == pOther->m_bInteger && m_Integer == pOther->m_Integer;
    416 }
    417 CFX_ByteString CPDF_Number::GetString() const {
    418   return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED)
    419                     : CFX_ByteString::FormatFloat(m_Float);
    420 }
    421 void CPDF_Number::SetNumber(FX_FLOAT value) {
    422   m_bInteger = FALSE;
    423   m_Float = value;
    424 }
    425 CPDF_String::CPDF_String(const CFX_WideString& str)
    426     : CPDF_Object(PDFOBJ_STRING), m_bHex(FALSE) {
    427   m_String = PDF_EncodeText(str);
    428 }
    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 }
    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 }
    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 }
    457 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 }
    462 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 }
    467 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 }
    472 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 }
    477 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 }
    482 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 }
    487 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 }
    497 CPDF_Stream* CPDF_Array::GetStream(FX_DWORD i) const {
    498   return ToStream(GetElementValue(i));
    499 }
    500 CPDF_Array* CPDF_Array::GetArray(FX_DWORD i) const {
    501   return ToArray(GetElementValue(i));
    502 }
    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 }
    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 }
    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 }
    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 }
    547 void CPDF_Array::AddName(const CFX_ByteString& str) {
    548   ASSERT(IsArray());
    549   Add(new CPDF_Name(str));
    550 }
    551 void CPDF_Array::AddString(const CFX_ByteString& str) {
    552   ASSERT(IsArray());
    553   Add(new CPDF_String(str, FALSE));
    554 }
    555 void CPDF_Array::AddInteger(int i) {
    556   ASSERT(IsArray());
    557   Add(new CPDF_Number(i));
    558 }
    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 }
    565 void CPDF_Array::AddReference(CPDF_IndirectObjectHolder* pDoc,
    566                               FX_DWORD objnum) {
    567   ASSERT(IsArray());
    568   Add(new CPDF_Reference(pDoc, objnum));
    569 }
    570 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 }
    580 CPDF_Dictionary::~CPDF_Dictionary() {
    581   for (const auto& it : m_Map) {
    582     it.second->Release();
    583   }
    584 }
    585 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 }
    591 CPDF_Object* CPDF_Dictionary::GetElementValue(
    592     const CFX_ByteStringC& key) const {
    593   CPDF_Object* p = GetElement(key);
    594   return p ? p->GetDirect() : nullptr;
    595 }
    596 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 }
    603 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 }
    611 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 }
    618 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 }
    626 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 }
    635 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 }
    642 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 }
    649 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 }
    656 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 }
    663 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 }
    673 CPDF_Array* CPDF_Dictionary::GetArray(const CFX_ByteStringC& key) const {
    674   return ToArray(GetElementValue(key));
    675 }
    676 CPDF_Stream* CPDF_Dictionary::GetStream(const CFX_ByteStringC& key) const {
    677   return ToStream(GetElementValue(key));
    678 }
    679 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 }
    686 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 }
    693 FX_BOOL CPDF_Dictionary::KeyExist(const CFX_ByteStringC& key) const {
    694   return pdfium::ContainsKey(m_Map, key);
    695 }
    696 
    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 }
    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 }
    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 }
    748 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 }
    762 void CPDF_Dictionary::SetAtInteger(const CFX_ByteStringC& key, int i) {
    763   SetAt(key, new CPDF_Number(i));
    764 }
    765 void CPDF_Dictionary::SetAtName(const CFX_ByteStringC& key,
    766                                 const CFX_ByteString& name) {
    767   SetAt(key, new CPDF_Name(name));
    768 }
    769 void CPDF_Dictionary::SetAtString(const CFX_ByteStringC& key,
    770                                   const CFX_ByteString& str) {
    771   SetAt(key, new CPDF_String(str, FALSE));
    772 }
    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 }
    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 }
    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 }
    788 void CPDF_Dictionary::SetAtBoolean(const CFX_ByteStringC& key, FX_BOOL bValue) {
    789   SetAt(key, new CPDF_Boolean(bValue));
    790 }
    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 }
    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 }
    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 
    818 CPDF_Stream::~CPDF_Stream() {
    819   if (IsMemoryBased())
    820     FX_Free(m_pDataBuf);
    821 
    822   if (m_pDict)
    823     m_pDict->Release();
    824 }
    825 
    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 
    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 }
    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 }
    878 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 }
    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 
    898 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 
    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 }
    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 }
   1023 CPDF_StreamAcc::~CPDF_StreamAcc() {
   1024   if (m_bNewBuf) {
   1025     FX_Free(m_pData);
   1026   }
   1027   FX_Free(m_pSrcData);
   1028 }
   1029 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 }
   1038 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 }
   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 }
   1058 void CPDF_Reference::SetRef(CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum) {
   1059   m_pObjList = pDoc;
   1060   m_RefObjNum = objnum;
   1061 }
   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 }
   1067 CPDF_IndirectObjectHolder::~CPDF_IndirectObjectHolder() {
   1068   for (const auto& pair : m_IndirectObjs) {
   1069     pair.second->Destroy();
   1070   }
   1071 }
   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 }
   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 }
   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 }
   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 }
   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