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 #ifndef CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_
8 #define CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_
9
10 #include <functional>
11 #include <map>
12 #include <set>
13 #include <utility>
14 #include <vector>
15
16 #include "core/fpdfapi/parser/cpdf_object.h"
17 #include "core/fxcrt/fx_coordinates.h"
18 #include "core/fxcrt/fx_string.h"
19 #include "core/fxcrt/retain_ptr.h"
20 #include "core/fxcrt/string_pool_template.h"
21 #include "core/fxcrt/weak_ptr.h"
22 #include "third_party/base/check.h"
23
24 class CPDF_IndirectObjectHolder;
25
26 // Dictionaries never contain nullptr for valid keys, but some of the methods
27 // will return nullptr to indicate non-existent keys.
28 class CPDF_Dictionary final : public CPDF_Object {
29 public:
30 using DictMap = std::map<ByteString, RetainPtr<CPDF_Object>, std::less<>>;
31 using const_iterator = DictMap::const_iterator;
32
33 CONSTRUCT_VIA_MAKE_RETAIN;
34
35 // CPDF_Object:
36 Type GetType() const override;
37 RetainPtr<CPDF_Object> Clone() const override;
38 CPDF_Dictionary* AsMutableDictionary() override;
39 bool WriteTo(IFX_ArchiveStream* archive,
40 const CPDF_Encryptor* encryptor) const override;
41
IsLocked()42 bool IsLocked() const { return !!m_LockCount; }
43
size()44 size_t size() const { return m_Map.size(); }
45 RetainPtr<const CPDF_Object> GetObjectFor(const ByteString& key) const;
46 RetainPtr<CPDF_Object> GetMutableObjectFor(const ByteString& key);
47
48 RetainPtr<const CPDF_Object> GetDirectObjectFor(const ByteString& key) const;
49 RetainPtr<CPDF_Object> GetMutableDirectObjectFor(const ByteString& key);
50
51 // These will return the string representation of the object specified by
52 // |key|, for any object type that has a string representation.
53 ByteString GetByteStringFor(const ByteString& key) const;
54 ByteString GetByteStringFor(const ByteString& key,
55 const ByteString& default_str) const;
56 WideString GetUnicodeTextFor(const ByteString& key) const;
57
58 // This will only return the string representation of a name object specified
59 // by |key|. Useful when the PDF spec requires the value to be an object of
60 // type name. i.e. /Foo and not (Foo).
61 ByteString GetNameFor(const ByteString& key) const;
62
63 bool GetBooleanFor(const ByteString& key, bool bDefault) const;
64 int GetIntegerFor(const ByteString& key) const;
65 int GetIntegerFor(const ByteString& key, int default_int) const;
66 int GetDirectIntegerFor(const ByteString& key) const;
67 float GetFloatFor(const ByteString& key) const;
68 RetainPtr<const CPDF_Dictionary> GetDictFor(const ByteString& key) const;
69 RetainPtr<CPDF_Dictionary> GetMutableDictFor(const ByteString& key);
70 RetainPtr<CPDF_Dictionary> GetOrCreateDictFor(const ByteString& key);
71 RetainPtr<const CPDF_Array> GetArrayFor(const ByteString& key) const;
72 RetainPtr<CPDF_Array> GetMutableArrayFor(const ByteString& key);
73 RetainPtr<CPDF_Array> GetOrCreateArrayFor(const ByteString& key);
74 RetainPtr<const CPDF_Stream> GetStreamFor(const ByteString& key) const;
75 RetainPtr<CPDF_Stream> GetMutableStreamFor(const ByteString& key);
76 RetainPtr<const CPDF_Number> GetNumberFor(const ByteString& key) const;
77 RetainPtr<const CPDF_String> GetStringFor(const ByteString& key) const;
78 CFX_FloatRect GetRectFor(const ByteString& key) const;
79 CFX_Matrix GetMatrixFor(const ByteString& key) const;
80
81 bool KeyExist(const ByteString& key) const;
82 std::vector<ByteString> GetKeys() const;
83
84 // Creates a new object owned by the dictionary and returns an unowned
85 // pointer to it. Invalidates iterators for the element with the key |key|.
86 // Prefer using these templates over calls to SetFor(), since by creating
87 // a new object with no previous references, they ensure cycles can not be
88 // introduced.
89 template <typename T, typename... Args>
90 typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type
SetNewFor(const ByteString & key,Args &&...args)91 SetNewFor(const ByteString& key, Args&&... args) {
92 return pdfium::WrapRetain(static_cast<T*>(SetForInternal(
93 key, pdfium::MakeRetain<T>(std::forward<Args>(args)...))));
94 }
95 template <typename T, typename... Args>
96 typename std::enable_if<CanInternStrings<T>::value, RetainPtr<T>>::type
SetNewFor(const ByteString & key,Args &&...args)97 SetNewFor(const ByteString& key, Args&&... args) {
98 return pdfium::WrapRetain(static_cast<T*>(SetForInternal(
99 key, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...))));
100 }
101
102 // If |pObj| is null, then |key| is erased from the map. Otherwise, takes
103 // ownership of |pObj| and stores in in the map. Invalidates iterators for
104 // the element with the key |key|.
105 void SetFor(const ByteString& key, RetainPtr<CPDF_Object> pObj);
106
107 // Convenience functions to convert native objects to array form.
108 void SetRectFor(const ByteString& key, const CFX_FloatRect& rect);
109 void SetMatrixFor(const ByteString& key, const CFX_Matrix& matrix);
110
111 void ConvertToIndirectObjectFor(const ByteString& key,
112 CPDF_IndirectObjectHolder* pHolder);
113
114 // Invalidates iterators for the element with the key |key|.
115 RetainPtr<CPDF_Object> RemoveFor(ByteStringView key);
116
117 // Invalidates iterators for the element with the key |oldkey|.
118 void ReplaceKey(const ByteString& oldkey, const ByteString& newkey);
119
GetByteStringPool()120 WeakPtr<ByteStringPool> GetByteStringPool() const { return m_pPool; }
121
122 private:
123 friend class CPDF_DictionaryLocker;
124
125 CPDF_Dictionary();
126 explicit CPDF_Dictionary(const WeakPtr<ByteStringPool>& pPool);
127 ~CPDF_Dictionary() override;
128
129 // No guarantees about result lifetime, use with caution.
130 const CPDF_Object* GetObjectForInternal(const ByteString& key) const;
131 const CPDF_Object* GetDirectObjectForInternal(const ByteString& key) const;
132 const CPDF_Array* GetArrayForInternal(const ByteString& key) const;
133 const CPDF_Dictionary* GetDictForInternal(const ByteString& key) const;
134 const CPDF_Number* GetNumberForInternal(const ByteString& key) const;
135 const CPDF_Stream* GetStreamForInternal(const ByteString& key) const;
136 const CPDF_String* GetStringForInternal(const ByteString& key) const;
137 CPDF_Object* SetForInternal(const ByteString& key,
138 RetainPtr<CPDF_Object> pObj);
139
140 ByteString MaybeIntern(const ByteString& str);
141 const CPDF_Dictionary* GetDictInternal() const override;
142 RetainPtr<CPDF_Object> CloneNonCyclic(
143 bool bDirect,
144 std::set<const CPDF_Object*>* visited) const override;
145
146 mutable uint32_t m_LockCount = 0;
147 WeakPtr<ByteStringPool> m_pPool;
148 DictMap m_Map;
149 };
150
151 class CPDF_DictionaryLocker {
152 public:
153 FX_STACK_ALLOCATED();
154 using const_iterator = CPDF_Dictionary::const_iterator;
155
156 explicit CPDF_DictionaryLocker(const CPDF_Dictionary* pDictionary);
157 explicit CPDF_DictionaryLocker(RetainPtr<CPDF_Dictionary> pDictionary);
158 explicit CPDF_DictionaryLocker(RetainPtr<const CPDF_Dictionary> pDictionary);
159 ~CPDF_DictionaryLocker();
160
begin()161 const_iterator begin() const {
162 CHECK(m_pDictionary->IsLocked());
163 return m_pDictionary->m_Map.begin();
164 }
end()165 const_iterator end() const {
166 CHECK(m_pDictionary->IsLocked());
167 return m_pDictionary->m_Map.end();
168 }
169
170 private:
171 RetainPtr<const CPDF_Dictionary> const m_pDictionary;
172 };
173
ToDictionary(CPDF_Object * obj)174 inline CPDF_Dictionary* ToDictionary(CPDF_Object* obj) {
175 return obj ? obj->AsMutableDictionary() : nullptr;
176 }
177
ToDictionary(const CPDF_Object * obj)178 inline const CPDF_Dictionary* ToDictionary(const CPDF_Object* obj) {
179 return obj ? obj->AsDictionary() : nullptr;
180 }
181
ToDictionary(RetainPtr<CPDF_Object> obj)182 inline RetainPtr<CPDF_Dictionary> ToDictionary(RetainPtr<CPDF_Object> obj) {
183 return RetainPtr<CPDF_Dictionary>(ToDictionary(obj.Get()));
184 }
185
ToDictionary(RetainPtr<const CPDF_Object> obj)186 inline RetainPtr<const CPDF_Dictionary> ToDictionary(
187 RetainPtr<const CPDF_Object> obj) {
188 return RetainPtr<const CPDF_Dictionary>(ToDictionary(obj.Get()));
189 }
190
191 #endif // CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_
192