1 // Copyright 2016 The PDFium Authors
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_utility.h"
21 #include "core/fxcrt/fx_stream.h"
22 #include "third_party/base/check.h"
23 #include "third_party/base/containers/contains.h"
24
CPDF_Dictionary()25 CPDF_Dictionary::CPDF_Dictionary()
26 : CPDF_Dictionary(WeakPtr<ByteStringPool>()) {}
27
CPDF_Dictionary(const WeakPtr<ByteStringPool> & pPool)28 CPDF_Dictionary::CPDF_Dictionary(const WeakPtr<ByteStringPool>& pPool)
29 : m_pPool(pPool) {}
30
~CPDF_Dictionary()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->GetObjNum() == kInvalidObjNum)
37 it.second.Leak();
38 }
39 }
40
GetType() const41 CPDF_Object::Type CPDF_Dictionary::GetType() const {
42 return kDictionary;
43 }
44
AsMutableDictionary()45 CPDF_Dictionary* CPDF_Dictionary::AsMutableDictionary() {
46 return this;
47 }
48
Clone() const49 RetainPtr<CPDF_Object> CPDF_Dictionary::Clone() const {
50 return CloneObjectNonCyclic(false);
51 }
52
CloneNonCyclic(bool bDirect,std::set<const CPDF_Object * > * pVisited) const53 RetainPtr<CPDF_Object> CPDF_Dictionary::CloneNonCyclic(
54 bool bDirect,
55 std::set<const CPDF_Object*>* pVisited) const {
56 pVisited->insert(this);
57 auto pCopy = pdfium::MakeRetain<CPDF_Dictionary>(m_pPool);
58 CPDF_DictionaryLocker locker(this);
59 for (const auto& it : locker) {
60 if (!pdfium::Contains(*pVisited, it.second.Get())) {
61 std::set<const CPDF_Object*> visited(*pVisited);
62 auto obj = it.second->CloneNonCyclic(bDirect, &visited);
63 if (obj)
64 pCopy->m_Map.insert(std::make_pair(it.first, std::move(obj)));
65 }
66 }
67 return pCopy;
68 }
69
GetObjectForInternal(const ByteString & key) const70 const CPDF_Object* CPDF_Dictionary::GetObjectForInternal(
71 const ByteString& key) const {
72 auto it = m_Map.find(key);
73 return it != m_Map.end() ? it->second.Get() : nullptr;
74 }
75
GetObjectFor(const ByteString & key) const76 RetainPtr<const CPDF_Object> CPDF_Dictionary::GetObjectFor(
77 const ByteString& key) const {
78 return pdfium::WrapRetain(GetObjectForInternal(key));
79 }
80
GetMutableObjectFor(const ByteString & key)81 RetainPtr<CPDF_Object> CPDF_Dictionary::GetMutableObjectFor(
82 const ByteString& key) {
83 return pdfium::WrapRetain(
84 const_cast<CPDF_Object*>(GetObjectForInternal(key)));
85 }
86
GetDirectObjectForInternal(const ByteString & key) const87 const CPDF_Object* CPDF_Dictionary::GetDirectObjectForInternal(
88 const ByteString& key) const {
89 const CPDF_Object* p = GetObjectForInternal(key);
90 return p ? p->GetDirectInternal() : nullptr;
91 }
92
GetDirectObjectFor(const ByteString & key) const93 RetainPtr<const CPDF_Object> CPDF_Dictionary::GetDirectObjectFor(
94 const ByteString& key) const {
95 return pdfium::WrapRetain(GetDirectObjectForInternal(key));
96 }
97
GetMutableDirectObjectFor(const ByteString & key)98 RetainPtr<CPDF_Object> CPDF_Dictionary::GetMutableDirectObjectFor(
99 const ByteString& key) {
100 return pdfium::WrapRetain(
101 const_cast<CPDF_Object*>(GetDirectObjectForInternal(key)));
102 }
103
GetByteStringFor(const ByteString & key) const104 ByteString CPDF_Dictionary::GetByteStringFor(const ByteString& key) const {
105 const CPDF_Object* p = GetObjectForInternal(key);
106 return p ? p->GetString() : ByteString();
107 }
108
GetByteStringFor(const ByteString & key,const ByteString & def) const109 ByteString CPDF_Dictionary::GetByteStringFor(const ByteString& key,
110 const ByteString& def) const {
111 const CPDF_Object* p = GetObjectForInternal(key);
112 return p ? p->GetString() : ByteString(def);
113 }
114
GetUnicodeTextFor(const ByteString & key) const115 WideString CPDF_Dictionary::GetUnicodeTextFor(const ByteString& key) const {
116 const CPDF_Object* p = GetObjectForInternal(key);
117 if (const CPDF_Reference* pRef = ToReference(p))
118 p = pRef->GetDirectInternal();
119 return p ? p->GetUnicodeText() : WideString();
120 }
121
GetNameFor(const ByteString & key) const122 ByteString CPDF_Dictionary::GetNameFor(const ByteString& key) const {
123 const CPDF_Name* p = ToName(GetObjectForInternal(key));
124 return p ? p->GetString() : ByteString();
125 }
126
GetBooleanFor(const ByteString & key,bool bDefault) const127 bool CPDF_Dictionary::GetBooleanFor(const ByteString& key,
128 bool bDefault) const {
129 const CPDF_Object* p = GetObjectForInternal(key);
130 return ToBoolean(p) ? p->GetInteger() != 0 : bDefault;
131 }
132
GetIntegerFor(const ByteString & key) const133 int CPDF_Dictionary::GetIntegerFor(const ByteString& key) const {
134 const CPDF_Object* p = GetObjectForInternal(key);
135 return p ? p->GetInteger() : 0;
136 }
137
GetIntegerFor(const ByteString & key,int def) const138 int CPDF_Dictionary::GetIntegerFor(const ByteString& key, int def) const {
139 const CPDF_Object* p = GetObjectForInternal(key);
140 return p ? p->GetInteger() : def;
141 }
142
GetDirectIntegerFor(const ByteString & key) const143 int CPDF_Dictionary::GetDirectIntegerFor(const ByteString& key) const {
144 const CPDF_Number* p = ToNumber(GetObjectForInternal(key));
145 return p ? p->GetInteger() : 0;
146 }
147
GetFloatFor(const ByteString & key) const148 float CPDF_Dictionary::GetFloatFor(const ByteString& key) const {
149 const CPDF_Object* p = GetObjectForInternal(key);
150 return p ? p->GetNumber() : 0;
151 }
152
GetDictInternal() const153 const CPDF_Dictionary* CPDF_Dictionary::GetDictInternal() const {
154 return this;
155 }
156
GetDictForInternal(const ByteString & key) const157 const CPDF_Dictionary* CPDF_Dictionary::GetDictForInternal(
158 const ByteString& key) const {
159 const CPDF_Object* p = GetDirectObjectForInternal(key);
160 return p ? p->GetDictInternal() : nullptr;
161 }
162
GetDictFor(const ByteString & key) const163 RetainPtr<const CPDF_Dictionary> CPDF_Dictionary::GetDictFor(
164 const ByteString& key) const {
165 return pdfium::WrapRetain(GetDictForInternal(key));
166 }
167
GetMutableDictFor(const ByteString & key)168 RetainPtr<CPDF_Dictionary> CPDF_Dictionary::GetMutableDictFor(
169 const ByteString& key) {
170 return pdfium::WrapRetain(
171 const_cast<CPDF_Dictionary*>(GetDictForInternal(key)));
172 }
173
GetOrCreateDictFor(const ByteString & key)174 RetainPtr<CPDF_Dictionary> CPDF_Dictionary::GetOrCreateDictFor(
175 const ByteString& key) {
176 RetainPtr<CPDF_Dictionary> result = GetMutableDictFor(key);
177 if (result)
178 return result;
179 return SetNewFor<CPDF_Dictionary>(key);
180 }
181
GetArrayForInternal(const ByteString & key) const182 const CPDF_Array* CPDF_Dictionary::GetArrayForInternal(
183 const ByteString& key) const {
184 return ToArray(GetDirectObjectForInternal(key));
185 }
186
GetArrayFor(const ByteString & key) const187 RetainPtr<const CPDF_Array> CPDF_Dictionary::GetArrayFor(
188 const ByteString& key) const {
189 return pdfium::WrapRetain(GetArrayForInternal(key));
190 }
191
GetMutableArrayFor(const ByteString & key)192 RetainPtr<CPDF_Array> CPDF_Dictionary::GetMutableArrayFor(
193 const ByteString& key) {
194 return pdfium::WrapRetain(const_cast<CPDF_Array*>(GetArrayForInternal(key)));
195 }
196
GetOrCreateArrayFor(const ByteString & key)197 RetainPtr<CPDF_Array> CPDF_Dictionary::GetOrCreateArrayFor(
198 const ByteString& key) {
199 RetainPtr<CPDF_Array> result = GetMutableArrayFor(key);
200 if (result)
201 return result;
202 return SetNewFor<CPDF_Array>(key);
203 }
204
GetStreamForInternal(const ByteString & key) const205 const CPDF_Stream* CPDF_Dictionary::GetStreamForInternal(
206 const ByteString& key) const {
207 return ToStream(GetDirectObjectForInternal(key));
208 }
209
GetStreamFor(const ByteString & key) const210 RetainPtr<const CPDF_Stream> CPDF_Dictionary::GetStreamFor(
211 const ByteString& key) const {
212 return pdfium::WrapRetain(GetStreamForInternal(key));
213 }
214
GetMutableStreamFor(const ByteString & key)215 RetainPtr<CPDF_Stream> CPDF_Dictionary::GetMutableStreamFor(
216 const ByteString& key) {
217 return pdfium::WrapRetain(
218 const_cast<CPDF_Stream*>(GetStreamForInternal(key)));
219 }
220
GetNumberForInternal(const ByteString & key) const221 const CPDF_Number* CPDF_Dictionary::GetNumberForInternal(
222 const ByteString& key) const {
223 return ToNumber(GetObjectForInternal(key));
224 }
225
GetNumberFor(const ByteString & key) const226 RetainPtr<const CPDF_Number> CPDF_Dictionary::GetNumberFor(
227 const ByteString& key) const {
228 return pdfium::WrapRetain(GetNumberForInternal(key));
229 }
230
GetStringForInternal(const ByteString & key) const231 const CPDF_String* CPDF_Dictionary::GetStringForInternal(
232 const ByteString& key) const {
233 return ToString(GetObjectForInternal(key));
234 }
235
GetStringFor(const ByteString & key) const236 RetainPtr<const CPDF_String> CPDF_Dictionary::GetStringFor(
237 const ByteString& key) const {
238 return pdfium::WrapRetain(GetStringForInternal(key));
239 }
240
GetRectFor(const ByteString & key) const241 CFX_FloatRect CPDF_Dictionary::GetRectFor(const ByteString& key) const {
242 const CPDF_Array* pArray = GetArrayForInternal(key);
243 if (pArray)
244 return pArray->GetRect();
245 return CFX_FloatRect();
246 }
247
GetMatrixFor(const ByteString & key) const248 CFX_Matrix CPDF_Dictionary::GetMatrixFor(const ByteString& key) const {
249 const CPDF_Array* pArray = GetArrayForInternal(key);
250 if (pArray)
251 return pArray->GetMatrix();
252 return CFX_Matrix();
253 }
254
KeyExist(const ByteString & key) const255 bool CPDF_Dictionary::KeyExist(const ByteString& key) const {
256 return pdfium::Contains(m_Map, key);
257 }
258
GetKeys() const259 std::vector<ByteString> CPDF_Dictionary::GetKeys() const {
260 std::vector<ByteString> result;
261 CPDF_DictionaryLocker locker(this);
262 for (const auto& item : locker)
263 result.push_back(item.first);
264 return result;
265 }
266
SetFor(const ByteString & key,RetainPtr<CPDF_Object> pObj)267 void CPDF_Dictionary::SetFor(const ByteString& key,
268 RetainPtr<CPDF_Object> pObj) {
269 (void)SetForInternal(key, std::move(pObj));
270 }
271
SetForInternal(const ByteString & key,RetainPtr<CPDF_Object> pObj)272 CPDF_Object* CPDF_Dictionary::SetForInternal(const ByteString& key,
273 RetainPtr<CPDF_Object> pObj) {
274 CHECK(!IsLocked());
275 if (!pObj) {
276 m_Map.erase(key);
277 return nullptr;
278 }
279 DCHECK(pObj->IsInline());
280 CPDF_Object* pRet = pObj.Get();
281 m_Map[MaybeIntern(key)] = std::move(pObj);
282 return pRet;
283 }
284
ConvertToIndirectObjectFor(const ByteString & key,CPDF_IndirectObjectHolder * pHolder)285 void CPDF_Dictionary::ConvertToIndirectObjectFor(
286 const ByteString& key,
287 CPDF_IndirectObjectHolder* pHolder) {
288 CHECK(!IsLocked());
289 auto it = m_Map.find(key);
290 if (it == m_Map.end() || it->second->IsReference())
291 return;
292
293 pHolder->AddIndirectObject(it->second);
294 it->second = it->second->MakeReference(pHolder);
295 }
296
RemoveFor(ByteStringView key)297 RetainPtr<CPDF_Object> CPDF_Dictionary::RemoveFor(ByteStringView key) {
298 CHECK(!IsLocked());
299 RetainPtr<CPDF_Object> result;
300 auto it = m_Map.find(key);
301 if (it != m_Map.end()) {
302 result = std::move(it->second);
303 m_Map.erase(it);
304 }
305 return result;
306 }
307
ReplaceKey(const ByteString & oldkey,const ByteString & newkey)308 void CPDF_Dictionary::ReplaceKey(const ByteString& oldkey,
309 const ByteString& newkey) {
310 CHECK(!IsLocked());
311 auto old_it = m_Map.find(oldkey);
312 if (old_it == m_Map.end())
313 return;
314
315 auto new_it = m_Map.find(newkey);
316 if (new_it == old_it)
317 return;
318
319 m_Map[MaybeIntern(newkey)] = std::move(old_it->second);
320 m_Map.erase(old_it);
321 }
322
SetRectFor(const ByteString & key,const CFX_FloatRect & rect)323 void CPDF_Dictionary::SetRectFor(const ByteString& key,
324 const CFX_FloatRect& rect) {
325 auto pArray = SetNewFor<CPDF_Array>(key);
326 pArray->AppendNew<CPDF_Number>(rect.left);
327 pArray->AppendNew<CPDF_Number>(rect.bottom);
328 pArray->AppendNew<CPDF_Number>(rect.right);
329 pArray->AppendNew<CPDF_Number>(rect.top);
330 }
331
SetMatrixFor(const ByteString & key,const CFX_Matrix & matrix)332 void CPDF_Dictionary::SetMatrixFor(const ByteString& key,
333 const CFX_Matrix& matrix) {
334 auto pArray = SetNewFor<CPDF_Array>(key);
335 pArray->AppendNew<CPDF_Number>(matrix.a);
336 pArray->AppendNew<CPDF_Number>(matrix.b);
337 pArray->AppendNew<CPDF_Number>(matrix.c);
338 pArray->AppendNew<CPDF_Number>(matrix.d);
339 pArray->AppendNew<CPDF_Number>(matrix.e);
340 pArray->AppendNew<CPDF_Number>(matrix.f);
341 }
342
MaybeIntern(const ByteString & str)343 ByteString CPDF_Dictionary::MaybeIntern(const ByteString& str) {
344 return m_pPool ? m_pPool->Intern(str) : str;
345 }
346
WriteTo(IFX_ArchiveStream * archive,const CPDF_Encryptor * encryptor) const347 bool CPDF_Dictionary::WriteTo(IFX_ArchiveStream* archive,
348 const CPDF_Encryptor* encryptor) const {
349 if (!archive->WriteString("<<"))
350 return false;
351
352 const bool is_signature = CPDF_CryptoHandler::IsSignatureDictionary(this);
353
354 CPDF_DictionaryLocker locker(this);
355 for (const auto& it : locker) {
356 const ByteString& key = it.first;
357 const RetainPtr<CPDF_Object>& pValue = it.second;
358 if (!archive->WriteString("/") ||
359 !archive->WriteString(PDF_NameEncode(key).AsStringView())) {
360 return false;
361 }
362 if (!pValue->WriteTo(archive, !is_signature || key != "Contents"
363 ? encryptor
364 : nullptr)) {
365 return false;
366 }
367 }
368 return archive->WriteString(">>");
369 }
370
CPDF_DictionaryLocker(const CPDF_Dictionary * pDictionary)371 CPDF_DictionaryLocker::CPDF_DictionaryLocker(const CPDF_Dictionary* pDictionary)
372 : m_pDictionary(pDictionary) {
373 m_pDictionary->m_LockCount++;
374 }
375
CPDF_DictionaryLocker(RetainPtr<CPDF_Dictionary> pDictionary)376 CPDF_DictionaryLocker::CPDF_DictionaryLocker(
377 RetainPtr<CPDF_Dictionary> pDictionary)
378 : m_pDictionary(std::move(pDictionary)) {
379 m_pDictionary->m_LockCount++;
380 }
381
CPDF_DictionaryLocker(RetainPtr<const CPDF_Dictionary> pDictionary)382 CPDF_DictionaryLocker::CPDF_DictionaryLocker(
383 RetainPtr<const CPDF_Dictionary> pDictionary)
384 : m_pDictionary(std::move(pDictionary)) {
385 m_pDictionary->m_LockCount++;
386 }
387
~CPDF_DictionaryLocker()388 CPDF_DictionaryLocker::~CPDF_DictionaryLocker() {
389 m_pDictionary->m_LockCount--;
390 }
391