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 21 CPDF_Array::CPDF_Array() {} 22 23 CPDF_Array::CPDF_Array(const WeakPtr<ByteStringPool>& pPool) : 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 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 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 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 90 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 96 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 102 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 108 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 114 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 120 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 126 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 137 CPDF_Stream* CPDF_Array::GetStreamAt(size_t i) const { 138 return ToStream(GetDirectObjectAt(i)); 139 } 140 141 CPDF_Array* CPDF_Array::GetArrayAt(size_t i) const { 142 return ToArray(GetDirectObjectAt(i)); 143 } 144 145 void CPDF_Array::Clear() { 146 m_Objects.clear(); 147 } 148 149 void CPDF_Array::RemoveAt(size_t i) { 150 if (i < m_Objects.size()) 151 m_Objects.erase(m_Objects.begin() + i); 152 } 153 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 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 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 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 202 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