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