1 // Copyright 2017 The PDFium Authors 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/check.h" 13 14 namespace { 15 16 class StreamIterator final : public CPDF_ObjectWalker::SubobjectIterator { 17 public: StreamIterator(RetainPtr<const CPDF_Stream> stream)18 explicit StreamIterator(RetainPtr<const CPDF_Stream> stream) 19 : SubobjectIterator(std::move(stream)) {} 20 21 ~StreamIterator() override = default; 22 IsFinished() const23 bool IsFinished() const override { return IsStarted() && is_finished_; } 24 IncrementImpl()25 RetainPtr<const CPDF_Object> IncrementImpl() override { 26 DCHECK(IsStarted()); 27 DCHECK(!IsFinished()); 28 is_finished_ = true; 29 return object()->GetDict(); 30 } 31 Start()32 void Start() override {} 33 34 private: 35 bool is_finished_ = false; 36 }; 37 38 class DictionaryIterator final : public CPDF_ObjectWalker::SubobjectIterator { 39 public: DictionaryIterator(RetainPtr<const CPDF_Dictionary> dictionary)40 explicit DictionaryIterator(RetainPtr<const CPDF_Dictionary> dictionary) 41 : SubobjectIterator(dictionary), locker_(dictionary) {} 42 43 ~DictionaryIterator() override = default; 44 IsFinished() const45 bool IsFinished() const override { 46 return IsStarted() && dict_iterator_ == locker_.end(); 47 } 48 IncrementImpl()49 RetainPtr<const CPDF_Object> IncrementImpl() override { 50 DCHECK(IsStarted()); 51 DCHECK(!IsFinished()); 52 RetainPtr<const CPDF_Object> result = dict_iterator_->second; 53 dict_key_ = dict_iterator_->first; 54 ++dict_iterator_; 55 return result; 56 } 57 Start()58 void Start() override { 59 DCHECK(!IsStarted()); 60 dict_iterator_ = locker_.begin(); 61 } 62 dict_key() const63 ByteString dict_key() const { return dict_key_; } 64 65 private: 66 CPDF_Dictionary::const_iterator dict_iterator_; 67 CPDF_DictionaryLocker locker_; 68 ByteString dict_key_; 69 }; 70 71 class ArrayIterator final : public CPDF_ObjectWalker::SubobjectIterator { 72 public: ArrayIterator(RetainPtr<const CPDF_Array> array)73 explicit ArrayIterator(RetainPtr<const CPDF_Array> array) 74 : SubobjectIterator(array), locker_(array) {} 75 76 ~ArrayIterator() override = default; 77 IsFinished() const78 bool IsFinished() const override { 79 return IsStarted() && arr_iterator_ == locker_.end(); 80 } 81 IncrementImpl()82 RetainPtr<const CPDF_Object> IncrementImpl() override { 83 DCHECK(IsStarted()); 84 DCHECK(!IsFinished()); 85 RetainPtr<const CPDF_Object> result = *arr_iterator_; 86 ++arr_iterator_; 87 return result; 88 } 89 Start()90 void Start() override { arr_iterator_ = locker_.begin(); } 91 92 public: 93 CPDF_Array::const_iterator arr_iterator_; 94 CPDF_ArrayLocker locker_; 95 }; 96 97 } // namespace 98 99 CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() = default; 100 Increment()101RetainPtr<const CPDF_Object> CPDF_ObjectWalker::SubobjectIterator::Increment() { 102 if (!IsStarted()) { 103 Start(); 104 is_started_ = true; 105 } 106 while (!IsFinished()) { 107 RetainPtr<const CPDF_Object> result = IncrementImpl(); 108 if (result) 109 return result; 110 } 111 return nullptr; 112 } 113 SubobjectIterator(RetainPtr<const CPDF_Object> object)114CPDF_ObjectWalker::SubobjectIterator::SubobjectIterator( 115 RetainPtr<const CPDF_Object> object) 116 : object_(std::move(object)) { 117 DCHECK(object_); 118 } 119 120 // static 121 std::unique_ptr<CPDF_ObjectWalker::SubobjectIterator> MakeIterator(RetainPtr<const CPDF_Object> object)122CPDF_ObjectWalker::MakeIterator(RetainPtr<const CPDF_Object> object) { 123 if (object->IsStream()) 124 return std::make_unique<StreamIterator>(ToStream(object)); 125 if (object->IsDictionary()) 126 return std::make_unique<DictionaryIterator>(ToDictionary(object)); 127 if (object->IsArray()) 128 return std::make_unique<ArrayIterator>(ToArray(object)); 129 return nullptr; 130 } 131 CPDF_ObjectWalker(RetainPtr<const CPDF_Object> root)132CPDF_ObjectWalker::CPDF_ObjectWalker(RetainPtr<const CPDF_Object> root) 133 : next_object_(std::move(root)) {} 134 135 CPDF_ObjectWalker::~CPDF_ObjectWalker() = default; 136 GetNext()137RetainPtr<const CPDF_Object> CPDF_ObjectWalker::GetNext() { 138 while (!stack_.empty() || next_object_) { 139 if (next_object_) { 140 auto new_iterator = MakeIterator(next_object_); 141 if (new_iterator) { 142 // Schedule walk within composite objects. 143 stack_.push(std::move(new_iterator)); 144 } 145 return std::move(next_object_); // next_object_ is NULL after move. 146 } 147 148 SubobjectIterator* it = stack_.top().get(); 149 if (it->IsFinished()) { 150 stack_.pop(); 151 } else { 152 next_object_ = 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 CPDF_NonConstObjectWalker(RetainPtr<CPDF_Object> root)171CPDF_NonConstObjectWalker::CPDF_NonConstObjectWalker( 172 RetainPtr<CPDF_Object> root) 173 : CPDF_ObjectWalker(std::move(root)) {} 174 GetNext()175RetainPtr<CPDF_Object> CPDF_NonConstObjectWalker::GetNext() { 176 return pdfium::WrapRetain( 177 const_cast<CPDF_Object*>(CPDF_ObjectWalker::GetNext().Get())); 178 } 179