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 "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