1 // Copyright (c) 2016 The WebM project authors. All Rights Reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. An additional intellectual property rights grant can be found 6 // in the file PATENTS. All contributing project authors may 7 // be found in the AUTHORS file in the root of the source tree. 8 #ifndef SRC_RECURSIVE_PARSER_H_ 9 #define SRC_RECURSIVE_PARSER_H_ 10 11 #include <cassert> 12 #include <cstdint> 13 #include <memory> 14 #include <utility> 15 16 #include "src/element_parser.h" 17 #include "webm/callback.h" 18 #include "webm/reader.h" 19 #include "webm/status.h" 20 21 namespace webm { 22 23 // Lazily instantiates a parser of type T, and uses that parser to handle all 24 // parsing operations. The parser is allocated when Init is called. This class 25 // is intended to be used with recursive elements, where a parser needs to 26 // recursively instantiate parsers of the same type. 27 template <typename T> 28 class RecursiveParser : public ElementParser { 29 public: 30 explicit RecursiveParser(std::size_t max_recursion_depth = 25) max_recursion_depth_(max_recursion_depth)31 : max_recursion_depth_(max_recursion_depth){}; 32 33 RecursiveParser(RecursiveParser&&) = default; 34 RecursiveParser& operator=(RecursiveParser&&) = default; 35 36 RecursiveParser(const RecursiveParser&) = delete; 37 RecursiveParser& operator=(const RecursiveParser&) = delete; 38 Init(const ElementMetadata & metadata,std::uint64_t max_size)39 Status Init(const ElementMetadata& metadata, 40 std::uint64_t max_size) override { 41 assert(metadata.size == kUnknownElementSize || metadata.size <= max_size); 42 43 if (max_recursion_depth_ == 0) { 44 return Status(Status::kExceededRecursionDepthLimit); 45 } 46 47 if (!impl_) { 48 impl_.reset(new T(max_recursion_depth_ - 1)); 49 } 50 51 return impl_->Init(metadata, max_size); 52 } 53 InitAfterSeek(const Ancestory & child_ancestory,const ElementMetadata & child_metadata)54 void InitAfterSeek(const Ancestory& child_ancestory, 55 const ElementMetadata& child_metadata) override { 56 assert(max_recursion_depth_ > 0); 57 if (!impl_) { 58 impl_.reset(new T(max_recursion_depth_ - 1)); 59 } 60 61 impl_->InitAfterSeek(child_ancestory, child_metadata); 62 } 63 Feed(Callback * callback,Reader * reader,std::uint64_t * num_bytes_read)64 Status Feed(Callback* callback, Reader* reader, 65 std::uint64_t* num_bytes_read) override { 66 assert(callback != nullptr); 67 assert(reader != nullptr); 68 assert(num_bytes_read != nullptr); 69 assert(impl_ != nullptr); 70 71 return impl_->Feed(callback, reader, num_bytes_read); 72 } 73 value()74 decltype(std::declval<T>().value()) value() const { 75 assert(impl_ != nullptr); 76 77 return impl_->value(); 78 } 79 mutable_value()80 decltype(std::declval<T>().mutable_value()) mutable_value() { 81 assert(impl_ != nullptr); 82 83 return impl_->mutable_value(); 84 } 85 86 private: 87 std::unique_ptr<T> impl_; 88 std::size_t max_recursion_depth_; 89 }; 90 91 } // namespace webm 92 93 #endif // SRC_RECURSIVE_PARSER_H_ 94