Home | History | Annotate | Download | only in parser
      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 #include "core/fpdfapi/parser/cpdf_object_walker.h"
      6 
      7 #include <utility>
      8 
      9 #include "core/fpdfapi/parser/cpdf_array.h"
     10 #include "core/fpdfapi/parser/cpdf_dictionary.h"
     11 #include "core/fpdfapi/parser/cpdf_stream.h"
     12 
     13 namespace {
     14 
     15 class StreamIterator : public CPDF_ObjectWalker::SubobjectIterator {
     16  public:
     17   explicit StreamIterator(const CPDF_Stream* stream)
     18       : SubobjectIterator(stream) {}
     19   ~StreamIterator() override {}
     20 
     21   bool IsFinished() const override { return IsStarted() && is_finished_; }
     22 
     23   const CPDF_Object* IncrementImpl() override {
     24     ASSERT(IsStarted());
     25     ASSERT(!IsFinished());
     26     is_finished_ = true;
     27     return object()->GetDict();
     28   }
     29 
     30   void Start() override {}
     31 
     32  private:
     33   bool is_finished_ = false;
     34 };
     35 
     36 class DictionaryIterator : public CPDF_ObjectWalker::SubobjectIterator {
     37  public:
     38   explicit DictionaryIterator(const CPDF_Dictionary* dictionary)
     39       : SubobjectIterator(dictionary) {}
     40   ~DictionaryIterator() override {}
     41 
     42   bool IsFinished() const override {
     43     return IsStarted() && dict_iterator_ == object()->GetDict()->end();
     44   }
     45 
     46   const CPDF_Object* IncrementImpl() override {
     47     ASSERT(IsStarted());
     48     ASSERT(!IsFinished());
     49     const CPDF_Object* result = dict_iterator_->second.get();
     50     dict_key_ = dict_iterator_->first;
     51     ++dict_iterator_;
     52     return result;
     53   }
     54 
     55   void Start() override {
     56     ASSERT(!IsStarted());
     57     dict_iterator_ = object()->GetDict()->begin();
     58   }
     59 
     60   const ByteString& dict_key() const { return dict_key_; }
     61 
     62  private:
     63   CPDF_Dictionary::const_iterator dict_iterator_;
     64   ByteString dict_key_;
     65 };
     66 
     67 class ArrayIterator : public CPDF_ObjectWalker::SubobjectIterator {
     68  public:
     69   explicit ArrayIterator(const CPDF_Array* array) : SubobjectIterator(array) {}
     70 
     71   ~ArrayIterator() override {}
     72 
     73   bool IsFinished() const override {
     74     return IsStarted() && arr_iterator_ == object()->AsArray()->end();
     75   }
     76 
     77   const CPDF_Object* IncrementImpl() override {
     78     ASSERT(IsStarted());
     79     ASSERT(!IsFinished());
     80     const CPDF_Object* result = arr_iterator_->get();
     81     ++arr_iterator_;
     82     return result;
     83   }
     84 
     85   void Start() override { arr_iterator_ = object()->AsArray()->begin(); }
     86 
     87  public:
     88   CPDF_Array::const_iterator arr_iterator_;
     89 };
     90 
     91 }  // namespace
     92 
     93 CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() {}
     94 
     95 const CPDF_Object* CPDF_ObjectWalker::SubobjectIterator::Increment() {
     96   if (!IsStarted()) {
     97     Start();
     98     is_started_ = true;
     99   }
    100   while (!IsFinished()) {
    101     const CPDF_Object* result = IncrementImpl();
    102     if (result)
    103       return result;
    104   }
    105   return nullptr;
    106 }
    107 
    108 CPDF_ObjectWalker::SubobjectIterator::SubobjectIterator(
    109     const CPDF_Object* object)
    110     : object_(object) {
    111   ASSERT(object_);
    112 }
    113 
    114 // static
    115 std::unique_ptr<CPDF_ObjectWalker::SubobjectIterator>
    116 CPDF_ObjectWalker::MakeIterator(const CPDF_Object* object) {
    117   if (object->IsStream())
    118     return pdfium::MakeUnique<StreamIterator>(object->AsStream());
    119   if (object->IsDictionary())
    120     return pdfium::MakeUnique<DictionaryIterator>(object->AsDictionary());
    121   if (object->IsArray())
    122     return pdfium::MakeUnique<ArrayIterator>(object->AsArray());
    123   return nullptr;
    124 }
    125 
    126 CPDF_ObjectWalker::CPDF_ObjectWalker(const CPDF_Object* root)
    127     : next_object_(root), parent_object_(nullptr), current_depth_(0) {}
    128 
    129 CPDF_ObjectWalker::~CPDF_ObjectWalker() {}
    130 
    131 const CPDF_Object* CPDF_ObjectWalker::GetNext() {
    132   while (!stack_.empty() || next_object_) {
    133     if (next_object_) {
    134       auto new_iterator = MakeIterator(next_object_);
    135       if (new_iterator) {
    136         // Schedule walk within composite objects.
    137         stack_.push(std::move(new_iterator));
    138       }
    139       auto* result = next_object_;
    140       next_object_ = nullptr;
    141       return result;
    142     }
    143 
    144     SubobjectIterator* it = stack_.top().get();
    145     if (it->IsFinished()) {
    146       stack_.pop();
    147     } else {
    148       next_object_ = it->Increment();
    149       parent_object_ = it->object();
    150       dict_key_ = parent_object_->IsDictionary()
    151                       ? static_cast<DictionaryIterator*>(it)->dict_key()
    152                       : ByteString();
    153       current_depth_ = stack_.size();
    154     }
    155   }
    156   dict_key_ = ByteString();
    157   current_depth_ = 0;
    158   return nullptr;
    159 }
    160 
    161 void CPDF_ObjectWalker::SkipWalkIntoCurrentObject() {
    162   if (stack_.empty() || stack_.top()->IsStarted())
    163     return;
    164   stack_.pop();
    165 }
    166