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 20 CPDF_Array::CPDF_Array() {} 21 22 CPDF_Array::CPDF_Array(const CFX_WeakPtr<CFX_ByteStringPool>& pPool) 23 : m_pPool(pPool) {} 24 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 34 CPDF_Object::Type CPDF_Array::GetType() const { 35 return ARRAY; 36 } 37 38 bool CPDF_Array::IsArray() const { 39 return true; 40 } 41 42 CPDF_Array* CPDF_Array::AsArray() { 43 return this; 44 } 45 46 const CPDF_Array* CPDF_Array::AsArray() const { 47 return this; 48 } 49 50 std::unique_ptr<CPDF_Object> CPDF_Array::Clone() const { 51 return CloneObjectNonCyclic(false); 52 } 53 54 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 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 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 87 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 93 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 99 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 105 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 111 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 117 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 128 CPDF_Stream* CPDF_Array::GetStreamAt(size_t i) const { 129 return ToStream(GetDirectObjectAt(i)); 130 } 131 132 CPDF_Array* CPDF_Array::GetArrayAt(size_t i) const { 133 return ToArray(GetDirectObjectAt(i)); 134 } 135 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 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 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 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 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