xref: /aosp_15_r20/external/pdfium/core/fpdfapi/parser/cpdf_object_walker.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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()101 RetainPtr<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)114 CPDF_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)122 CPDF_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)132 CPDF_ObjectWalker::CPDF_ObjectWalker(RetainPtr<const CPDF_Object> root)
133     : next_object_(std::move(root)) {}
134 
135 CPDF_ObjectWalker::~CPDF_ObjectWalker() = default;
136 
GetNext()137 RetainPtr<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()165 void CPDF_ObjectWalker::SkipWalkIntoCurrentObject() {
166   if (stack_.empty() || stack_.top()->IsStarted())
167     return;
168   stack_.pop();
169 }
170 
CPDF_NonConstObjectWalker(RetainPtr<CPDF_Object> root)171 CPDF_NonConstObjectWalker::CPDF_NonConstObjectWalker(
172     RetainPtr<CPDF_Object> root)
173     : CPDF_ObjectWalker(std::move(root)) {}
174 
GetNext()175 RetainPtr<CPDF_Object> CPDF_NonConstObjectWalker::GetNext() {
176   return pdfium::WrapRetain(
177       const_cast<CPDF_Object*>(CPDF_ObjectWalker::GetNext().Get()));
178 }
179