// 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 #include #include #include #include #include #include #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 bar; // Element 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, 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 { // FooParser() // : MasterValueParser(MakeChild(Id::kBar, &Foo::bar), // MakeChild(Id::kBaz, &Foo::baz)) {} // }; template 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>. // 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 class SingleChildFactory { public: constexpr SingleChildFactory(Id id, Element T::*member) : id_(id), member_(member) {} // Builds a std::pair>. 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> BuildParser( MasterValueParser* parent, T* value) { assert(parent != nullptr); assert(value != nullptr); Element* child_member = &(value->*member_); auto lambda = [child_member](Parser* parser) { child_member->Set(std::move(*parser->mutable_value()), true); }; return {id_, MakeChildParser( parent, std::move(lambda), child_member)}; } // If called, OnParseStarted will be called on the parent element when this // particular element is encountered. constexpr SingleChildFactory UseAsStartEvent() const { return {id_, member_}; } // If called, OnChildParsed will be called on the parent element when this // particular element is fully parsed. constexpr SingleChildFactory NotifyOnParseComplete() const { return {id_, member_}; } private: Id id_; Element T::*member_; }; template class RepeatedChildFactory { public: constexpr RepeatedChildFactory(Id id, std::vector> T::*member) : id_(id), member_(member) {} // Builds a std::pair>. 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> BuildParser( MasterValueParser* parent, T* value) { assert(parent != nullptr); assert(value != nullptr); std::vector>* 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( parent, std::move(lambda), child_member)}; } // If called, OnParseStarted will be called on the parent element when this // particular element is encountered. constexpr RepeatedChildFactory UseAsStartEvent() const { return {id_, member_}; } // If called, OnChildParsed will be called on the parent element when this // particular element is fully parsed. constexpr RepeatedChildFactory NotifyOnParseComplete() const { return {id_, member_}; } private: Id id_; std::vector> T::*member_; }; template class RecursiveChildFactory { public: constexpr RecursiveChildFactory(Id id, std::vector> T::*member, std::size_t max_recursion_depth) : id_(id), member_(member), max_recursion_depth_(max_recursion_depth) {} // Builds a std::pair>. 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> BuildParser( MasterValueParser* parent, T* value) { assert(parent != nullptr); assert(value != nullptr); std::vector>* child_member = &(value->*member_); auto lambda = [child_member](RecursiveParser* 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( new ChildParser, 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 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 NotifyOnParseComplete() const { return {id_, member_, max_recursion_depth_}; } private: Id id_; std::vector> T::*member_; std::size_t max_recursion_depth_; }; // Constructs a new parser. Each argument must be a *ChildFactory, constructed // from the MakeChild method. template explicit MasterValueParser(Args&&... args) : master_parser_(args.BuildParser(this, &value_)...) {} // Returns a factory that will produce a // std::pair>. 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 static SingleChildFactory MakeChild( Id id, Element T::*member) { static_assert(std::is_base_of::value, "Parser must derive from ElementParser"); static_assert(!std::is_base_of, Parser>::value, "Recursive elements should be contained in a std::vector"); return SingleChildFactory(id, member); } template static RepeatedChildFactory MakeChild( Id id, std::vector> T::*member) { static_assert(std::is_base_of::value, "Parser must derive from ElementParser"); static_assert(!std::is_base_of, Parser>::value, "Recursive elements require a maximum recursion depth"); return RepeatedChildFactory(id, member); } template static RecursiveChildFactory MakeChild( Id id, std::vector> T::*member, std::size_t max_recursion_depth) { static_assert(std::is_base_of, Parser>::value, "Child must be recusrive to use maximum recursion depth"); return RecursiveChildFactory(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 struct HasTag; // Base condition: Tags is empty, so it trivially does not contain Tag. template struct HasTag : std::false_type {}; // If the head of the Tags list is a different tag, skip it and check the // remaining tags. template struct HasTag : HasTag {}; // If the head of the Tags list is the same as Tag, then we're done. template struct HasTag : std::true_type {}; template class ChildParser : public Base { public: using Base::WasSkipped; template explicit ChildParser(MasterValueParser* parent, F consume_element_value, Args&&... base_args) : Base(std::forward(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()) { parent_->OnChildParsed(parent_->child_metadata()); } } return status; } private: MasterValueParser* parent_; F consume_element_value_; Status Prepare(Callback* callback) { if (has_tag() && !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 constexpr static bool has_tag() { return MasterValueParser::HasTag::value; } }; // Returns a std::unique_ptr that points to a ChildParser // when the Parser's constructor does not take a Value parameter. template static typename std::enable_if::value, std::unique_ptr>::type MakeChildParser(MasterValueParser* parent, F consume_element_value, ...) { return std::unique_ptr(new ChildParser( parent, std::move(consume_element_value))); } // Returns a std::unique_ptr that points to a ChildParser // when the Parser's constructor does take a Value parameter. template static typename std::enable_if::value, std::unique_ptr>::type MakeChildParser(MasterValueParser* parent, F consume_element_value, const Element* default_value) { return std::unique_ptr(new ChildParser( parent, std::move(consume_element_value), default_value->value())); } // Returns a std::unique_ptr that points to a ChildParser // when the Parser's constructor does take a Value parameter. template static typename std::enable_if::value, std::unique_ptr>::type MakeChildParser(MasterValueParser* parent, F consume_element_value, const std::vector>* member) { Value default_value{}; if (!member->empty()) { default_value = member->front().value(); } return std::unique_ptr(new ChildParser( 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_