Home | History | Annotate | Download | only in parser
      1 // Copyright 2016 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/fpdfapi/parser/cpdf_dictionary.h"
      8 
      9 #include <set>
     10 #include <utility>
     11 
     12 #include "core/fpdfapi/parser/cpdf_array.h"
     13 #include "core/fpdfapi/parser/cpdf_boolean.h"
     14 #include "core/fpdfapi/parser/cpdf_crypto_handler.h"
     15 #include "core/fpdfapi/parser/cpdf_name.h"
     16 #include "core/fpdfapi/parser/cpdf_number.h"
     17 #include "core/fpdfapi/parser/cpdf_reference.h"
     18 #include "core/fpdfapi/parser/cpdf_stream.h"
     19 #include "core/fpdfapi/parser/cpdf_string.h"
     20 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
     21 #include "core/fxcrt/fx_stream.h"
     22 #include "third_party/base/logging.h"
     23 #include "third_party/base/stl_util.h"
     24 
     25 CPDF_Dictionary::CPDF_Dictionary()
     26     : CPDF_Dictionary(WeakPtr<ByteStringPool>()) {}
     27 
     28 CPDF_Dictionary::CPDF_Dictionary(const WeakPtr<ByteStringPool>& pPool)
     29     : m_pPool(pPool) {}
     30 
     31 CPDF_Dictionary::~CPDF_Dictionary() {
     32   // Mark the object as deleted so that it will not be deleted again,
     33   // and break cyclic references.
     34   m_ObjNum = kInvalidObjNum;
     35   for (auto& it : m_Map) {
     36     if (it.second && it.second->GetObjNum() == kInvalidObjNum)
     37       it.second.release();
     38   }
     39 }
     40 
     41 CPDF_Object::Type CPDF_Dictionary::GetType() const {
     42   return DICTIONARY;
     43 }
     44 
     45 CPDF_Dictionary* CPDF_Dictionary::GetDict() const {
     46   // The method should be made non-const if we want to not be const.
     47   // See bug #234.
     48   return const_cast<CPDF_Dictionary*>(this);
     49 }
     50 
     51 bool CPDF_Dictionary::IsDictionary() const {
     52   return true;
     53 }
     54 
     55 CPDF_Dictionary* CPDF_Dictionary::AsDictionary() {
     56   return this;
     57 }
     58 
     59 const CPDF_Dictionary* CPDF_Dictionary::AsDictionary() const {
     60   return this;
     61 }
     62 
     63 std::unique_ptr<CPDF_Object> CPDF_Dictionary::Clone() const {
     64   return CloneObjectNonCyclic(false);
     65 }
     66 
     67 std::unique_ptr<CPDF_Object> CPDF_Dictionary::CloneNonCyclic(
     68     bool bDirect,
     69     std::set<const CPDF_Object*>* pVisited) const {
     70   pVisited->insert(this);
     71   auto pCopy = pdfium::MakeUnique<CPDF_Dictionary>(m_pPool);
     72   for (const auto& it : *this) {
     73     if (!pdfium::ContainsKey(*pVisited, it.second.get())) {
     74       std::set<const CPDF_Object*> visited(*pVisited);
     75       if (auto obj = it.second->CloneNonCyclic(bDirect, &visited))
     76         pCopy->m_Map.insert(std::make_pair(it.first, std::move(obj)));
     77     }
     78   }
     79   return std::move(pCopy);
     80 }
     81 
     82 CPDF_Object* CPDF_Dictionary::GetObjectFor(const ByteString& key) const {
     83   auto it = m_Map.find(key);
     84   return it != m_Map.end() ? it->second.get() : nullptr;
     85 }
     86 
     87 CPDF_Object* CPDF_Dictionary::GetDirectObjectFor(const ByteString& key) const {
     88   CPDF_Object* p = GetObjectFor(key);
     89   return p ? p->GetDirect() : nullptr;
     90 }
     91 
     92 ByteString CPDF_Dictionary::GetStringFor(const ByteString& key) const {
     93   CPDF_Object* p = GetObjectFor(key);
     94   return p ? p->GetString() : ByteString();
     95 }
     96 
     97 WideString CPDF_Dictionary::GetUnicodeTextFor(const ByteString& key) const {
     98   CPDF_Object* p = GetObjectFor(key);
     99   if (CPDF_Reference* pRef = ToReference(p))
    100     p = pRef->GetDirect();
    101   return p ? p->GetUnicodeText() : WideString();
    102 }
    103 
    104 ByteString CPDF_Dictionary::GetStringFor(const ByteString& key,
    105                                          const ByteString& def) const {
    106   CPDF_Object* p = GetObjectFor(key);
    107   return p ? p->GetString() : ByteString(def);
    108 }
    109 
    110 int CPDF_Dictionary::GetIntegerFor(const ByteString& key) const {
    111   CPDF_Object* p = GetObjectFor(key);
    112   return p ? p->GetInteger() : 0;
    113 }
    114 
    115 int CPDF_Dictionary::GetIntegerFor(const ByteString& key, int def) const {
    116   CPDF_Object* p = GetObjectFor(key);
    117   return p ? p->GetInteger() : def;
    118 }
    119 
    120 float CPDF_Dictionary::GetNumberFor(const ByteString& key) const {
    121   CPDF_Object* p = GetObjectFor(key);
    122   return p ? p->GetNumber() : 0;
    123 }
    124 
    125 bool CPDF_Dictionary::GetBooleanFor(const ByteString& key,
    126                                     bool bDefault) const {
    127   CPDF_Object* p = GetObjectFor(key);
    128   return ToBoolean(p) ? p->GetInteger() != 0 : bDefault;
    129 }
    130 
    131 CPDF_Dictionary* CPDF_Dictionary::GetDictFor(const ByteString& key) const {
    132   CPDF_Object* p = GetDirectObjectFor(key);
    133   if (!p)
    134     return nullptr;
    135   if (CPDF_Dictionary* pDict = p->AsDictionary())
    136     return pDict;
    137   if (CPDF_Stream* pStream = p->AsStream())
    138     return pStream->GetDict();
    139   return nullptr;
    140 }
    141 
    142 CPDF_Array* CPDF_Dictionary::GetArrayFor(const ByteString& key) const {
    143   return ToArray(GetDirectObjectFor(key));
    144 }
    145 
    146 CPDF_Stream* CPDF_Dictionary::GetStreamFor(const ByteString& key) const {
    147   return ToStream(GetDirectObjectFor(key));
    148 }
    149 
    150 CFX_FloatRect CPDF_Dictionary::GetRectFor(const ByteString& key) const {
    151   CFX_FloatRect rect;
    152   CPDF_Array* pArray = GetArrayFor(key);
    153   if (pArray)
    154     rect = pArray->GetRect();
    155   return rect;
    156 }
    157 
    158 CFX_Matrix CPDF_Dictionary::GetMatrixFor(const ByteString& key) const {
    159   CFX_Matrix matrix;
    160   CPDF_Array* pArray = GetArrayFor(key);
    161   if (pArray)
    162     matrix = pArray->GetMatrix();
    163   return matrix;
    164 }
    165 
    166 bool CPDF_Dictionary::KeyExist(const ByteString& key) const {
    167   return pdfium::ContainsKey(m_Map, key);
    168 }
    169 
    170 bool CPDF_Dictionary::IsSignatureDict() const {
    171   return CPDF_CryptoHandler::IsSignatureDictionary(this);
    172 }
    173 
    174 CPDF_Object* CPDF_Dictionary::SetFor(const ByteString& key,
    175                                      std::unique_ptr<CPDF_Object> pObj) {
    176   if (!pObj) {
    177     m_Map.erase(key);
    178     return nullptr;
    179   }
    180   ASSERT(pObj->IsInline());
    181   CPDF_Object* pRet = pObj.get();
    182   m_Map[MaybeIntern(key)] = std::move(pObj);
    183   return pRet;
    184 }
    185 
    186 void CPDF_Dictionary::ConvertToIndirectObjectFor(
    187     const ByteString& key,
    188     CPDF_IndirectObjectHolder* pHolder) {
    189   auto it = m_Map.find(key);
    190   if (it == m_Map.end() || it->second->IsReference())
    191     return;
    192 
    193   CPDF_Object* pObj = pHolder->AddIndirectObject(std::move(it->second));
    194   it->second = pdfium::MakeUnique<CPDF_Reference>(pHolder, pObj->GetObjNum());
    195 }
    196 
    197 std::unique_ptr<CPDF_Object> CPDF_Dictionary::RemoveFor(const ByteString& key) {
    198   std::unique_ptr<CPDF_Object> result;
    199   auto it = m_Map.find(key);
    200   if (it != m_Map.end()) {
    201     result = std::move(it->second);
    202     m_Map.erase(it);
    203   }
    204   return result;
    205 }
    206 
    207 void CPDF_Dictionary::ReplaceKey(const ByteString& oldkey,
    208                                  const ByteString& newkey) {
    209   auto old_it = m_Map.find(oldkey);
    210   if (old_it == m_Map.end())
    211     return;
    212 
    213   auto new_it = m_Map.find(newkey);
    214   if (new_it == old_it)
    215     return;
    216 
    217   m_Map[MaybeIntern(newkey)] = std::move(old_it->second);
    218   m_Map.erase(old_it);
    219 }
    220 
    221 void CPDF_Dictionary::SetRectFor(const ByteString& key,
    222                                  const CFX_FloatRect& rect) {
    223   CPDF_Array* pArray = SetNewFor<CPDF_Array>(key);
    224   pArray->AddNew<CPDF_Number>(rect.left);
    225   pArray->AddNew<CPDF_Number>(rect.bottom);
    226   pArray->AddNew<CPDF_Number>(rect.right);
    227   pArray->AddNew<CPDF_Number>(rect.top);
    228 }
    229 
    230 void CPDF_Dictionary::SetMatrixFor(const ByteString& key,
    231                                    const CFX_Matrix& matrix) {
    232   CPDF_Array* pArray = SetNewFor<CPDF_Array>(key);
    233   pArray->AddNew<CPDF_Number>(matrix.a);
    234   pArray->AddNew<CPDF_Number>(matrix.b);
    235   pArray->AddNew<CPDF_Number>(matrix.c);
    236   pArray->AddNew<CPDF_Number>(matrix.d);
    237   pArray->AddNew<CPDF_Number>(matrix.e);
    238   pArray->AddNew<CPDF_Number>(matrix.f);
    239 }
    240 
    241 ByteString CPDF_Dictionary::MaybeIntern(const ByteString& str) {
    242   return m_pPool ? m_pPool->Intern(str) : str;
    243 }
    244 
    245 bool CPDF_Dictionary::WriteTo(IFX_ArchiveStream* archive) const {
    246   if (!archive->WriteString("<<"))
    247     return false;
    248 
    249   for (const auto& it : *this) {
    250     const ByteString& key = it.first;
    251     CPDF_Object* pValue = it.second.get();
    252     if (!archive->WriteString("/") ||
    253         !archive->WriteString(PDF_NameEncode(key).AsStringView())) {
    254       return false;
    255     }
    256 
    257     if (!pValue->IsInline()) {
    258       if (!archive->WriteString(" ") ||
    259           !archive->WriteDWord(pValue->GetObjNum()) ||
    260           !archive->WriteString(" 0 R")) {
    261         return false;
    262       }
    263     } else if (!pValue->WriteTo(archive)) {
    264       return false;
    265     }
    266   }
    267   return archive->WriteString(">>");
    268 }
    269