From f57cad4f5dd0436d5b207d362afb34fc5f3f9acb Mon Sep 17 00:00:00 2001 From: Artem Strygin Date: Mon, 14 Aug 2017 23:35:52 +0300 Subject: Add CPDF_ObjectWalker. It is allow us to walk on all non-null sub-objects in an object in depth, include itself, Change-Id: Ia23051073984411668112422b47cf7a4460aa078 Reviewed-on: https://pdfium-review.googlesource.com/8910 Commit-Queue: Art Snake Reviewed-by: dsinclair --- core/fpdfapi/parser/cpdf_object_walker.cpp | 165 +++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 core/fpdfapi/parser/cpdf_object_walker.cpp (limited to 'core/fpdfapi/parser/cpdf_object_walker.cpp') diff --git a/core/fpdfapi/parser/cpdf_object_walker.cpp b/core/fpdfapi/parser/cpdf_object_walker.cpp new file mode 100644 index 0000000000..c6e0f0091d --- /dev/null +++ b/core/fpdfapi/parser/cpdf_object_walker.cpp @@ -0,0 +1,165 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/parser/cpdf_object_walker.h" + +#include + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream.h" + +namespace { + +class StreamIterator : public CPDF_ObjectWalker::SubobjectIterator { + public: + explicit StreamIterator(const CPDF_Stream* stream) + : SubobjectIterator(stream) {} + ~StreamIterator() override {} + + bool IsFinished() const override { return IsStarted() && is_finished_; } + + const CPDF_Object* IncrementImpl() override { + ASSERT(IsStarted()); + ASSERT(!IsFinished()); + is_finished_ = true; + return object()->GetDict(); + } + + void Start() override {} + + private: + bool is_finished_ = false; +}; + +class DictionaryIterator : public CPDF_ObjectWalker::SubobjectIterator { + public: + explicit DictionaryIterator(const CPDF_Dictionary* dictionary) + : SubobjectIterator(dictionary) {} + ~DictionaryIterator() override {} + + bool IsFinished() const override { + return IsStarted() && dict_iterator_ == object()->GetDict()->end(); + } + + const CPDF_Object* IncrementImpl() override { + ASSERT(IsStarted()); + ASSERT(!IsFinished()); + const CPDF_Object* result = dict_iterator_->second.get(); + dict_key_ = dict_iterator_->first; + ++dict_iterator_; + return result; + } + + void Start() override { + ASSERT(!IsStarted()); + dict_iterator_ = object()->GetDict()->begin(); + } + + const CFX_ByteString& dict_key() const { return dict_key_; } + + private: + CPDF_Dictionary::const_iterator dict_iterator_; + CFX_ByteString dict_key_; +}; + +class ArrayIterator : public CPDF_ObjectWalker::SubobjectIterator { + public: + explicit ArrayIterator(const CPDF_Array* array) : SubobjectIterator(array) {} + + ~ArrayIterator() override {} + + bool IsFinished() const override { + return IsStarted() && arr_iterator_ == object()->AsArray()->end(); + } + + const CPDF_Object* IncrementImpl() override { + ASSERT(IsStarted()); + ASSERT(!IsFinished()); + const CPDF_Object* result = arr_iterator_->get(); + ++arr_iterator_; + return result; + } + + void Start() override { arr_iterator_ = object()->AsArray()->begin(); } + + public: + CPDF_Array::const_iterator arr_iterator_; +}; + +} // namespace + +CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() {} + +const CPDF_Object* CPDF_ObjectWalker::SubobjectIterator::Increment() { + if (!IsStarted()) { + Start(); + is_started_ = true; + } + while (!IsFinished()) { + const CPDF_Object* result = IncrementImpl(); + if (result) + return result; + } + return nullptr; +} + +CPDF_ObjectWalker::SubobjectIterator::SubobjectIterator( + const CPDF_Object* object) + : object_(object) { + ASSERT(object_); +} + +// static +std::unique_ptr +CPDF_ObjectWalker::MakeIterator(const CPDF_Object* object) { + if (object->IsStream()) + return pdfium::MakeUnique(object->AsStream()); + if (object->IsDictionary()) + return pdfium::MakeUnique(object->AsDictionary()); + if (object->IsArray()) + return pdfium::MakeUnique(object->AsArray()); + return nullptr; +} + +CPDF_ObjectWalker::CPDF_ObjectWalker(const CPDF_Object* root) + : next_object_(root), parent_object_(nullptr), current_depth_(0) {} + +CPDF_ObjectWalker::~CPDF_ObjectWalker() {} + +const CPDF_Object* CPDF_ObjectWalker::GetNext() { + while (!stack_.empty() || next_object_) { + if (next_object_) { + auto new_iterator = MakeIterator(next_object_); + if (new_iterator) { + // Schedule walk within composite objects. + stack_.push(std::move(new_iterator)); + } + auto* result = next_object_; + next_object_ = nullptr; + return result; + } + + SubobjectIterator* it = stack_.top().get(); + if (it->IsFinished()) { + stack_.pop(); + } else { + next_object_ = it->Increment(); + parent_object_ = it->object(); + dict_key_ = parent_object_->IsDictionary() + ? static_cast(it)->dict_key() + : CFX_ByteString(); + current_depth_ = stack_.size(); + } + } + dict_key_ = CFX_ByteString(); + current_depth_ = 0; + return nullptr; +} + +void CPDF_ObjectWalker::SkipWalkIntoCurrentObject() { + if (stack_.empty() || stack_.top()->IsStarted()) + return; + stack_.pop(); +} -- cgit v1.2.3