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 "core/fxcrt/fx_stream.h"
18 #include "third_party/base/logging.h"
19 #include "third_party/base/stl_util.h"
20
CPDF_Array()21 CPDF_Array::CPDF_Array() {}
22
CPDF_Array(const WeakPtr<ByteStringPool> & pPool)23 CPDF_Array::CPDF_Array(const WeakPtr<ByteStringPool>& pPool) : 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 std::set<const CPDF_Object*> visited(*pVisited);
62 if (auto obj = pValue->CloneNonCyclic(bDirect, &visited))
63 pCopy->m_Objects.push_back(std::move(obj));
64 }
65 }
66 return std::move(pCopy);
67 }
68
GetRect()69 CFX_FloatRect CPDF_Array::GetRect() {
70 CFX_FloatRect rect;
71 if (!IsArray() || m_Objects.size() != 4)
72 return rect;
73
74 rect.left = GetNumberAt(0);
75 rect.bottom = GetNumberAt(1);
76 rect.right = GetNumberAt(2);
77 rect.top = GetNumberAt(3);
78 return rect;
79 }
80
GetMatrix()81 CFX_Matrix CPDF_Array::GetMatrix() {
82 CFX_Matrix matrix;
83 if (!IsArray() || m_Objects.size() != 6)
84 return CFX_Matrix();
85
86 return CFX_Matrix(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2),
87 GetNumberAt(3), GetNumberAt(4), GetNumberAt(5));
88 }
89
GetObjectAt(size_t i) const90 CPDF_Object* CPDF_Array::GetObjectAt(size_t i) const {
91 if (i >= m_Objects.size())
92 return nullptr;
93 return m_Objects[i].get();
94 }
95
GetDirectObjectAt(size_t i) const96 CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t i) const {
97 if (i >= m_Objects.size())
98 return nullptr;
99 return m_Objects[i]->GetDirect();
100 }
101
GetStringAt(size_t i) const102 ByteString CPDF_Array::GetStringAt(size_t i) const {
103 if (i >= m_Objects.size())
104 return ByteString();
105 return m_Objects[i]->GetString();
106 }
107
GetUnicodeTextAt(size_t i) const108 WideString CPDF_Array::GetUnicodeTextAt(size_t i) const {
109 if (i >= m_Objects.size())
110 return WideString();
111 return m_Objects[i]->GetUnicodeText();
112 }
113
GetIntegerAt(size_t i) const114 int CPDF_Array::GetIntegerAt(size_t i) const {
115 if (i >= m_Objects.size())
116 return 0;
117 return m_Objects[i]->GetInteger();
118 }
119
GetNumberAt(size_t i) const120 float CPDF_Array::GetNumberAt(size_t i) const {
121 if (i >= m_Objects.size())
122 return 0;
123 return m_Objects[i]->GetNumber();
124 }
125
GetDictAt(size_t i) const126 CPDF_Dictionary* CPDF_Array::GetDictAt(size_t i) const {
127 CPDF_Object* p = GetDirectObjectAt(i);
128 if (!p)
129 return nullptr;
130 if (CPDF_Dictionary* pDict = p->AsDictionary())
131 return pDict;
132 if (CPDF_Stream* pStream = p->AsStream())
133 return pStream->GetDict();
134 return nullptr;
135 }
136
GetStreamAt(size_t i) const137 CPDF_Stream* CPDF_Array::GetStreamAt(size_t i) const {
138 return ToStream(GetDirectObjectAt(i));
139 }
140
GetArrayAt(size_t i) const141 CPDF_Array* CPDF_Array::GetArrayAt(size_t i) const {
142 return ToArray(GetDirectObjectAt(i));
143 }
144
Clear()145 void CPDF_Array::Clear() {
146 m_Objects.clear();
147 }
148
RemoveAt(size_t i)149 void CPDF_Array::RemoveAt(size_t i) {
150 if (i < m_Objects.size())
151 m_Objects.erase(m_Objects.begin() + i);
152 }
153
ConvertToIndirectObjectAt(size_t i,CPDF_IndirectObjectHolder * pHolder)154 void CPDF_Array::ConvertToIndirectObjectAt(size_t i,
155 CPDF_IndirectObjectHolder* pHolder) {
156 if (i >= m_Objects.size())
157 return;
158
159 if (!m_Objects[i] || m_Objects[i]->IsReference())
160 return;
161
162 CPDF_Object* pNew = pHolder->AddIndirectObject(std::move(m_Objects[i]));
163 m_Objects[i] = pdfium::MakeUnique<CPDF_Reference>(pHolder, pNew->GetObjNum());
164 }
165
SetAt(size_t i,std::unique_ptr<CPDF_Object> pObj)166 CPDF_Object* CPDF_Array::SetAt(size_t i, std::unique_ptr<CPDF_Object> pObj) {
167 ASSERT(IsArray());
168 ASSERT(!pObj || pObj->IsInline());
169 if (i >= m_Objects.size()) {
170 NOTREACHED();
171 return nullptr;
172 }
173 CPDF_Object* pRet = pObj.get();
174 m_Objects[i] = std::move(pObj);
175 return pRet;
176 }
177
InsertAt(size_t index,std::unique_ptr<CPDF_Object> pObj)178 CPDF_Object* CPDF_Array::InsertAt(size_t index,
179 std::unique_ptr<CPDF_Object> pObj) {
180 ASSERT(IsArray());
181 CHECK(!pObj || pObj->IsInline());
182 CPDF_Object* pRet = pObj.get();
183 if (index >= m_Objects.size()) {
184 // Allocate space first.
185 m_Objects.resize(index + 1);
186 m_Objects[index] = std::move(pObj);
187 } else {
188 // Directly insert.
189 m_Objects.insert(m_Objects.begin() + index, std::move(pObj));
190 }
191 return pRet;
192 }
193
Add(std::unique_ptr<CPDF_Object> pObj)194 CPDF_Object* CPDF_Array::Add(std::unique_ptr<CPDF_Object> pObj) {
195 ASSERT(IsArray());
196 CHECK(!pObj || pObj->IsInline());
197 CPDF_Object* pRet = pObj.get();
198 m_Objects.push_back(std::move(pObj));
199 return pRet;
200 }
201
WriteTo(IFX_ArchiveStream * archive) const202 bool CPDF_Array::WriteTo(IFX_ArchiveStream* archive) const {
203 if (!archive->WriteString("["))
204 return false;
205
206 for (size_t i = 0; i < GetCount(); ++i) {
207 CPDF_Object* pElement = GetObjectAt(i);
208 if (!pElement->IsInline()) {
209 if (!archive->WriteString(" ") ||
210 !archive->WriteDWord(pElement->GetObjNum()) ||
211 !archive->WriteString(" 0 R")) {
212 return false;
213 }
214 } else if (!pElement->WriteTo(archive)) {
215 return false;
216 }
217 }
218 return archive->WriteString("]");
219 }
220