• 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 
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()93 CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() {}
94 
Increment()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 
SubobjectIterator(const CPDF_Object * object)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>
MakeIterator(const CPDF_Object * object)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 
CPDF_ObjectWalker(const CPDF_Object * root)126 CPDF_ObjectWalker::CPDF_ObjectWalker(const CPDF_Object* root)
127     : next_object_(root), parent_object_(nullptr), current_depth_(0) {}
128 
~CPDF_ObjectWalker()129 CPDF_ObjectWalker::~CPDF_ObjectWalker() {}
130 
GetNext()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 
SkipWalkIntoCurrentObject()161 void CPDF_ObjectWalker::SkipWalkIntoCurrentObject() {
162   if (stack_.empty() || stack_.top()->IsStarted())
163     return;
164   stack_.pop();
165 }
166