Home | History | Annotate | Download | only in parser
      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