1*103e46e4SHarish Mahendrakar // Copyright (c) 2016 The WebM project authors. All Rights Reserved. 2*103e46e4SHarish Mahendrakar // 3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license 4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source 5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found 6*103e46e4SHarish Mahendrakar // in the file PATENTS. All contributing project authors may 7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree. 8*103e46e4SHarish Mahendrakar #ifndef SRC_INT_PARSER_H_ 9*103e46e4SHarish Mahendrakar #define SRC_INT_PARSER_H_ 10*103e46e4SHarish Mahendrakar 11*103e46e4SHarish Mahendrakar #include <cassert> 12*103e46e4SHarish Mahendrakar #include <cstdint> 13*103e46e4SHarish Mahendrakar #include <limits> 14*103e46e4SHarish Mahendrakar #include <type_traits> 15*103e46e4SHarish Mahendrakar 16*103e46e4SHarish Mahendrakar #include "src/element_parser.h" 17*103e46e4SHarish Mahendrakar #include "src/parser_utils.h" 18*103e46e4SHarish Mahendrakar #include "webm/callback.h" 19*103e46e4SHarish Mahendrakar #include "webm/element.h" 20*103e46e4SHarish Mahendrakar #include "webm/reader.h" 21*103e46e4SHarish Mahendrakar #include "webm/status.h" 22*103e46e4SHarish Mahendrakar 23*103e46e4SHarish Mahendrakar namespace webm { 24*103e46e4SHarish Mahendrakar 25*103e46e4SHarish Mahendrakar // Parses an EBML signed/unsigned int from a byte stream. 26*103e46e4SHarish Mahendrakar // Spec reference: 27*103e46e4SHarish Mahendrakar // http://matroska.org/technical/specs/index.html#EBML_ex 28*103e46e4SHarish Mahendrakar // https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#element-data-size 29*103e46e4SHarish Mahendrakar // https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-element-types 30*103e46e4SHarish Mahendrakar template <typename T> 31*103e46e4SHarish Mahendrakar class IntParser : public ElementParser { 32*103e46e4SHarish Mahendrakar public: 33*103e46e4SHarish Mahendrakar static_assert( 34*103e46e4SHarish Mahendrakar std::is_same<T, std::int64_t>::value || 35*103e46e4SHarish Mahendrakar std::is_same<T, std::uint64_t>::value || 36*103e46e4SHarish Mahendrakar (std::is_enum<T>::value && sizeof(T) == 8), 37*103e46e4SHarish Mahendrakar "T must be either std::int64_t, std::uint64_t, or a 64-bit enum"); 38*103e46e4SHarish Mahendrakar 39*103e46e4SHarish Mahendrakar // Constructs a new parser which will use the given default_value as the 40*103e46e4SHarish Mahendrakar // value for the element if its size is zero. Defaults to the value zero (as 41*103e46e4SHarish Mahendrakar // the EBML spec indicates). default_value_(default_value)42*103e46e4SHarish Mahendrakar explicit IntParser(T default_value = {}) : default_value_(default_value) {} 43*103e46e4SHarish Mahendrakar 44*103e46e4SHarish Mahendrakar IntParser(IntParser&&) = default; 45*103e46e4SHarish Mahendrakar IntParser& operator=(IntParser&&) = default; 46*103e46e4SHarish Mahendrakar 47*103e46e4SHarish Mahendrakar IntParser(const IntParser&) = delete; 48*103e46e4SHarish Mahendrakar IntParser& operator=(const IntParser&) = delete; 49*103e46e4SHarish Mahendrakar Init(const ElementMetadata & metadata,std::uint64_t max_size)50*103e46e4SHarish Mahendrakar Status Init(const ElementMetadata& metadata, 51*103e46e4SHarish Mahendrakar std::uint64_t max_size) override { 52*103e46e4SHarish Mahendrakar assert(metadata.size == kUnknownElementSize || metadata.size <= max_size); 53*103e46e4SHarish Mahendrakar 54*103e46e4SHarish Mahendrakar // Matroska requires integers to be 0-8 bytes in size. 55*103e46e4SHarish Mahendrakar if (metadata.size > 8) { 56*103e46e4SHarish Mahendrakar return Status(Status::kInvalidElementSize); 57*103e46e4SHarish Mahendrakar } 58*103e46e4SHarish Mahendrakar 59*103e46e4SHarish Mahendrakar size_ = num_bytes_remaining_ = static_cast<int>(metadata.size); 60*103e46e4SHarish Mahendrakar 61*103e46e4SHarish Mahendrakar if (metadata.size == 0) { 62*103e46e4SHarish Mahendrakar value_ = default_value_; 63*103e46e4SHarish Mahendrakar } else { 64*103e46e4SHarish Mahendrakar value_ = {}; 65*103e46e4SHarish Mahendrakar } 66*103e46e4SHarish Mahendrakar 67*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted); 68*103e46e4SHarish Mahendrakar } 69*103e46e4SHarish Mahendrakar Feed(Callback * callback,Reader * reader,std::uint64_t * num_bytes_read)70*103e46e4SHarish Mahendrakar Status Feed(Callback* callback, Reader* reader, 71*103e46e4SHarish Mahendrakar std::uint64_t* num_bytes_read) override { 72*103e46e4SHarish Mahendrakar assert(callback != nullptr); 73*103e46e4SHarish Mahendrakar assert(reader != nullptr); 74*103e46e4SHarish Mahendrakar assert(num_bytes_read != nullptr); 75*103e46e4SHarish Mahendrakar 76*103e46e4SHarish Mahendrakar const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader, 77*103e46e4SHarish Mahendrakar &value_, num_bytes_read); 78*103e46e4SHarish Mahendrakar num_bytes_remaining_ -= static_cast<int>(*num_bytes_read); 79*103e46e4SHarish Mahendrakar 80*103e46e4SHarish Mahendrakar // Sign extend the integer if it's a negative value. EBML allows for 81*103e46e4SHarish Mahendrakar // negative integers to drop superfluous sign bytes (i.e. -1 can be encoded 82*103e46e4SHarish Mahendrakar // as 0xFF instead of 0xFFFFFFFFFFFFFFFF). 83*103e46e4SHarish Mahendrakar if (std::is_signed<T>::value && num_bytes_remaining_ == 0 && size_ > 0) { 84*103e46e4SHarish Mahendrakar std::uint64_t sign_bits = std::numeric_limits<std::uint64_t>::max() 85*103e46e4SHarish Mahendrakar << (8 * size_ - 1); 86*103e46e4SHarish Mahendrakar std::uint64_t unsigned_value = static_cast<std::uint64_t>(value_); 87*103e46e4SHarish Mahendrakar if (unsigned_value & sign_bits) { 88*103e46e4SHarish Mahendrakar value_ = static_cast<T>(unsigned_value | sign_bits); 89*103e46e4SHarish Mahendrakar } 90*103e46e4SHarish Mahendrakar } 91*103e46e4SHarish Mahendrakar 92*103e46e4SHarish Mahendrakar return status; 93*103e46e4SHarish Mahendrakar } 94*103e46e4SHarish Mahendrakar 95*103e46e4SHarish Mahendrakar // Gets the parsed int. This must not be called until the parse had been 96*103e46e4SHarish Mahendrakar // successfully completed. value()97*103e46e4SHarish Mahendrakar T value() const { 98*103e46e4SHarish Mahendrakar assert(num_bytes_remaining_ == 0); 99*103e46e4SHarish Mahendrakar return value_; 100*103e46e4SHarish Mahendrakar } 101*103e46e4SHarish Mahendrakar 102*103e46e4SHarish Mahendrakar // Gets the parsed int. This must not be called until the parse had been 103*103e46e4SHarish Mahendrakar // successfully completed. mutable_value()104*103e46e4SHarish Mahendrakar T* mutable_value() { 105*103e46e4SHarish Mahendrakar assert(num_bytes_remaining_ == 0); 106*103e46e4SHarish Mahendrakar return &value_; 107*103e46e4SHarish Mahendrakar } 108*103e46e4SHarish Mahendrakar 109*103e46e4SHarish Mahendrakar private: 110*103e46e4SHarish Mahendrakar T value_; 111*103e46e4SHarish Mahendrakar T default_value_; 112*103e46e4SHarish Mahendrakar int num_bytes_remaining_ = -1; 113*103e46e4SHarish Mahendrakar int size_; 114*103e46e4SHarish Mahendrakar }; 115*103e46e4SHarish Mahendrakar 116*103e46e4SHarish Mahendrakar using SignedIntParser = IntParser<std::int64_t>; 117*103e46e4SHarish Mahendrakar using UnsignedIntParser = IntParser<std::uint64_t>; 118*103e46e4SHarish Mahendrakar 119*103e46e4SHarish Mahendrakar } // namespace webm 120*103e46e4SHarish Mahendrakar 121*103e46e4SHarish Mahendrakar #endif // SRC_INT_PARSER_H_ 122