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: StreamIterator(const CPDF_Stream * stream)17 explicit StreamIterator(const CPDF_Stream* stream) 18 : SubobjectIterator(stream) {} ~StreamIterator()19 ~StreamIterator() override {} 20 IsFinished() const21 bool IsFinished() const override { return IsStarted() && is_finished_; } 22 IncrementImpl()23 const CPDF_Object* IncrementImpl() override { 24 ASSERT(IsStarted()); 25 ASSERT(!IsFinished()); 26 is_finished_ = true; 27 return object()->GetDict(); 28 } 29 Start()30 void Start() override {} 31 32 private: 33 bool is_finished_ = false; 34 }; 35 36 class DictionaryIterator : public CPDF_ObjectWalker::SubobjectIterator { 37 public: DictionaryIterator(const CPDF_Dictionary * dictionary)38 explicit DictionaryIterator(const CPDF_Dictionary* dictionary) 39 : SubobjectIterator(dictionary) {} ~DictionaryIterator()40 ~DictionaryIterator() override {} 41 IsFinished() const42 bool IsFinished() const override { 43 return IsStarted() && dict_iterator_ == object()->GetDict()->end(); 44 } 45 IncrementImpl()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 Start()55 void Start() override { 56 ASSERT(!IsStarted()); 57 dict_iterator_ = object()->GetDict()->begin(); 58 } 59 dict_key() const60 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: ArrayIterator(const CPDF_Array * array)69 explicit ArrayIterator(const CPDF_Array* array) : SubobjectIterator(array) {} 70 ~ArrayIterator()71 ~ArrayIterator() override {} 72 IsFinished() const73 bool IsFinished() const override { 74 return IsStarted() && arr_iterator_ == object()->AsArray()->end(); 75 } 76 IncrementImpl()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 Start()85 void Start() override { arr_iterator_ = object()->AsArray()->begin(); } 86 87 public: 88 CPDF_Array::const_iterator arr_iterator_; 89 }; 90 91 } // namespace 92 ~SubobjectIterator()93CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() {} 94 Increment()95const 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 SubobjectIterator(const CPDF_Object * object)108CPDF_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> MakeIterator(const CPDF_Object * object)116CPDF_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 CPDF_ObjectWalker(const CPDF_Object * root)126CPDF_ObjectWalker::CPDF_ObjectWalker(const CPDF_Object* root) 127 : next_object_(root), parent_object_(nullptr), current_depth_(0) {} 128 ~CPDF_ObjectWalker()129CPDF_ObjectWalker::~CPDF_ObjectWalker() {} 130 GetNext()131const 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 SkipWalkIntoCurrentObject()161void CPDF_ObjectWalker::SkipWalkIntoCurrentObject() { 162 if (stack_.empty() || stack_.top()->IsStarted()) 163 return; 164 stack_.pop(); 165 } 166