| // Copyright (c) 2016 The WebM project authors. All Rights Reserved. |
| // |
| // Use of this source code is governed by a BSD-style license |
| // that can be found in the LICENSE file in the root of the source |
| // tree. An additional intellectual property rights grant can be found |
| // in the file PATENTS. All contributing project authors may |
| // be found in the AUTHORS file in the root of the source tree. |
| #ifndef SRC_MASTER_VALUE_PARSER_H_ |
| #define SRC_MASTER_VALUE_PARSER_H_ |
| |
| #include <cassert> |
| #include <cstdint> |
| #include <functional> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "src/master_parser.h" |
| #include "src/recursive_parser.h" |
| #include "src/skip_callback.h" |
| #include "webm/callback.h" |
| #include "webm/element.h" |
| #include "webm/id.h" |
| #include "webm/reader.h" |
| #include "webm/status.h" |
| |
| namespace webm { |
| |
| // Parses Master elements from an EBML stream, storing child values in a |
| // structure of type T. This class differs from MasterParser in that |
| // MasterParser does not collect the parsed data into an object that can then be |
| // retrieved. |
| // |
| // For example, consider the following Foo object, which represents a master |
| // element that contains two booleans: |
| // |
| // struct Foo { |
| // Element<bool> bar; |
| // Element<bool> baz; |
| // }; |
| // |
| // A FooParser implemented via MasterParser, like below, could be used to parse |
| // the master element and the boolean children, but the boolean values could not |
| // be retrieved from the parser. |
| // |
| // struct FooParser : public MasterParser { |
| // FooParser() |
| // : MasterParser({Id::kBar, new BoolParser}, // std::pair<*> types |
| // {Id::kBaz, new BoolParser}) {} // omitted for brevity. |
| // }; |
| // |
| // However, if FooParser is implemented via MasterValueParser<Foo>, then the |
| // boolean values will be parsed into a Foo object that can be retrieved from |
| // FooParser via its value() and mutable_value() methods. |
| // |
| // struct FooParser : public MasterValueParser<Foo> { |
| // FooParser() |
| // : MasterValueParser(MakeChild<BoolParser>(Id::kBar, &Foo::bar), |
| // MakeChild<BoolParser>(Id::kBaz, &Foo::baz)) {} |
| // }; |
| template <typename T> |
| class MasterValueParser : public ElementParser { |
| public: |
| Status Init(const ElementMetadata& metadata, |
| std::uint64_t max_size) override { |
| assert(metadata.size == kUnknownElementSize || metadata.size <= max_size); |
| |
| PreInit(); |
| |
| const Status status = master_parser_.Init(metadata, max_size); |
| if (!status.completed_ok()) { |
| return status; |
| } |
| |
| return status; |
| } |
| |
| void InitAfterSeek(const Ancestory& child_ancestory, |
| const ElementMetadata& child_metadata) override { |
| PreInit(); |
| started_done_ = true; |
| master_parser_.InitAfterSeek(child_ancestory, child_metadata); |
| } |
| |
| Status Feed(Callback* callback, Reader* reader, |
| std::uint64_t* num_bytes_read) override { |
| assert(callback != nullptr); |
| assert(reader != nullptr); |
| assert(num_bytes_read != nullptr); |
| |
| *num_bytes_read = 0; |
| |
| if (!parse_complete_) { |
| // TODO(mjbshaw): just call Reader::Skip if element's size is known and |
| // action is skip. |
| SkipCallback skip_callback; |
| if (action_ == Action::kSkip) { |
| callback = &skip_callback; |
| } |
| |
| Status status = master_parser_.Feed(callback, reader, num_bytes_read); |
| // Check if we've artificially injected an error code, and if so, switch |
| // into skipping mode. |
| if (status.code == Status::kSwitchToSkip) { |
| assert(started_done_); |
| assert(action_ == Action::kSkip); |
| callback = &skip_callback; |
| std::uint64_t local_num_bytes_read; |
| status = master_parser_.Feed(callback, reader, &local_num_bytes_read); |
| *num_bytes_read += local_num_bytes_read; |
| } |
| if (!status.completed_ok()) { |
| return status; |
| } |
| parse_complete_ = true; |
| } |
| |
| if (!started_done_) { |
| Status status = OnParseStarted(callback, &action_); |
| if (!status.completed_ok()) { |
| return status; |
| } |
| started_done_ = true; |
| } |
| |
| if (action_ != Action::kSkip) { |
| return OnParseCompleted(callback); |
| } |
| |
| return Status(Status::kOkCompleted); |
| } |
| |
| bool GetCachedMetadata(ElementMetadata* metadata) override { |
| return master_parser_.GetCachedMetadata(metadata); |
| } |
| |
| bool WasSkipped() const override { return action_ == Action::kSkip; } |
| |
| const T& value() const { return value_; } |
| |
| T* mutable_value() { return &value_; } |
| |
| protected: |
| // Users and subclasses are not meant to use the Tag* classes; they're an |
| // internal implementation detail. |
| // A tag that will cause the internal ChildParser to use the parsed child as a |
| // start event. |
| struct TagUseAsStart {}; |
| // A tag that will cause the internal ChildParser to call OnChildParsed once |
| // it has been fully parsed. |
| struct TagNotifyOnParseComplete {}; |
| |
| // A factory that will create a std::pair<Id, std::unique_ptr<ElementParser>>. |
| // Users and subclasses are not meant to use this class directly, as it is an |
| // internal implementation detail of this class. Subclasses should use |
| // MakeChild instead of using this class directly. |
| template <typename Parser, typename Value, typename... Tags> |
| class SingleChildFactory { |
| public: |
| constexpr SingleChildFactory(Id id, Element<Value> T::*member) |
| : id_(id), member_(member) {} |
| |
| // Builds a std::pair<Id, std::unique_ptr<ElementParser>>. The parent |
| // pointer must be a pointer to the MasterValueParser that is being |
| // constructed. The given value pointer must be the pointer to the fully |
| // constructed MasterValueParser::value_ object. |
| std::pair<Id, std::unique_ptr<ElementParser>> BuildParser( |
| MasterValueParser* parent, T* value) { |
| assert(parent != nullptr); |
| assert(value != nullptr); |
| |
| Element<Value>* child_member = &(value->*member_); |
| auto lambda = [child_member](Parser* parser) { |
| child_member->Set(std::move(*parser->mutable_value()), true); |
| }; |
| return {id_, MakeChildParser<Parser, Value, Tags...>( |
| parent, std::move(lambda), child_member)}; |
| } |
| |
| // If called, OnParseStarted will be called on the parent element when this |
| // particular element is encountered. |
| constexpr SingleChildFactory<Parser, Value, TagUseAsStart, Tags...> |
| UseAsStartEvent() const { |
| return {id_, member_}; |
| } |
| |
| // If called, OnChildParsed will be called on the parent element when this |
| // particular element is fully parsed. |
| constexpr SingleChildFactory<Parser, Value, TagNotifyOnParseComplete, |
| Tags...> |
| NotifyOnParseComplete() const { |
| return {id_, member_}; |
| } |
| |
| private: |
| Id id_; |
| Element<Value> T::*member_; |
| }; |
| |
| template <typename Parser, typename Value, typename... Tags> |
| class RepeatedChildFactory { |
| public: |
| constexpr RepeatedChildFactory(Id id, |
| std::vector<Element<Value>> T::*member) |
| : id_(id), member_(member) {} |
| |
| // Builds a std::pair<Id, std::unique_ptr<ElementParser>>. The parent |
| // pointer must be a pointer to the MasterValueParser that is being |
| // constructed. The given value pointer must be the pointer to the fully |
| // constructed MasterValueParser::value_ object. |
| std::pair<Id, std::unique_ptr<ElementParser>> BuildParser( |
| MasterValueParser* parent, T* value) { |
| assert(parent != nullptr); |
| assert(value != nullptr); |
| |
| std::vector<Element<Value>>* child_member = &(value->*member_); |
| auto lambda = [child_member](Parser* parser) { |
| if (child_member->size() == 1 && !child_member->front().is_present()) { |
| child_member->clear(); |
| } |
| child_member->emplace_back(std::move(*parser->mutable_value()), true); |
| }; |
| return {id_, MakeChildParser<Parser, Value, Tags...>( |
| parent, std::move(lambda), child_member)}; |
| } |
| |
| // If called, OnParseStarted will be called on the parent element when this |
| // particular element is encountered. |
| constexpr RepeatedChildFactory<Parser, Value, TagUseAsStart, Tags...> |
| UseAsStartEvent() const { |
| return {id_, member_}; |
| } |
| |
| // If called, OnChildParsed will be called on the parent element when this |
| // particular element is fully parsed. |
| constexpr RepeatedChildFactory<Parser, Value, TagNotifyOnParseComplete, |
| Tags...> |
| NotifyOnParseComplete() const { |
| return {id_, member_}; |
| } |
| |
| private: |
| Id id_; |
| std::vector<Element<Value>> T::*member_; |
| }; |
| |
| template <typename Parser, typename... Tags> |
| class RecursiveChildFactory { |
| public: |
| constexpr RecursiveChildFactory(Id id, std::vector<Element<T>> T::*member, |
| std::size_t max_recursion_depth) |
| : id_(id), member_(member), max_recursion_depth_(max_recursion_depth) {} |
| |
| // Builds a std::pair<Id, std::unique_ptr<ElementParser>>. The parent |
| // pointer must be a pointer to the MasterValueParser that is being |
| // constructed. The given value pointer must be the pointer to the fully |
| // constructed MasterValueParser::value_ object. |
| std::pair<Id, std::unique_ptr<ElementParser>> BuildParser( |
| MasterValueParser* parent, T* value) { |
| assert(parent != nullptr); |
| assert(value != nullptr); |
| |
| std::vector<Element<T>>* child_member = &(value->*member_); |
| auto lambda = [child_member](RecursiveParser<Parser>* parser) { |
| if (child_member->size() == 1 && !child_member->front().is_present()) { |
| child_member->clear(); |
| } |
| child_member->emplace_back(std::move(*parser->mutable_value()), true); |
| }; |
| |
| return {id_, std::unique_ptr<ElementParser>( |
| new ChildParser<RecursiveParser<Parser>, |
| decltype(lambda), Tags...>( |
| parent, std::move(lambda), max_recursion_depth_))}; |
| } |
| |
| // If called, OnParseStarted will be called on the parent element when this |
| // particular element is encountered. |
| constexpr RecursiveChildFactory<Parser, TagUseAsStart, Tags...> |
| UseAsStartEvent() const { |
| return {id_, member_, max_recursion_depth_}; |
| } |
| |
| // If called, OnChildParsed will be called on the parent element when this |
| // particular element is fully parsed. |
| constexpr RecursiveChildFactory<Parser, TagNotifyOnParseComplete, Tags...> |
| NotifyOnParseComplete() const { |
| return {id_, member_, max_recursion_depth_}; |
| } |
| |
| private: |
| Id id_; |
| std::vector<Element<T>> T::*member_; |
| std::size_t max_recursion_depth_; |
| }; |
| |
| // Constructs a new parser. Each argument must be a *ChildFactory, constructed |
| // from the MakeChild method. |
| template <typename... Args> |
| explicit MasterValueParser(Args&&... args) |
| : master_parser_(args.BuildParser(this, &value_)...) {} |
| |
| // Returns a factory that will produce a |
| // std::pair<Id, std::unique_ptr<ElementParser>>. When a child element of the |
| // given ID is encountered, a parser of type Parser will be used to parse it, |
| // and store its value in the member pointer when the parse is complete. The |
| // given default value will be used in the event that the child element has a |
| // zero size. This method is only meant to be used by subclasses to provide |
| // the necessary factories to the constructor. |
| template <typename Parser, typename Value> |
| static SingleChildFactory<Parser, Value> MakeChild( |
| Id id, Element<Value> T::*member) { |
| static_assert(std::is_base_of<ElementParser, Parser>::value, |
| "Parser must derive from ElementParser"); |
| static_assert(!std::is_base_of<MasterValueParser<T>, Parser>::value, |
| "Recursive elements should be contained in a std::vector"); |
| return SingleChildFactory<Parser, Value>(id, member); |
| } |
| |
| template <typename Parser, typename Value> |
| static RepeatedChildFactory<Parser, Value> MakeChild( |
| Id id, std::vector<Element<Value>> T::*member) { |
| static_assert(std::is_base_of<ElementParser, Parser>::value, |
| "Parser must derive from ElementParser"); |
| static_assert(!std::is_base_of<MasterValueParser<T>, Parser>::value, |
| "Recursive elements require a maximum recursion depth"); |
| return RepeatedChildFactory<Parser, Value>(id, member); |
| } |
| |
| template <typename Parser> |
| static RecursiveChildFactory<Parser> MakeChild( |
| Id id, std::vector<Element<T>> T::*member, |
| std::size_t max_recursion_depth) { |
| static_assert(std::is_base_of<MasterValueParser<T>, Parser>::value, |
| "Child must be recusrive to use maximum recursion depth"); |
| return RecursiveChildFactory<Parser>(id, member, max_recursion_depth); |
| } |
| |
| // Gets the metadata for this element, setting the EBML element ID to id. Only |
| // call after Init() has been called. |
| ElementMetadata metadata(Id id) const { |
| return {id, master_parser_.header_size(), master_parser_.size(), |
| master_parser_.position()}; |
| } |
| |
| // This method will be called once the element has been fully parsed, or a |
| // particular child element of interest (see UseAsStartEvent()) is |
| // encountered. By default it just sets *action to Action::kRead and returns |
| // Status::kOkCompleted. May be overridden (i.e. in order to call a Callback |
| // method). Returning anything other than Status::kOkCompleted will stop |
| // parsing and the status to be returned by Init or Feed (whichever originated |
| // the call to this method). In this case, resuming parsing will result in |
| // this method being called again. |
| virtual Status OnParseStarted(Callback* callback, Action* action) { |
| assert(callback != nullptr); |
| assert(action != nullptr); |
| *action = Action::kRead; |
| return Status(Status::kOkCompleted); |
| } |
| |
| // This method is the companion to OnParseStarted, and will only be called |
| // after OnParseStarted has already been called and parsing has completed. |
| // This will not be called if OnParseStarted set the action to Action::kSkip. |
| // By default it just returns Status::kOkCompleted. Returning anything other |
| // than Status::kOkCompleted will stop parsing and the status to be returned |
| // by Init or Feed (whichever originated the call to this method). In this |
| // case, resuming parsing will result in this method being called again. |
| virtual Status OnParseCompleted(Callback* callback) { |
| assert(callback != nullptr); |
| return Status(Status::kOkCompleted); |
| } |
| |
| // Returns true if the OnParseStarted method has already been called and has |
| // completed. |
| bool parse_started_event_completed() const { return started_done_; } |
| |
| // Derived classes may manually call OnParseStarted before calling Feed, in |
| // which case this method should be called to inform this class that |
| // OnParseStarted has already been called and it should not be called again. |
| void set_parse_started_event_completed_with_action(Action action) { |
| assert(!started_done_); |
| |
| action_ = action; |
| started_done_ = true; |
| } |
| |
| // This method will be called for each child element that has been fully |
| // parsed for which NotifyOnParseComplete() was requested. The provided |
| // metadata is for the child element that has just completed parsing. By |
| // default this method does nothing. |
| virtual void OnChildParsed(const ElementMetadata& /* metadata */) {} |
| |
| private: |
| T value_; |
| Action action_ = Action::kRead; |
| bool parse_complete_; |
| bool started_done_; |
| // master_parser_ must be after value_ to ensure correct initialization order. |
| MasterParser master_parser_; |
| |
| const ElementMetadata& child_metadata() const { |
| return master_parser_.child_metadata(); |
| } |
| |
| // Helper struct that will be std::true_type if Tag is in Tags, or |
| // std::false_type otherwise. |
| template <typename Tag, typename... Tags> |
| struct HasTag; |
| |
| // Base condition: Tags is empty, so it trivially does not contain Tag. |
| template <typename Tag> |
| struct HasTag<Tag> : std::false_type {}; |
| |
| // If the head of the Tags list is a different tag, skip it and check the |
| // remaining tags. |
| template <typename Tag, typename DifferentTag, typename... Tags> |
| struct HasTag<Tag, DifferentTag, Tags...> : HasTag<Tag, Tags...> {}; |
| |
| // If the head of the Tags list is the same as Tag, then we're done. |
| template <typename Tag, typename... Tags> |
| struct HasTag<Tag, Tag, Tags...> : std::true_type {}; |
| |
| template <typename Base, typename F, typename... Tags> |
| class ChildParser : public Base { |
| public: |
| using Base::WasSkipped; |
| |
| template <typename... Args> |
| explicit ChildParser(MasterValueParser* parent, F consume_element_value, |
| Args&&... base_args) |
| : Base(std::forward<Args>(base_args)...), |
| parent_(parent), |
| consume_element_value_(std::move(consume_element_value)) {} |
| |
| ChildParser() = delete; |
| ChildParser(const ChildParser&) = delete; |
| ChildParser& operator=(const ChildParser&) = delete; |
| |
| Status Feed(Callback* callback, Reader* reader, |
| std::uint64_t* num_bytes_read) override { |
| *num_bytes_read = 0; |
| |
| Status status = Prepare(callback); |
| if (!status.completed_ok()) { |
| return status; |
| } |
| |
| status = Base::Feed(callback, reader, num_bytes_read); |
| if (status.completed_ok() && parent_->action_ != Action::kSkip && |
| !WasSkipped()) { |
| consume_element_value_(this); |
| if (has_tag<TagNotifyOnParseComplete>()) { |
| parent_->OnChildParsed(parent_->child_metadata()); |
| } |
| } |
| return status; |
| } |
| |
| private: |
| MasterValueParser* parent_; |
| F consume_element_value_; |
| |
| Status Prepare(Callback* callback) { |
| if (has_tag<TagUseAsStart>() && !parent_->started_done_) { |
| const Status status = |
| parent_->OnParseStarted(callback, &parent_->action_); |
| if (!status.completed_ok()) { |
| return status; |
| } |
| parent_->started_done_ = true; |
| if (parent_->action_ == Action::kSkip) { |
| return Status(Status::kSwitchToSkip); |
| } |
| } |
| return Status(Status::kOkCompleted); |
| } |
| |
| template <typename Tag> |
| constexpr static bool has_tag() { |
| return MasterValueParser::HasTag<Tag, Tags...>::value; |
| } |
| }; |
| |
| // Returns a std::unique_ptr<ElementParser> that points to a ChildParser |
| // when the Parser's constructor does not take a Value parameter. |
| template <typename Parser, typename Value, typename... Tags, typename F> |
| static typename std::enable_if<!std::is_constructible<Parser, Value>::value, |
| std::unique_ptr<ElementParser>>::type |
| MakeChildParser(MasterValueParser* parent, F consume_element_value, ...) { |
| return std::unique_ptr<ElementParser>(new ChildParser<Parser, F, Tags...>( |
| parent, std::move(consume_element_value))); |
| } |
| |
| // Returns a std::unique_ptr<ElementParser> that points to a ChildParser |
| // when the Parser's constructor does take a Value parameter. |
| template <typename Parser, typename Value, typename... Tags, typename F> |
| static typename std::enable_if<std::is_constructible<Parser, Value>::value, |
| std::unique_ptr<ElementParser>>::type |
| MakeChildParser(MasterValueParser* parent, F consume_element_value, |
| const Element<Value>* default_value) { |
| return std::unique_ptr<ElementParser>(new ChildParser<Parser, F, Tags...>( |
| parent, std::move(consume_element_value), default_value->value())); |
| } |
| |
| // Returns a std::unique_ptr<ElementParser> that points to a ChildParser |
| // when the Parser's constructor does take a Value parameter. |
| template <typename Parser, typename Value, typename... Tags, typename F> |
| static typename std::enable_if<std::is_constructible<Parser, Value>::value, |
| std::unique_ptr<ElementParser>>::type |
| MakeChildParser(MasterValueParser* parent, F consume_element_value, |
| const std::vector<Element<Value>>* member) { |
| Value default_value{}; |
| if (!member->empty()) { |
| default_value = member->front().value(); |
| } |
| return std::unique_ptr<ElementParser>(new ChildParser<Parser, F, Tags...>( |
| parent, std::move(consume_element_value), std::move(default_value))); |
| } |
| |
| // Initializes object state. Call immediately before initializing |
| // master_parser_. |
| void PreInit() { |
| value_ = {}; |
| action_ = Action::kRead; |
| parse_complete_ = false; |
| started_done_ = false; |
| } |
| }; |
| |
| } // namespace webm |
| |
| #endif // SRC_MASTER_VALUE_PARSER_H_ |