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_array.h"
8
9 #include <set>
10 #include <utility>
11
12 #include "core/fpdfapi/parser/cpdf_boolean.h"
13 #include "core/fpdfapi/parser/cpdf_name.h"
14 #include "core/fpdfapi/parser/cpdf_number.h"
15 #include "core/fpdfapi/parser/cpdf_reference.h"
16 #include "core/fpdfapi/parser/cpdf_stream.h"
17 #include "core/fpdfapi/parser/cpdf_string.h"
18 #include "core/fxcrt/fx_stream.h"
19 #include "third_party/base/logging.h"
20 #include "third_party/base/ptr_util.h"
21 #include "third_party/base/stl_util.h"
22
23 CPDF_Array::CPDF_Array() = default;
24
CPDF_Array(const WeakPtr<ByteStringPool> & pPool)25 CPDF_Array::CPDF_Array(const WeakPtr<ByteStringPool>& pPool) : m_pPool(pPool) {}
26
~CPDF_Array()27 CPDF_Array::~CPDF_Array() {
28 // Break cycles for cyclic references.
29 m_ObjNum = kInvalidObjNum;
30 for (auto& it : m_Objects) {
31 if (it && it->GetObjNum() == kInvalidObjNum)
32 it.Leak();
33 }
34 }
35
GetType() const36 CPDF_Object::Type CPDF_Array::GetType() const {
37 return kArray;
38 }
39
IsArray() const40 bool CPDF_Array::IsArray() const {
41 return true;
42 }
43
AsArray()44 CPDF_Array* CPDF_Array::AsArray() {
45 return this;
46 }
47
AsArray() const48 const CPDF_Array* CPDF_Array::AsArray() const {
49 return this;
50 }
51
Clone() const52 RetainPtr<CPDF_Object> CPDF_Array::Clone() const {
53 return CloneObjectNonCyclic(false);
54 }
55
CloneNonCyclic(bool bDirect,std::set<const CPDF_Object * > * pVisited) const56 RetainPtr<CPDF_Object> CPDF_Array::CloneNonCyclic(
57 bool bDirect,
58 std::set<const CPDF_Object*>* pVisited) const {
59 pVisited->insert(this);
60 auto pCopy = pdfium::MakeRetain<CPDF_Array>();
61 for (const auto& pValue : m_Objects) {
62 if (!pdfium::ContainsKey(*pVisited, pValue.Get())) {
63 std::set<const CPDF_Object*> visited(*pVisited);
64 if (auto obj = pValue->CloneNonCyclic(bDirect, &visited))
65 pCopy->m_Objects.push_back(std::move(obj));
66 }
67 }
68 return pCopy;
69 }
70
GetRect() const71 CFX_FloatRect CPDF_Array::GetRect() const {
72 CFX_FloatRect rect;
73 if (m_Objects.size() != 4)
74 return rect;
75
76 rect.left = GetNumberAt(0);
77 rect.bottom = GetNumberAt(1);
78 rect.right = GetNumberAt(2);
79 rect.top = GetNumberAt(3);
80 return rect;
81 }
82
GetMatrix() const83 CFX_Matrix CPDF_Array::GetMatrix() const {
84 if (m_Objects.size() != 6)
85 return CFX_Matrix();
86
87 return CFX_Matrix(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2),
88 GetNumberAt(3), GetNumberAt(4), GetNumberAt(5));
89 }
90
GetObjectAt(size_t index)91 CPDF_Object* CPDF_Array::GetObjectAt(size_t index) {
92 if (index >= m_Objects.size())
93 return nullptr;
94 return m_Objects[index].Get();
95 }
96
GetObjectAt(size_t index) const97 const CPDF_Object* CPDF_Array::GetObjectAt(size_t index) const {
98 if (index >= m_Objects.size())
99 return nullptr;
100 return m_Objects[index].Get();
101 }
102
GetDirectObjectAt(size_t index)103 CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t index) {
104 if (index >= m_Objects.size())
105 return nullptr;
106 return m_Objects[index]->GetDirect();
107 }
108
GetDirectObjectAt(size_t index) const109 const CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t index) const {
110 if (index >= m_Objects.size())
111 return nullptr;
112 return m_Objects[index]->GetDirect();
113 }
114
GetStringAt(size_t index) const115 ByteString CPDF_Array::GetStringAt(size_t index) const {
116 if (index >= m_Objects.size())
117 return ByteString();
118 return m_Objects[index]->GetString();
119 }
120
GetUnicodeTextAt(size_t index) const121 WideString CPDF_Array::GetUnicodeTextAt(size_t index) const {
122 if (index >= m_Objects.size())
123 return WideString();
124 return m_Objects[index]->GetUnicodeText();
125 }
126
GetBooleanAt(size_t index,bool bDefault) const127 bool CPDF_Array::GetBooleanAt(size_t index, bool bDefault) const {
128 if (index >= m_Objects.size())
129 return bDefault;
130 const CPDF_Object* p = m_Objects[index].Get();
131 return ToBoolean(p) ? p->GetInteger() != 0 : bDefault;
132 }
133
GetIntegerAt(size_t index) const134 int CPDF_Array::GetIntegerAt(size_t index) const {
135 if (index >= m_Objects.size())
136 return 0;
137 return m_Objects[index]->GetInteger();
138 }
139
GetNumberAt(size_t index) const140 float CPDF_Array::GetNumberAt(size_t index) const {
141 if (index >= m_Objects.size())
142 return 0;
143 return m_Objects[index]->GetNumber();
144 }
145
GetDictAt(size_t index)146 CPDF_Dictionary* CPDF_Array::GetDictAt(size_t index) {
147 CPDF_Object* p = GetDirectObjectAt(index);
148 if (!p)
149 return nullptr;
150 if (CPDF_Dictionary* pDict = p->AsDictionary())
151 return pDict;
152 if (CPDF_Stream* pStream = p->AsStream())
153 return pStream->GetDict();
154 return nullptr;
155 }
156
GetDictAt(size_t index) const157 const CPDF_Dictionary* CPDF_Array::GetDictAt(size_t index) const {
158 const CPDF_Object* p = GetDirectObjectAt(index);
159 if (!p)
160 return nullptr;
161 if (const CPDF_Dictionary* pDict = p->AsDictionary())
162 return pDict;
163 if (const CPDF_Stream* pStream = p->AsStream())
164 return pStream->GetDict();
165 return nullptr;
166 }
167
GetStreamAt(size_t index)168 CPDF_Stream* CPDF_Array::GetStreamAt(size_t index) {
169 return ToStream(GetDirectObjectAt(index));
170 }
171
GetStreamAt(size_t index) const172 const CPDF_Stream* CPDF_Array::GetStreamAt(size_t index) const {
173 return ToStream(GetDirectObjectAt(index));
174 }
175
GetArrayAt(size_t index)176 CPDF_Array* CPDF_Array::GetArrayAt(size_t index) {
177 return ToArray(GetDirectObjectAt(index));
178 }
179
GetArrayAt(size_t index) const180 const CPDF_Array* CPDF_Array::GetArrayAt(size_t index) const {
181 return ToArray(GetDirectObjectAt(index));
182 }
183
Clear()184 void CPDF_Array::Clear() {
185 CHECK(!IsLocked());
186 m_Objects.clear();
187 }
188
RemoveAt(size_t index)189 void CPDF_Array::RemoveAt(size_t index) {
190 CHECK(!IsLocked());
191 if (index < m_Objects.size())
192 m_Objects.erase(m_Objects.begin() + index);
193 }
194
ConvertToIndirectObjectAt(size_t index,CPDF_IndirectObjectHolder * pHolder)195 void CPDF_Array::ConvertToIndirectObjectAt(size_t index,
196 CPDF_IndirectObjectHolder* pHolder) {
197 CHECK(!IsLocked());
198 if (index >= m_Objects.size())
199 return;
200
201 if (!m_Objects[index] || m_Objects[index]->IsReference())
202 return;
203
204 CPDF_Object* pNew = pHolder->AddIndirectObject(std::move(m_Objects[index]));
205 m_Objects[index] = pNew->MakeReference(pHolder);
206 }
207
SetAt(size_t index,RetainPtr<CPDF_Object> pObj)208 CPDF_Object* CPDF_Array::SetAt(size_t index, RetainPtr<CPDF_Object> pObj) {
209 CHECK(!IsLocked());
210 ASSERT(!pObj || pObj->IsInline());
211 if (index >= m_Objects.size()) {
212 NOTREACHED();
213 return nullptr;
214 }
215 CPDF_Object* pRet = pObj.Get();
216 m_Objects[index] = std::move(pObj);
217 return pRet;
218 }
219
InsertAt(size_t index,RetainPtr<CPDF_Object> pObj)220 CPDF_Object* CPDF_Array::InsertAt(size_t index, RetainPtr<CPDF_Object> pObj) {
221 CHECK(!IsLocked());
222 CHECK(!pObj || pObj->IsInline());
223 CPDF_Object* pRet = pObj.Get();
224 if (index >= m_Objects.size()) {
225 // Allocate space first.
226 m_Objects.resize(index + 1);
227 m_Objects[index] = std::move(pObj);
228 } else {
229 // Directly insert.
230 m_Objects.insert(m_Objects.begin() + index, std::move(pObj));
231 }
232 return pRet;
233 }
234
Add(RetainPtr<CPDF_Object> pObj)235 CPDF_Object* CPDF_Array::Add(RetainPtr<CPDF_Object> pObj) {
236 CHECK(!IsLocked());
237 CHECK(!pObj || pObj->IsInline());
238 CPDF_Object* pRet = pObj.Get();
239 m_Objects.push_back(std::move(pObj));
240 return pRet;
241 }
242
WriteTo(IFX_ArchiveStream * archive,const CPDF_Encryptor * encryptor) const243 bool CPDF_Array::WriteTo(IFX_ArchiveStream* archive,
244 const CPDF_Encryptor* encryptor) const {
245 if (!archive->WriteString("["))
246 return false;
247
248 for (size_t i = 0; i < size(); ++i) {
249 if (!GetObjectAt(i)->WriteTo(archive, encryptor))
250 return false;
251 }
252 return archive->WriteString("]");
253 }
254
CPDF_ArrayLocker(const CPDF_Array * pArray)255 CPDF_ArrayLocker::CPDF_ArrayLocker(const CPDF_Array* pArray)
256 : m_pArray(pArray) {
257 m_pArray->m_LockCount++;
258 }
259
~CPDF_ArrayLocker()260 CPDF_ArrayLocker::~CPDF_ArrayLocker() {
261 m_pArray->m_LockCount--;
262 }
263