• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()97 CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() {}
98 
Increment()99 const 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)112 CPDF_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)120 CPDF_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)130 CPDF_ObjectWalker::CPDF_ObjectWalker(const CPDF_Object* root)
131     : next_object_(root) {}
132 
133 CPDF_ObjectWalker::~CPDF_ObjectWalker() = default;
134 
GetNext()135 const 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()165 void CPDF_ObjectWalker::SkipWalkIntoCurrentObject() {
166   if (stack_.empty() || stack_.top()->IsStarted())
167     return;
168   stack_.pop();
169 }
170