Home | History | Annotate | Download | only in fpdfdoc
      1 // Copyright 2017 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/fpdfdoc/cpdf_structelement.h"
      8 
      9 #include "core/fpdfapi/parser/cpdf_array.h"
     10 #include "core/fpdfapi/parser/cpdf_dictionary.h"
     11 #include "core/fpdfapi/parser/cpdf_name.h"
     12 #include "core/fpdfapi/parser/cpdf_number.h"
     13 #include "core/fpdfapi/parser/cpdf_object.h"
     14 #include "core/fpdfapi/parser/cpdf_reference.h"
     15 #include "core/fpdfapi/parser/cpdf_stream.h"
     16 #include "core/fpdfdoc/cpdf_structtree.h"
     17 
     18 CPDF_StructKid::CPDF_StructKid()
     19     : m_Type(Invalid),
     20       m_pDict(nullptr),
     21       m_PageObjNum(0),
     22       m_RefObjNum(0),
     23       m_ContentId(0) {}
     24 
     25 CPDF_StructKid::CPDF_StructKid(const CPDF_StructKid& that) = default;
     26 
     27 CPDF_StructKid::~CPDF_StructKid() = default;
     28 
     29 CPDF_StructElement::CPDF_StructElement(CPDF_StructTree* pTree,
     30                                        CPDF_StructElement* pParent,
     31                                        CPDF_Dictionary* pDict)
     32     : m_pTree(pTree),
     33       m_pParent(pParent),
     34       m_pDict(pDict),
     35       m_Type(pDict->GetStringFor("S")),
     36       m_Title(pDict->GetStringFor("T")) {
     37   if (pTree->GetRoleMap()) {
     38     ByteString mapped = pTree->GetRoleMap()->GetStringFor(m_Type);
     39     if (!mapped.IsEmpty())
     40       m_Type = mapped;
     41   }
     42   LoadKids(pDict);
     43 }
     44 
     45 CPDF_StructElement::~CPDF_StructElement() = default;
     46 
     47 size_t CPDF_StructElement::CountKids() const {
     48   return m_Kids.size();
     49 }
     50 
     51 CPDF_StructElement* CPDF_StructElement::GetKidIfElement(size_t index) const {
     52   return m_Kids[index].m_Type == CPDF_StructKid::Element
     53              ? m_Kids[index].m_pElement.Get()
     54              : nullptr;
     55 }
     56 
     57 void CPDF_StructElement::LoadKids(CPDF_Dictionary* pDict) {
     58   CPDF_Object* pObj = pDict->GetObjectFor("Pg");
     59   uint32_t PageObjNum = 0;
     60   if (CPDF_Reference* pRef = ToReference(pObj))
     61     PageObjNum = pRef->GetRefObjNum();
     62 
     63   CPDF_Object* pKids = pDict->GetDirectObjectFor("K");
     64   if (!pKids)
     65     return;
     66 
     67   m_Kids.clear();
     68   if (CPDF_Array* pArray = pKids->AsArray()) {
     69     m_Kids.resize(pArray->GetCount());
     70     for (uint32_t i = 0; i < pArray->GetCount(); i++) {
     71       CPDF_Object* pKid = pArray->GetDirectObjectAt(i);
     72       LoadKid(PageObjNum, pKid, &m_Kids[i]);
     73     }
     74     return;
     75   }
     76 
     77   m_Kids.resize(1);
     78   LoadKid(PageObjNum, pKids, &m_Kids[0]);
     79 }
     80 
     81 void CPDF_StructElement::LoadKid(uint32_t PageObjNum,
     82                                  CPDF_Object* pKidObj,
     83                                  CPDF_StructKid* pKid) {
     84   pKid->m_Type = CPDF_StructKid::Invalid;
     85   if (!pKidObj)
     86     return;
     87 
     88   if (pKidObj->IsNumber()) {
     89     if (m_pTree->GetPage() && m_pTree->GetPage()->GetObjNum() != PageObjNum)
     90       return;
     91 
     92     pKid->m_Type = CPDF_StructKid::PageContent;
     93     pKid->m_ContentId = pKidObj->GetInteger();
     94     pKid->m_PageObjNum = PageObjNum;
     95     return;
     96   }
     97 
     98   CPDF_Dictionary* pKidDict = pKidObj->AsDictionary();
     99   if (!pKidDict)
    100     return;
    101   if (CPDF_Reference* pRef = ToReference(pKidDict->GetObjectFor("Pg")))
    102     PageObjNum = pRef->GetRefObjNum();
    103 
    104   ByteString type = pKidDict->GetStringFor("Type");
    105   if ((type == "MCR" || type == "OBJR") && m_pTree->GetPage() &&
    106       m_pTree->GetPage()->GetObjNum() != PageObjNum) {
    107     return;
    108   }
    109 
    110   if (type == "MCR") {
    111     pKid->m_Type = CPDF_StructKid::StreamContent;
    112     CPDF_Reference* pRef = ToReference(pKidDict->GetObjectFor("Stm"));
    113     pKid->m_RefObjNum = pRef ? pRef->GetRefObjNum() : 0;
    114     pKid->m_PageObjNum = PageObjNum;
    115     pKid->m_ContentId = pKidDict->GetIntegerFor("MCID");
    116     return;
    117   }
    118 
    119   if (type == "OBJR") {
    120     pKid->m_Type = CPDF_StructKid::Object;
    121     CPDF_Reference* pObj = ToReference(pKidDict->GetObjectFor("Obj"));
    122     pKid->m_RefObjNum = pObj ? pObj->GetRefObjNum() : 0;
    123     pKid->m_PageObjNum = PageObjNum;
    124     return;
    125   }
    126 
    127   pKid->m_Type = CPDF_StructKid::Element;
    128   pKid->m_pDict = pKidDict;
    129   if (m_pTree->GetPage()) {
    130     pKid->m_pElement = nullptr;
    131     return;
    132   }
    133 
    134   pKid->m_pElement =
    135       pdfium::MakeRetain<CPDF_StructElement>(m_pTree.Get(), this, pKidDict);
    136 }
    137