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