• 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_array.h"
8 
9 #include <set>
10 #include <utility>
11 
12 #include "core/fpdfapi/parser/cpdf_boolean.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_name.h"
15 #include "core/fpdfapi/parser/cpdf_number.h"
16 #include "core/fpdfapi/parser/cpdf_reference.h"
17 #include "core/fpdfapi/parser/cpdf_stream.h"
18 #include "core/fpdfapi/parser/cpdf_string.h"
19 #include "core/fxcrt/check.h"
20 #include "core/fxcrt/containers/contains.h"
21 #include "core/fxcrt/fx_stream.h"
22 #include "core/fxcrt/notreached.h"
23 
24 CPDF_Array::CPDF_Array() = default;
25 
CPDF_Array(const WeakPtr<ByteStringPool> & pPool)26 CPDF_Array::CPDF_Array(const WeakPtr<ByteStringPool>& pPool) : m_pPool(pPool) {}
27 
~CPDF_Array()28 CPDF_Array::~CPDF_Array() {
29   // Break cycles for cyclic references.
30   m_ObjNum = kInvalidObjNum;
31   for (auto& it : m_Objects) {
32     if (it->GetObjNum() == kInvalidObjNum)
33       it.Leak();
34   }
35 }
36 
GetType() const37 CPDF_Object::Type CPDF_Array::GetType() const {
38   return kArray;
39 }
40 
AsMutableArray()41 CPDF_Array* CPDF_Array::AsMutableArray() {
42   return this;
43 }
44 
Clone() const45 RetainPtr<CPDF_Object> CPDF_Array::Clone() const {
46   return CloneObjectNonCyclic(false);
47 }
48 
CloneNonCyclic(bool bDirect,std::set<const CPDF_Object * > * pVisited) const49 RetainPtr<CPDF_Object> CPDF_Array::CloneNonCyclic(
50     bool bDirect,
51     std::set<const CPDF_Object*>* pVisited) const {
52   pVisited->insert(this);
53   auto pCopy = pdfium::MakeRetain<CPDF_Array>();
54   for (const auto& pValue : m_Objects) {
55     if (!pdfium::Contains(*pVisited, pValue.Get())) {
56       std::set<const CPDF_Object*> visited(*pVisited);
57       if (auto obj = pValue->CloneNonCyclic(bDirect, &visited))
58         pCopy->m_Objects.push_back(std::move(obj));
59     }
60   }
61   return pCopy;
62 }
63 
GetRect() const64 CFX_FloatRect CPDF_Array::GetRect() const {
65   CFX_FloatRect rect;
66   if (m_Objects.size() != 4)
67     return rect;
68 
69   rect.left = GetFloatAt(0);
70   rect.bottom = GetFloatAt(1);
71   rect.right = GetFloatAt(2);
72   rect.top = GetFloatAt(3);
73   return rect;
74 }
75 
GetMatrix() const76 CFX_Matrix CPDF_Array::GetMatrix() const {
77   if (m_Objects.size() != 6)
78     return CFX_Matrix();
79 
80   return CFX_Matrix(GetFloatAt(0), GetFloatAt(1), GetFloatAt(2), GetFloatAt(3),
81                     GetFloatAt(4), GetFloatAt(5));
82 }
83 
Find(const CPDF_Object * pThat) const84 std::optional<size_t> CPDF_Array::Find(const CPDF_Object* pThat) const {
85   for (size_t i = 0; i < size(); ++i) {
86     if (GetDirectObjectAt(i) == pThat)
87       return i;
88   }
89   return std::nullopt;
90 }
91 
Contains(const CPDF_Object * pThat) const92 bool CPDF_Array::Contains(const CPDF_Object* pThat) const {
93   return Find(pThat).has_value();
94 }
95 
GetMutableObjectAtInternal(size_t index)96 CPDF_Object* CPDF_Array::GetMutableObjectAtInternal(size_t index) {
97   return index < m_Objects.size() ? m_Objects[index].Get() : nullptr;
98 }
99 
GetObjectAtInternal(size_t index) const100 const CPDF_Object* CPDF_Array::GetObjectAtInternal(size_t index) const {
101   return const_cast<CPDF_Array*>(this)->GetMutableObjectAtInternal(index);
102 }
103 
GetMutableObjectAt(size_t index)104 RetainPtr<CPDF_Object> CPDF_Array::GetMutableObjectAt(size_t index) {
105   return pdfium::WrapRetain(GetMutableObjectAtInternal(index));
106 }
107 
GetObjectAt(size_t index) const108 RetainPtr<const CPDF_Object> CPDF_Array::GetObjectAt(size_t index) const {
109   return pdfium::WrapRetain(GetObjectAtInternal(index));
110 }
111 
GetDirectObjectAt(size_t index) const112 RetainPtr<const CPDF_Object> CPDF_Array::GetDirectObjectAt(size_t index) const {
113   return const_cast<CPDF_Array*>(this)->GetMutableDirectObjectAt(index);
114 }
115 
GetMutableDirectObjectAt(size_t index)116 RetainPtr<CPDF_Object> CPDF_Array::GetMutableDirectObjectAt(size_t index) {
117   RetainPtr<CPDF_Object> pObj = GetMutableObjectAt(index);
118   return pObj ? pObj->GetMutableDirect() : nullptr;
119 }
120 
GetByteStringAt(size_t index) const121 ByteString CPDF_Array::GetByteStringAt(size_t index) const {
122   if (index >= m_Objects.size())
123     return ByteString();
124   return m_Objects[index]->GetString();
125 }
126 
GetUnicodeTextAt(size_t index) const127 WideString CPDF_Array::GetUnicodeTextAt(size_t index) const {
128   if (index >= m_Objects.size())
129     return WideString();
130   return m_Objects[index]->GetUnicodeText();
131 }
132 
GetBooleanAt(size_t index,bool bDefault) const133 bool CPDF_Array::GetBooleanAt(size_t index, bool bDefault) const {
134   if (index >= m_Objects.size())
135     return bDefault;
136   const CPDF_Object* p = m_Objects[index].Get();
137   return ToBoolean(p) ? p->GetInteger() != 0 : bDefault;
138 }
139 
GetIntegerAt(size_t index) const140 int CPDF_Array::GetIntegerAt(size_t index) const {
141   if (index >= m_Objects.size())
142     return 0;
143   return m_Objects[index]->GetInteger();
144 }
145 
GetFloatAt(size_t index) const146 float CPDF_Array::GetFloatAt(size_t index) const {
147   if (index >= m_Objects.size())
148     return 0;
149   return m_Objects[index]->GetNumber();
150 }
151 
GetMutableDictAt(size_t index)152 RetainPtr<CPDF_Dictionary> CPDF_Array::GetMutableDictAt(size_t index) {
153   RetainPtr<CPDF_Object> p = GetMutableDirectObjectAt(index);
154   if (!p)
155     return nullptr;
156   CPDF_Dictionary* pDict = p->AsMutableDictionary();
157   if (pDict)
158     return pdfium::WrapRetain(pDict);
159   CPDF_Stream* pStream = p->AsMutableStream();
160   if (pStream)
161     return pStream->GetMutableDict();
162   return nullptr;
163 }
164 
GetDictAt(size_t index) const165 RetainPtr<const CPDF_Dictionary> CPDF_Array::GetDictAt(size_t index) const {
166   return const_cast<CPDF_Array*>(this)->GetMutableDictAt(index);
167 }
168 
GetMutableStreamAt(size_t index)169 RetainPtr<CPDF_Stream> CPDF_Array::GetMutableStreamAt(size_t index) {
170   return ToStream(GetMutableDirectObjectAt(index));
171 }
172 
GetStreamAt(size_t index) const173 RetainPtr<const CPDF_Stream> CPDF_Array::GetStreamAt(size_t index) const {
174   return const_cast<CPDF_Array*>(this)->GetMutableStreamAt(index);
175 }
176 
GetMutableArrayAt(size_t index)177 RetainPtr<CPDF_Array> CPDF_Array::GetMutableArrayAt(size_t index) {
178   return ToArray(GetMutableDirectObjectAt(index));
179 }
180 
GetArrayAt(size_t index) const181 RetainPtr<const CPDF_Array> CPDF_Array::GetArrayAt(size_t index) const {
182   return const_cast<CPDF_Array*>(this)->GetMutableArrayAt(index);
183 }
184 
GetNumberAt(size_t index) const185 RetainPtr<const CPDF_Number> CPDF_Array::GetNumberAt(size_t index) const {
186   return ToNumber(GetObjectAt(index));
187 }
188 
GetStringAt(size_t index) const189 RetainPtr<const CPDF_String> CPDF_Array::GetStringAt(size_t index) const {
190   return ToString(GetObjectAt(index));
191 }
192 
Clear()193 void CPDF_Array::Clear() {
194   CHECK(!IsLocked());
195   m_Objects.clear();
196 }
197 
RemoveAt(size_t index)198 void CPDF_Array::RemoveAt(size_t index) {
199   CHECK(!IsLocked());
200   if (index < m_Objects.size())
201     m_Objects.erase(m_Objects.begin() + index);
202 }
203 
ConvertToIndirectObjectAt(size_t index,CPDF_IndirectObjectHolder * pHolder)204 void CPDF_Array::ConvertToIndirectObjectAt(size_t index,
205                                            CPDF_IndirectObjectHolder* pHolder) {
206   CHECK(!IsLocked());
207   if (index >= m_Objects.size())
208     return;
209 
210   if (!m_Objects[index] || m_Objects[index]->IsReference())
211     return;
212 
213   pHolder->AddIndirectObject(m_Objects[index]);
214   m_Objects[index] = m_Objects[index]->MakeReference(pHolder);
215 }
216 
SetAt(size_t index,RetainPtr<CPDF_Object> object)217 void CPDF_Array::SetAt(size_t index, RetainPtr<CPDF_Object> object) {
218   (void)SetAtInternal(index, std::move(object));
219 }
220 
InsertAt(size_t index,RetainPtr<CPDF_Object> object)221 void CPDF_Array::InsertAt(size_t index, RetainPtr<CPDF_Object> object) {
222   (void)InsertAtInternal(index, std::move(object));
223 }
224 
Append(RetainPtr<CPDF_Object> object)225 void CPDF_Array::Append(RetainPtr<CPDF_Object> object) {
226   (void)AppendInternal(std::move(object));
227 }
228 
SetAtInternal(size_t index,RetainPtr<CPDF_Object> pObj)229 CPDF_Object* CPDF_Array::SetAtInternal(size_t index,
230                                        RetainPtr<CPDF_Object> pObj) {
231   CHECK(!IsLocked());
232   CHECK(pObj);
233   CHECK(pObj->IsInline());
234   CHECK(!pObj->IsStream());
235   if (index >= m_Objects.size())
236     return nullptr;
237 
238   CPDF_Object* pRet = pObj.Get();
239   m_Objects[index] = std::move(pObj);
240   return pRet;
241 }
242 
InsertAtInternal(size_t index,RetainPtr<CPDF_Object> pObj)243 CPDF_Object* CPDF_Array::InsertAtInternal(size_t index,
244                                           RetainPtr<CPDF_Object> pObj) {
245   CHECK(!IsLocked());
246   CHECK(pObj);
247   CHECK(pObj->IsInline());
248   CHECK(!pObj->IsStream());
249   if (index > m_Objects.size())
250     return nullptr;
251 
252   CPDF_Object* pRet = pObj.Get();
253   m_Objects.insert(m_Objects.begin() + index, std::move(pObj));
254   return pRet;
255 }
256 
AppendInternal(RetainPtr<CPDF_Object> pObj)257 CPDF_Object* CPDF_Array::AppendInternal(RetainPtr<CPDF_Object> pObj) {
258   CHECK(!IsLocked());
259   CHECK(pObj);
260   CHECK(pObj->IsInline());
261   CHECK(!pObj->IsStream());
262   CPDF_Object* pRet = pObj.Get();
263   m_Objects.push_back(std::move(pObj));
264   return pRet;
265 }
266 
WriteTo(IFX_ArchiveStream * archive,const CPDF_Encryptor * encryptor) const267 bool CPDF_Array::WriteTo(IFX_ArchiveStream* archive,
268                          const CPDF_Encryptor* encryptor) const {
269   if (!archive->WriteString("["))
270     return false;
271 
272   for (size_t i = 0; i < size(); ++i) {
273     if (!GetObjectAt(i)->WriteTo(archive, encryptor))
274       return false;
275   }
276   return archive->WriteString("]");
277 }
278 
CPDF_ArrayLocker(const CPDF_Array * pArray)279 CPDF_ArrayLocker::CPDF_ArrayLocker(const CPDF_Array* pArray)
280     : m_pArray(pArray) {
281   m_pArray->m_LockCount++;
282 }
283 
CPDF_ArrayLocker(RetainPtr<CPDF_Array> pArray)284 CPDF_ArrayLocker::CPDF_ArrayLocker(RetainPtr<CPDF_Array> pArray)
285     : m_pArray(std::move(pArray)) {
286   m_pArray->m_LockCount++;
287 }
288 
CPDF_ArrayLocker(RetainPtr<const CPDF_Array> pArray)289 CPDF_ArrayLocker::CPDF_ArrayLocker(RetainPtr<const CPDF_Array> pArray)
290     : m_pArray(std::move(pArray)) {
291   m_pArray->m_LockCount++;
292 }
293 
~CPDF_ArrayLocker()294 CPDF_ArrayLocker::~CPDF_ArrayLocker() {
295   m_pArray->m_LockCount--;
296 }
297