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_name.h"
13 #include "core/fpdfapi/parser/cpdf_number.h"
14 #include "core/fpdfapi/parser/cpdf_reference.h"
15 #include "core/fpdfapi/parser/cpdf_stream.h"
16 #include "core/fpdfapi/parser/cpdf_string.h"
17 #include "third_party/base/logging.h"
18 #include "third_party/base/stl_util.h"
19
CPDF_Array()20 CPDF_Array::CPDF_Array() {}
21
CPDF_Array(const CFX_WeakPtr<CFX_ByteStringPool> & pPool)22 CPDF_Array::CPDF_Array(const CFX_WeakPtr<CFX_ByteStringPool>& pPool)
23 : m_pPool(pPool) {}
24
~CPDF_Array()25 CPDF_Array::~CPDF_Array() {
26 // Break cycles for cyclic references.
27 m_ObjNum = kInvalidObjNum;
28 for (auto& it : m_Objects) {
29 if (it && it->GetObjNum() == kInvalidObjNum)
30 it.release();
31 }
32 }
33
GetType() const34 CPDF_Object::Type CPDF_Array::GetType() const {
35 return ARRAY;
36 }
37
IsArray() const38 bool CPDF_Array::IsArray() const {
39 return true;
40 }
41
AsArray()42 CPDF_Array* CPDF_Array::AsArray() {
43 return this;
44 }
45
AsArray() const46 const CPDF_Array* CPDF_Array::AsArray() const {
47 return this;
48 }
49
Clone() const50 std::unique_ptr<CPDF_Object> CPDF_Array::Clone() const {
51 return CloneObjectNonCyclic(false);
52 }
53
CloneNonCyclic(bool bDirect,std::set<const CPDF_Object * > * pVisited) const54 std::unique_ptr<CPDF_Object> CPDF_Array::CloneNonCyclic(
55 bool bDirect,
56 std::set<const CPDF_Object*>* pVisited) const {
57 pVisited->insert(this);
58 auto pCopy = pdfium::MakeUnique<CPDF_Array>();
59 for (const auto& pValue : m_Objects) {
60 if (!pdfium::ContainsKey(*pVisited, pValue.get()))
61 pCopy->m_Objects.push_back(pValue->CloneNonCyclic(bDirect, pVisited));
62 }
63 return std::move(pCopy);
64 }
65
GetRect()66 CFX_FloatRect CPDF_Array::GetRect() {
67 CFX_FloatRect rect;
68 if (!IsArray() || m_Objects.size() != 4)
69 return rect;
70
71 rect.left = GetNumberAt(0);
72 rect.bottom = GetNumberAt(1);
73 rect.right = GetNumberAt(2);
74 rect.top = GetNumberAt(3);
75 return rect;
76 }
77
GetMatrix()78 CFX_Matrix CPDF_Array::GetMatrix() {
79 CFX_Matrix matrix;
80 if (!IsArray() || m_Objects.size() != 6)
81 return CFX_Matrix();
82
83 return CFX_Matrix(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2),
84 GetNumberAt(3), GetNumberAt(4), GetNumberAt(5));
85 }
86
GetObjectAt(size_t i) const87 CPDF_Object* CPDF_Array::GetObjectAt(size_t i) const {
88 if (i >= m_Objects.size())
89 return nullptr;
90 return m_Objects[i].get();
91 }
92
GetDirectObjectAt(size_t i) const93 CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t i) const {
94 if (i >= m_Objects.size())
95 return nullptr;
96 return m_Objects[i]->GetDirect();
97 }
98
GetStringAt(size_t i) const99 CFX_ByteString CPDF_Array::GetStringAt(size_t i) const {
100 if (i >= m_Objects.size())
101 return CFX_ByteString();
102 return m_Objects[i]->GetString();
103 }
104
GetIntegerAt(size_t i) const105 int CPDF_Array::GetIntegerAt(size_t i) const {
106 if (i >= m_Objects.size())
107 return 0;
108 return m_Objects[i]->GetInteger();
109 }
110
GetNumberAt(size_t i) const111 FX_FLOAT CPDF_Array::GetNumberAt(size_t i) const {
112 if (i >= m_Objects.size())
113 return 0;
114 return m_Objects[i]->GetNumber();
115 }
116
GetDictAt(size_t i) const117 CPDF_Dictionary* CPDF_Array::GetDictAt(size_t i) const {
118 CPDF_Object* p = GetDirectObjectAt(i);
119 if (!p)
120 return nullptr;
121 if (CPDF_Dictionary* pDict = p->AsDictionary())
122 return pDict;
123 if (CPDF_Stream* pStream = p->AsStream())
124 return pStream->GetDict();
125 return nullptr;
126 }
127
GetStreamAt(size_t i) const128 CPDF_Stream* CPDF_Array::GetStreamAt(size_t i) const {
129 return ToStream(GetDirectObjectAt(i));
130 }
131
GetArrayAt(size_t i) const132 CPDF_Array* CPDF_Array::GetArrayAt(size_t i) const {
133 return ToArray(GetDirectObjectAt(i));
134 }
135
RemoveAt(size_t i,size_t nCount)136 void CPDF_Array::RemoveAt(size_t i, size_t nCount) {
137 if (i >= m_Objects.size())
138 return;
139
140 if (nCount <= 0 || nCount > m_Objects.size() - i)
141 return;
142
143 m_Objects.erase(m_Objects.begin() + i, m_Objects.begin() + i + nCount);
144 }
145
ConvertToIndirectObjectAt(size_t i,CPDF_IndirectObjectHolder * pHolder)146 void CPDF_Array::ConvertToIndirectObjectAt(size_t i,
147 CPDF_IndirectObjectHolder* pHolder) {
148 if (i >= m_Objects.size())
149 return;
150
151 if (!m_Objects[i] || m_Objects[i]->IsReference())
152 return;
153
154 CPDF_Object* pNew = pHolder->AddIndirectObject(std::move(m_Objects[i]));
155 m_Objects[i] = pdfium::MakeUnique<CPDF_Reference>(pHolder, pNew->GetObjNum());
156 }
157
SetAt(size_t i,std::unique_ptr<CPDF_Object> pObj)158 CPDF_Object* CPDF_Array::SetAt(size_t i, std::unique_ptr<CPDF_Object> pObj) {
159 ASSERT(IsArray());
160 ASSERT(!pObj || pObj->IsInline());
161 if (i >= m_Objects.size()) {
162 ASSERT(false);
163 return nullptr;
164 }
165 CPDF_Object* pRet = pObj.get();
166 m_Objects[i] = std::move(pObj);
167 return pRet;
168 }
169
InsertAt(size_t index,std::unique_ptr<CPDF_Object> pObj)170 CPDF_Object* CPDF_Array::InsertAt(size_t index,
171 std::unique_ptr<CPDF_Object> pObj) {
172 ASSERT(IsArray());
173 CHECK(!pObj || pObj->IsInline());
174 CPDF_Object* pRet = pObj.get();
175 if (index >= m_Objects.size()) {
176 // Allocate space first.
177 m_Objects.resize(index + 1);
178 m_Objects[index] = std::move(pObj);
179 } else {
180 // Directly insert.
181 m_Objects.insert(m_Objects.begin() + index, std::move(pObj));
182 }
183 return pRet;
184 }
185
Add(std::unique_ptr<CPDF_Object> pObj)186 CPDF_Object* CPDF_Array::Add(std::unique_ptr<CPDF_Object> pObj) {
187 ASSERT(IsArray());
188 CHECK(!pObj || pObj->IsInline());
189 CPDF_Object* pRet = pObj.get();
190 m_Objects.push_back(std::move(pObj));
191 return pRet;
192 }
193