• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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