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_name.h"
15 #include "core/fpdfapi/parser/cpdf_number.h"
16 #include "core/fpdfapi/parser/cpdf_reference.h"
17 #include "core/fpdfapi/parser/cpdf_stream.h"
18 #include "core/fpdfapi/parser/cpdf_string.h"
19 #include "third_party/base/logging.h"
20 #include "third_party/base/stl_util.h"
21
CPDF_Dictionary()22 CPDF_Dictionary::CPDF_Dictionary()
23 : CPDF_Dictionary(CFX_WeakPtr<CFX_ByteStringPool>()) {}
24
CPDF_Dictionary(const CFX_WeakPtr<CFX_ByteStringPool> & pPool)25 CPDF_Dictionary::CPDF_Dictionary(const CFX_WeakPtr<CFX_ByteStringPool>& pPool)
26 : m_pPool(pPool) {}
27
~CPDF_Dictionary()28 CPDF_Dictionary::~CPDF_Dictionary() {
29 // Mark the object as deleted so that it will not be deleted again,
30 // and break cyclic references.
31 m_ObjNum = kInvalidObjNum;
32 for (auto& it : m_Map) {
33 if (it.second && it.second->GetObjNum() == kInvalidObjNum)
34 it.second.release();
35 }
36 }
37
GetType() const38 CPDF_Object::Type CPDF_Dictionary::GetType() const {
39 return DICTIONARY;
40 }
41
GetDict() const42 CPDF_Dictionary* CPDF_Dictionary::GetDict() const {
43 // The method should be made non-const if we want to not be const.
44 // See bug #234.
45 return const_cast<CPDF_Dictionary*>(this);
46 }
47
IsDictionary() const48 bool CPDF_Dictionary::IsDictionary() const {
49 return true;
50 }
51
AsDictionary()52 CPDF_Dictionary* CPDF_Dictionary::AsDictionary() {
53 return this;
54 }
55
AsDictionary() const56 const CPDF_Dictionary* CPDF_Dictionary::AsDictionary() const {
57 return this;
58 }
59
Clone() const60 std::unique_ptr<CPDF_Object> CPDF_Dictionary::Clone() const {
61 return CloneObjectNonCyclic(false);
62 }
63
CloneNonCyclic(bool bDirect,std::set<const CPDF_Object * > * pVisited) const64 std::unique_ptr<CPDF_Object> CPDF_Dictionary::CloneNonCyclic(
65 bool bDirect,
66 std::set<const CPDF_Object*>* pVisited) const {
67 pVisited->insert(this);
68 auto pCopy = pdfium::MakeUnique<CPDF_Dictionary>(m_pPool);
69 for (const auto& it : *this) {
70 if (!pdfium::ContainsKey(*pVisited, it.second.get())) {
71 pCopy->m_Map.insert(std::make_pair(
72 it.first, it.second->CloneNonCyclic(bDirect, pVisited)));
73 }
74 }
75 return std::move(pCopy);
76 }
77
GetObjectFor(const CFX_ByteString & key) const78 CPDF_Object* CPDF_Dictionary::GetObjectFor(const CFX_ByteString& key) const {
79 auto it = m_Map.find(key);
80 return it != m_Map.end() ? it->second.get() : nullptr;
81 }
82
GetDirectObjectFor(const CFX_ByteString & key) const83 CPDF_Object* CPDF_Dictionary::GetDirectObjectFor(
84 const CFX_ByteString& key) const {
85 CPDF_Object* p = GetObjectFor(key);
86 return p ? p->GetDirect() : nullptr;
87 }
88
GetStringFor(const CFX_ByteString & key) const89 CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key) const {
90 CPDF_Object* p = GetObjectFor(key);
91 return p ? p->GetString() : CFX_ByteString();
92 }
93
GetUnicodeTextFor(const CFX_ByteString & key) const94 CFX_WideString CPDF_Dictionary::GetUnicodeTextFor(
95 const CFX_ByteString& key) const {
96 CPDF_Object* p = GetObjectFor(key);
97 if (CPDF_Reference* pRef = ToReference(p))
98 p = pRef->GetDirect();
99 return p ? p->GetUnicodeText() : CFX_WideString();
100 }
101
GetStringFor(const CFX_ByteString & key,const CFX_ByteString & def) const102 CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key,
103 const CFX_ByteString& def) const {
104 CPDF_Object* p = GetObjectFor(key);
105 return p ? p->GetString() : CFX_ByteString(def);
106 }
107
GetIntegerFor(const CFX_ByteString & key) const108 int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key) const {
109 CPDF_Object* p = GetObjectFor(key);
110 return p ? p->GetInteger() : 0;
111 }
112
GetIntegerFor(const CFX_ByteString & key,int def) const113 int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key, int def) const {
114 CPDF_Object* p = GetObjectFor(key);
115 return p ? p->GetInteger() : def;
116 }
117
GetNumberFor(const CFX_ByteString & key) const118 FX_FLOAT CPDF_Dictionary::GetNumberFor(const CFX_ByteString& key) const {
119 CPDF_Object* p = GetObjectFor(key);
120 return p ? p->GetNumber() : 0;
121 }
122
GetBooleanFor(const CFX_ByteString & key,bool bDefault) const123 bool CPDF_Dictionary::GetBooleanFor(const CFX_ByteString& key,
124 bool bDefault) const {
125 CPDF_Object* p = GetObjectFor(key);
126 return ToBoolean(p) ? p->GetInteger() != 0 : bDefault;
127 }
128
GetDictFor(const CFX_ByteString & key) const129 CPDF_Dictionary* CPDF_Dictionary::GetDictFor(const CFX_ByteString& key) const {
130 CPDF_Object* p = GetDirectObjectFor(key);
131 if (!p)
132 return nullptr;
133 if (CPDF_Dictionary* pDict = p->AsDictionary())
134 return pDict;
135 if (CPDF_Stream* pStream = p->AsStream())
136 return pStream->GetDict();
137 return nullptr;
138 }
139
GetArrayFor(const CFX_ByteString & key) const140 CPDF_Array* CPDF_Dictionary::GetArrayFor(const CFX_ByteString& key) const {
141 return ToArray(GetDirectObjectFor(key));
142 }
143
GetStreamFor(const CFX_ByteString & key) const144 CPDF_Stream* CPDF_Dictionary::GetStreamFor(const CFX_ByteString& key) const {
145 return ToStream(GetDirectObjectFor(key));
146 }
147
GetRectFor(const CFX_ByteString & key) const148 CFX_FloatRect CPDF_Dictionary::GetRectFor(const CFX_ByteString& key) const {
149 CFX_FloatRect rect;
150 CPDF_Array* pArray = GetArrayFor(key);
151 if (pArray)
152 rect = pArray->GetRect();
153 return rect;
154 }
155
GetMatrixFor(const CFX_ByteString & key) const156 CFX_Matrix CPDF_Dictionary::GetMatrixFor(const CFX_ByteString& key) const {
157 CFX_Matrix matrix;
158 CPDF_Array* pArray = GetArrayFor(key);
159 if (pArray)
160 matrix = pArray->GetMatrix();
161 return matrix;
162 }
163
KeyExist(const CFX_ByteString & key) const164 bool CPDF_Dictionary::KeyExist(const CFX_ByteString& key) const {
165 return pdfium::ContainsKey(m_Map, key);
166 }
167
IsSignatureDict() const168 bool CPDF_Dictionary::IsSignatureDict() const {
169 CPDF_Object* pType = GetDirectObjectFor("Type");
170 if (!pType)
171 pType = GetDirectObjectFor("FT");
172 return pType && pType->GetString() == "Sig";
173 }
174
SetFor(const CFX_ByteString & key,std::unique_ptr<CPDF_Object> pObj)175 CPDF_Object* CPDF_Dictionary::SetFor(const CFX_ByteString& key,
176 std::unique_ptr<CPDF_Object> pObj) {
177 if (!pObj) {
178 m_Map.erase(key);
179 return nullptr;
180 }
181 ASSERT(pObj->IsInline());
182 CPDF_Object* pRet = pObj.get();
183 m_Map[MaybeIntern(key)] = std::move(pObj);
184 return pRet;
185 }
186
ConvertToIndirectObjectFor(const CFX_ByteString & key,CPDF_IndirectObjectHolder * pHolder)187 void CPDF_Dictionary::ConvertToIndirectObjectFor(
188 const CFX_ByteString& key,
189 CPDF_IndirectObjectHolder* pHolder) {
190 auto it = m_Map.find(key);
191 if (it == m_Map.end() || it->second->IsReference())
192 return;
193
194 CPDF_Object* pObj = pHolder->AddIndirectObject(std::move(it->second));
195 it->second = pdfium::MakeUnique<CPDF_Reference>(pHolder, pObj->GetObjNum());
196 }
197
RemoveFor(const CFX_ByteString & key)198 void CPDF_Dictionary::RemoveFor(const CFX_ByteString& key) {
199 m_Map.erase(key);
200 }
201
ReplaceKey(const CFX_ByteString & oldkey,const CFX_ByteString & newkey)202 void CPDF_Dictionary::ReplaceKey(const CFX_ByteString& oldkey,
203 const CFX_ByteString& newkey) {
204 auto old_it = m_Map.find(oldkey);
205 if (old_it == m_Map.end())
206 return;
207
208 auto new_it = m_Map.find(newkey);
209 if (new_it == old_it)
210 return;
211
212 m_Map[MaybeIntern(newkey)] = std::move(old_it->second);
213 m_Map.erase(old_it);
214 }
215
SetRectFor(const CFX_ByteString & key,const CFX_FloatRect & rect)216 void CPDF_Dictionary::SetRectFor(const CFX_ByteString& key,
217 const CFX_FloatRect& rect) {
218 CPDF_Array* pArray = SetNewFor<CPDF_Array>(key);
219 pArray->AddNew<CPDF_Number>(rect.left);
220 pArray->AddNew<CPDF_Number>(rect.bottom);
221 pArray->AddNew<CPDF_Number>(rect.right);
222 pArray->AddNew<CPDF_Number>(rect.top);
223 }
224
SetMatrixFor(const CFX_ByteString & key,const CFX_Matrix & matrix)225 void CPDF_Dictionary::SetMatrixFor(const CFX_ByteString& key,
226 const CFX_Matrix& matrix) {
227 CPDF_Array* pArray = SetNewFor<CPDF_Array>(key);
228 pArray->AddNew<CPDF_Number>(matrix.a);
229 pArray->AddNew<CPDF_Number>(matrix.b);
230 pArray->AddNew<CPDF_Number>(matrix.c);
231 pArray->AddNew<CPDF_Number>(matrix.d);
232 pArray->AddNew<CPDF_Number>(matrix.e);
233 pArray->AddNew<CPDF_Number>(matrix.f);
234 }
235
MaybeIntern(const CFX_ByteString & str)236 CFX_ByteString CPDF_Dictionary::MaybeIntern(const CFX_ByteString& str) {
237 return m_pPool ? m_pPool->Intern(str) : str;
238 }
239