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