Add a new incremental parsing API

Change-Id: I6b921766836d58df0281fb23b2add3f62a478e14
This commit is contained in:
Michael Bradshaw
2016-06-14 16:53:56 -07:00
parent 900d322cc8
commit cb8ce0b4b5
752 changed files with 21329 additions and 0 deletions

View File

@@ -0,0 +1,316 @@
// 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.
#include "src/ancestory.h"
#include "webm/id.h"
namespace webm {
bool Ancestory::ById(Id id, Ancestory* ancestory) {
// These lists of IDs were generated and must match the switch statement and
// have static storage duration. They were generated as follows:
//
// 1. List all the master elements:
// kEbml
// kSegment
// kSeekHead
// kSeek
// kInfo
// kCluster
// kBlockGroup
// kBlockAdditions
// kBlockMore
// kSlices
// kTimeSlice
// etc.
//
// 2. Now prefix each entry with its full ancestory:
// kEbml
// kSegment
// kSegment, kSeekHead
// kSegment, kSeekHead, kSeek
// kSegment, kInfo
// kSegment, kCluster
// kSegment, kCluster, kBlockGroup
// kSegment, kCluster, kBlockGroup, kBlockAdditions
// kSegment, kCluster, kBlockGroup, kBlockAdditions, kBlockMore
// kSegment, kCluster, kBlockGroup, kSlices
// kSegment, kCluster, kBlockGroup, kSlices, kTimeSlice
// etc.
//
// 3. Now remove entries that are just subsets of others:
// kEbml
// kSegment, kSeekHead, kSeek
// kSegment, kInfo
// kSegment, kCluster, kBlockGroup, kBlockAdditions, kBlockMore
// kSegment, kCluster, kBlockGroup, kSlices, kTimeSlice
// etc.
static constexpr Id kEbmlAncestory[] = {
Id::kEbml,
};
static constexpr Id kSeekAncestory[] = {
Id::kSegment, Id::kSeekHead, Id::kSeek,
};
static constexpr Id kInfoAncestory[] = {
Id::kSegment, Id::kInfo,
};
static constexpr Id kBlockMoreAncestory[] = {
Id::kSegment, Id::kCluster, Id::kBlockGroup,
Id::kBlockAdditions, Id::kBlockMore,
};
static constexpr Id kTimeSliceAncestory[] = {
Id::kSegment, Id::kCluster, Id::kBlockGroup, Id::kSlices, Id::kTimeSlice,
};
static constexpr Id kVideoAncestory[] = {
Id::kSegment, Id::kTracks, Id::kTrackEntry, Id::kVideo,
};
static constexpr Id kAudioAncestory[] = {
Id::kSegment, Id::kTracks, Id::kTrackEntry, Id::kAudio,
};
static constexpr Id kContentEncAesSettingsAncestory[] = {
Id::kSegment,
Id::kTracks,
Id::kTrackEntry,
Id::kContentEncodings,
Id::kContentEncoding,
Id::kContentEncryption,
Id::kContentEncAesSettings,
};
static constexpr Id kCueTrackPositionsAncestory[] = {
Id::kSegment, Id::kCues, Id::kCuePoint, Id::kCueTrackPositions,
};
static constexpr Id kChapterDisplayAncestory[] = {
Id::kSegment, Id::kChapters, Id::kEditionEntry,
Id::kChapterAtom, Id::kChapterDisplay,
};
static constexpr Id kTargetsAncestory[] = {
Id::kSegment, Id::kTags, Id::kTag, Id::kTargets,
};
static constexpr Id kSimpleTagAncestory[] = {
Id::kSegment, Id::kTags, Id::kTag, Id::kSimpleTag,
};
switch (id) {
case Id::kEbmlVersion:
case Id::kEbmlReadVersion:
case Id::kEbmlMaxIdLength:
case Id::kEbmlMaxSizeLength:
case Id::kDocType:
case Id::kDocTypeVersion:
case Id::kDocTypeReadVersion:
*ancestory = Ancestory(kEbmlAncestory, 1);
return true;
case Id::kSeekHead:
case Id::kInfo:
case Id::kCluster:
case Id::kTracks:
case Id::kCues:
case Id::kChapters:
case Id::kTags:
*ancestory = Ancestory(kSeekAncestory, 1);
return true;
case Id::kSeek:
*ancestory = Ancestory(kSeekAncestory, 2);
return true;
case Id::kSeekId:
case Id::kSeekPosition:
*ancestory = Ancestory(kSeekAncestory, 3);
return true;
case Id::kTimecodeScale:
case Id::kDuration:
case Id::kDateUtc:
case Id::kTitle:
case Id::kMuxingApp:
case Id::kWritingApp:
*ancestory = Ancestory(kInfoAncestory, 2);
return true;
case Id::kTimecode:
case Id::kPrevSize:
case Id::kSimpleBlock:
case Id::kBlockGroup:
*ancestory = Ancestory(kBlockMoreAncestory, 2);
return true;
case Id::kBlock:
case Id::kBlockVirtual:
case Id::kBlockAdditions:
case Id::kBlockDuration:
case Id::kReferenceBlock:
case Id::kDiscardPadding:
case Id::kSlices:
*ancestory = Ancestory(kBlockMoreAncestory, 3);
return true;
case Id::kBlockMore:
*ancestory = Ancestory(kBlockMoreAncestory, 4);
return true;
case Id::kBlockAddId:
case Id::kBlockAdditional:
*ancestory = Ancestory(kBlockMoreAncestory, 5);
return true;
case Id::kTimeSlice:
*ancestory = Ancestory(kTimeSliceAncestory, 4);
return true;
case Id::kLaceNumber:
*ancestory = Ancestory(kTimeSliceAncestory, 5);
return true;
case Id::kTrackEntry:
*ancestory = Ancestory(kVideoAncestory, 2);
return true;
case Id::kTrackNumber:
case Id::kTrackUid:
case Id::kTrackType:
case Id::kFlagEnabled:
case Id::kFlagDefault:
case Id::kFlagForced:
case Id::kFlagLacing:
case Id::kDefaultDuration:
case Id::kName:
case Id::kLanguage:
case Id::kCodecId:
case Id::kCodecPrivate:
case Id::kCodecName:
case Id::kCodecDelay:
case Id::kSeekPreRoll:
case Id::kVideo:
case Id::kAudio:
case Id::kContentEncodings:
*ancestory = Ancestory(kVideoAncestory, 3);
return true;
case Id::kFlagInterlaced:
case Id::kStereoMode:
case Id::kAlphaMode:
case Id::kPixelWidth:
case Id::kPixelHeight:
case Id::kPixelCropBottom:
case Id::kPixelCropTop:
case Id::kPixelCropLeft:
case Id::kPixelCropRight:
case Id::kDisplayWidth:
case Id::kDisplayHeight:
case Id::kDisplayUnit:
case Id::kAspectRatioType:
case Id::kFrameRate:
*ancestory = Ancestory(kVideoAncestory, 4);
return true;
case Id::kSamplingFrequency:
case Id::kOutputSamplingFrequency:
case Id::kChannels:
case Id::kBitDepth:
*ancestory = Ancestory(kAudioAncestory, 4);
return true;
case Id::kContentEncoding:
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 4);
return true;
case Id::kContentEncodingOrder:
case Id::kContentEncodingScope:
case Id::kContentEncodingType:
case Id::kContentEncryption:
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 5);
return true;
case Id::kContentEncAlgo:
case Id::kContentEncKeyId:
case Id::kContentEncAesSettings:
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 6);
return true;
case Id::kAesSettingsCipherMode:
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 7);
return true;
case Id::kCuePoint:
*ancestory = Ancestory(kCueTrackPositionsAncestory, 2);
return true;
case Id::kCueTime:
case Id::kCueTrackPositions:
*ancestory = Ancestory(kCueTrackPositionsAncestory, 3);
return true;
case Id::kCueTrack:
case Id::kCueClusterPosition:
case Id::kCueRelativePosition:
case Id::kCueDuration:
case Id::kCueBlockNumber:
*ancestory = Ancestory(kCueTrackPositionsAncestory, 4);
return true;
case Id::kEditionEntry:
*ancestory = Ancestory(kChapterDisplayAncestory, 2);
return true;
case Id::kChapterAtom:
*ancestory = Ancestory(kChapterDisplayAncestory, 3);
return true;
case Id::kChapterUid:
case Id::kChapterStringUid:
case Id::kChapterTimeStart:
case Id::kChapterTimeEnd:
case Id::kChapterDisplay:
*ancestory = Ancestory(kChapterDisplayAncestory, 4);
return true;
case Id::kChapString:
case Id::kChapLanguage:
case Id::kChapCountry:
*ancestory = Ancestory(kChapterDisplayAncestory, 5);
return true;
case Id::kTag:
*ancestory = Ancestory(kTargetsAncestory, 2);
return true;
case Id::kTargets:
case Id::kSimpleTag:
*ancestory = Ancestory(kTargetsAncestory, 3);
return true;
case Id::kTargetTypeValue:
case Id::kTargetType:
case Id::kTagTrackUid:
*ancestory = Ancestory(kTargetsAncestory, 4);
return true;
case Id::kTagName:
case Id::kTagLanguage:
case Id::kTagDefault:
case Id::kTagString:
case Id::kTagBinary:
*ancestory = Ancestory(kSimpleTagAncestory, 4);
return true;
case Id::kEbml:
case Id::kSegment:
*ancestory = {};
return true;
default:
// This is an unknown element or a global element (i.e. Void); its
// ancestory cannot be deduced.
*ancestory = {};
return false;
}
}
} // namespace webm

View File

@@ -0,0 +1,83 @@
// 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_ANCESTORY_H_
#define SRC_ANCESTORY_H_
#include <cassert>
#include <cstddef>
#include <iterator>
#include "webm/id.h"
namespace webm {
// Represents an element's ancestory in descending order. For example, the
// Id::kTrackNumber element has an ancestory of {Id::kSegment, Id::kTracks,
// Id::kTrackEntry}.
class Ancestory {
public:
// Constructs an empty ancestory.
Ancestory() = default;
Ancestory(const Ancestory&) = default;
Ancestory(Ancestory&&) = default;
Ancestory& operator=(const Ancestory&) = default;
Ancestory& operator=(Ancestory&&) = default;
// Returns the ancestory with the top-level parent removed. For example, if
// the current ancestory is {Id::kSegment, Id::kTracks, Id::kTrackEntry}, next
// will return {Id::kTracks, Id::kTrackEntry}. This must not be called if the
// ancestory is empty.
Ancestory next() const {
assert(begin_ < end_);
Ancestory copy = *this;
++copy.begin_;
return copy;
}
// Gets the Id of the top-level parent. For example, if the current ancestory
// is {Id::kSegment, Id::kTracks, Id::kTrackEntry}, id will return
// Id::kSegment. This must not be called if the ancestory is empty.
Id id() const {
assert(begin_ < end_);
return *begin_;
}
// Returns true if the ancestory is empty.
bool empty() const { return begin_ == end_; }
// Looks up the ancestory of the given id. Returns true and sets ancestory if
// the element's ancestory could be deduced. Global elements (i.e. Id::kVoid)
// and unknown elements can't have their ancestory deduced.
static bool ById(Id id, Ancestory* ancestory);
private:
// Constructs an Ancestory using the first count elements of ancestory.
// ancestory must have static storage duration.
template <std::size_t N>
Ancestory(const Id (&ancestory)[N], std::size_t count)
: begin_(ancestory), end_(ancestory + count) {
assert(count <= N);
}
// The following invariants apply to begin_ and end_:
// begin_ <= end_
// (begin_ == end_) || (std::begin(kIds) <= begin_ && end_ <= std::end(kIds))
// The beginning (inclusive) of the sequence of IDs in kIds that defines the
// ancestory.
const Id* begin_ = nullptr;
// The ending (exclusive) of the sequence of IDs in kIds that defines the
// ancestory.
const Id* end_ = nullptr;
};
} // namespace webm
#endif // SRC_ANCESTORY_H_

View File

@@ -0,0 +1,84 @@
// 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_AUDIO_PARSER_H_
#define SRC_AUDIO_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/float_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/callback.h"
#include "webm/dom_types.h"
#include "webm/id.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Audio
// http://www.webmproject.org/docs/container/#Audio
class AudioParser : public MasterValueParser<Audio> {
public:
AudioParser()
: MasterValueParser<Audio>(
MakeChild<FloatParser>(Id::kSamplingFrequency,
&Audio::sampling_frequency),
MakeChild<FloatParser>(Id::kOutputSamplingFrequency,
&Audio::output_frequency)
.NotifyOnParseComplete(),
MakeChild<UnsignedIntParser>(Id::kChannels, &Audio::channels),
MakeChild<UnsignedIntParser>(Id::kBitDepth, &Audio::bit_depth)) {}
Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) override {
output_frequency_has_value_ = false;
return MasterValueParser::Init(metadata, max_size);
}
void InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) override {
output_frequency_has_value_ = false;
return MasterValueParser::InitAfterSeek(child_ancestory, child_metadata);
}
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override {
const Status status =
MasterValueParser::Feed(callback, reader, num_bytes_read);
if (status.completed_ok()) {
FixMissingOutputFrequency();
}
return status;
}
protected:
void OnChildParsed(const ElementMetadata& metadata) override {
assert(metadata.id == Id::kOutputSamplingFrequency);
output_frequency_has_value_ = metadata.size > 0;
}
private:
bool output_frequency_has_value_;
void FixMissingOutputFrequency() {
if (!output_frequency_has_value_) {
*mutable_value()->output_frequency.mutable_value() =
value().sampling_frequency.value();
}
}
};
} // namespace webm
#endif // SRC_AUDIO_PARSER_H_

View File

@@ -0,0 +1,25 @@
// 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.
#include "src/bit_utils.h"
#include <cstdint>
namespace webm {
std::uint8_t CountLeadingZeros(std::uint8_t value) {
// Special case for 0 since we can't shift by sizeof(T) * 8 bytes.
if (value == 0) return 8;
std::uint8_t count = 0;
while (!(value & (0x80 >> count))) {
++count;
}
return count;
}
} // namespace webm

View File

@@ -0,0 +1,24 @@
// 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_BIT_UTILS_H_
#define SRC_BIT_UTILS_H_
#include <cstdint>
namespace webm {
// Counts the number of leading zero bits.
// For example:
// assert(8 == CountLeadingZeros(0x00));
// assert(4 == CountLeadingZeros(0x0f));
// assert(0 == CountLeadingZeros(0xf0));
std::uint8_t CountLeadingZeros(std::uint8_t value);
} // namespace webm
#endif // SRC_BIT_UTILS_H_

View File

@@ -0,0 +1,30 @@
// 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_BLOCK_ADDITIONS_PARSER_H_
#define SRC_BLOCK_ADDITIONS_PARSER_H_
#include "src/block_more_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#BlockAdditions
// http://www.webmproject.org/docs/container/#BlockAdditions
class BlockAdditionsParser : public MasterValueParser<BlockAdditions> {
public:
BlockAdditionsParser()
: MasterValueParser<BlockAdditions>(MakeChild<BlockMoreParser>(
Id::kBlockMore, &BlockAdditions::block_mores)) {}
};
} // namespace webm
#endif // SRC_BLOCK_ADDITIONS_PARSER_H_

View File

@@ -0,0 +1,71 @@
// 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_BLOCK_GROUP_PARSER_H_
#define SRC_BLOCK_GROUP_PARSER_H_
#include "src/block_additions_parser.h"
#include "src/block_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "src/slices_parser.h"
#include "src/virtual_block_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#BlockGroup
// http://www.webmproject.org/docs/container/#BlockGroup
class BlockGroupParser : public MasterValueParser<BlockGroup> {
public:
BlockGroupParser()
: MasterValueParser<BlockGroup>(
MakeChild<BlockParser>(Id::kBlock, &BlockGroup::block),
MakeChild<VirtualBlockParser>(Id::kBlockVirtual,
&BlockGroup::virtual_block),
MakeChild<BlockAdditionsParser>(Id::kBlockAdditions,
&BlockGroup::additions),
MakeChild<UnsignedIntParser>(Id::kBlockDuration,
&BlockGroup::duration),
MakeChild<SignedIntParser>(Id::kReferenceBlock,
&BlockGroup::references),
MakeChild<SignedIntParser>(Id::kDiscardPadding,
&BlockGroup::discard_padding),
MakeChild<SlicesParser>(Id::kSlices, &BlockGroup::slices)) {}
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override {
*num_bytes_read = 0;
if (!parse_started_event_completed()) {
Action action;
Status status = OnParseStarted(callback, &action);
if (!status.completed_ok()) {
return status;
}
set_parse_started_event_completed_with_action(action);
}
return MasterValueParser::Feed(callback, reader, num_bytes_read);
}
protected:
Status OnParseStarted(Callback* callback, Action* action) override {
return callback->OnBlockGroupBegin(metadata(Id::kBlockGroup), action);
}
Status OnParseCompleted(Callback* callback) override {
return callback->OnBlockGroupEnd(metadata(Id::kBlockGroup), value());
}
};
} // namespace webm
#endif // SRC_BLOCK_GROUP_PARSER_H_

View File

@@ -0,0 +1,76 @@
// 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.
#include "src/block_header_parser.h"
#include <cassert>
#include <cstdint>
#include "src/parser_utils.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#block_structure
// http://matroska.org/technical/specs/index.html#simpleblock_structure
// http://matroska.org/technical/specs/index.html#block_virtual
Status BlockHeaderParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
*num_bytes_read = 0;
Status status;
std::uint64_t local_num_bytes_read;
while (true) {
switch (state_) {
case State::kReadingTrackNumber: {
status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
if (!status.completed_ok()) {
return status;
}
value_.track_number = uint_parser_.value();
state_ = State::kReadingTimecode;
continue;
}
case State::kReadingTimecode: {
status =
AccumulateIntegerBytes(timecode_bytes_remaining_, reader,
&value_.timecode, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
timecode_bytes_remaining_ -= static_cast<int>(local_num_bytes_read);
if (!status.completed_ok()) {
return status;
}
state_ = State::kReadingFlags;
continue;
}
case State::kReadingFlags: {
assert(timecode_bytes_remaining_ == 0);
status = ReadByte(reader, &value_.flags);
if (!status.completed_ok()) {
return status;
}
++*num_bytes_read;
state_ = State::kDone;
continue;
}
case State::kDone: {
return Status(Status::kOkCompleted);
}
}
}
}
} // namespace webm

View File

@@ -0,0 +1,63 @@
// 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_BLOCK_HEADER_PARSER_H_
#define SRC_BLOCK_HEADER_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/parser.h"
#include "src/var_int_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
struct BlockHeader {
std::uint64_t track_number;
std::int16_t timecode;
std::uint8_t flags;
bool operator==(const BlockHeader& other) const {
return track_number == other.track_number && timecode == other.timecode &&
flags == other.flags;
}
};
class BlockHeaderParser : public Parser {
public:
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed block header information. This must not be called until the
// parse has been successfully completed.
const BlockHeader& value() const {
assert(state_ == State::kDone);
return value_;
}
private:
BlockHeader value_;
VarIntParser uint_parser_;
int timecode_bytes_remaining_ = 2;
enum class State {
// State Transitions to state When
kReadingTrackNumber, // kReadingTimecode track parsed
kReadingTimecode, // kReadingFlags timecode parsed
kReadingFlags, // kDone flags parsed
kDone, // No transitions from here (must call Init)
} state_ = State::kReadingTrackNumber;
};
} // namespace webm
#endif // SRC_BLOCK_HEADER_PARSER_H_

View File

@@ -0,0 +1,32 @@
// 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_BLOCK_MORE_PARSER_H_
#define SRC_BLOCK_MORE_PARSER_H_
#include "src/byte_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#BlockMore
// http://www.webmproject.org/docs/container/#BlockMore
class BlockMoreParser : public MasterValueParser<BlockMore> {
public:
BlockMoreParser()
: MasterValueParser<BlockMore>(
MakeChild<UnsignedIntParser>(Id::kBlockAddId, &BlockMore::id),
MakeChild<BinaryParser>(Id::kBlockAdditional, &BlockMore::data)) {}
};
} // namespace webm
#endif // SRC_BLOCK_MORE_PARSER_H_

View File

@@ -0,0 +1,284 @@
// 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.
#include "src/block_parser.h"
#include <cassert>
#include <cstdint>
#include <numeric>
#include <type_traits>
#include <vector>
#include "src/parser_utils.h"
#include "webm/element.h"
namespace webm {
namespace {
// The ParseBasicBlockFlags functions parse extra flag bits into the block,
// depending on the type of block that is being parsed.
void ParseBasicBlockFlags(std::uint8_t flags, Block* block) {
// Block has no extra flags that aren't already handled.
}
void ParseBasicBlockFlags(std::uint8_t flags, SimpleBlock* block) {
block->is_key_frame = (0x80 & flags) != 0;
block->is_discardable = (0x01 & flags) != 0;
}
// The BasicBlockBegin functions call the Callback event handler and get the
// correct action for the parser, depending on the type of block that is being
// parsed.
Status BasicBlockBegin(const ElementMetadata& metadata, const Block& block,
Callback* callback, Action* action) {
return callback->OnBlockBegin(metadata, block, action);
}
Status BasicBlockBegin(const ElementMetadata& metadata,
const SimpleBlock& block, Callback* callback,
Action* action) {
return callback->OnSimpleBlockBegin(metadata, block, action);
}
// The BasicBlockEnd functions call the Callback event handler depending on the
// type of block that is being parsed.
Status BasicBlockEnd(const ElementMetadata& metadata, const Block& block,
Callback* callback) {
return callback->OnBlockEnd(metadata, block);
}
Status BasicBlockEnd(const ElementMetadata& metadata, const SimpleBlock& block,
Callback* callback) {
return callback->OnSimpleBlockEnd(metadata, block);
}
} // namespace
template <typename T>
Status BasicBlockParser<T>::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == kUnknownElementSize || metadata.size < 5) {
return Status(Status::kInvalidElementSize);
}
*this = {};
frame_metadata_.parent_element = metadata;
return Status(Status::kOkCompleted);
}
template <typename T>
Status BasicBlockParser<T>::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
*num_bytes_read = 0;
Status status;
std::uint64_t local_num_bytes_read;
while (true) {
switch (state_) {
case State::kReadingHeader: {
status = header_parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
header_bytes_read_ += local_num_bytes_read;
if (!status.completed_ok()) {
return status;
}
value_.track_number = header_parser_.value().track_number;
value_.timecode = header_parser_.value().timecode;
std::uint8_t flags = header_parser_.value().flags;
value_.is_visible = (0x08 & flags) == 0;
value_.lacing = static_cast<Lacing>(flags & 0x06);
ParseBasicBlockFlags(flags, &value_);
if (value_.lacing == Lacing::kNone) {
value_.num_frames = 1;
state_ = State::kGettingAction;
} else {
state_ = State::kReadingLaceCount;
}
continue;
}
case State::kReadingLaceCount: {
assert(lace_sizes_.empty());
std::uint8_t lace_count;
status = ReadByte(reader, &lace_count);
if (!status.completed_ok()) {
return status;
}
++*num_bytes_read;
++header_bytes_read_;
// Lace count is stored as (count - 1).
value_.num_frames = lace_count + 1;
state_ = State::kGettingAction;
continue;
}
case State::kGettingAction: {
Action action;
status = BasicBlockBegin(frame_metadata_.parent_element, value_,
callback, &action);
if (!status.completed_ok()) {
return status;
}
if (action == Action::kSkip) {
state_ = State::kSkipping;
} else if (value_.lacing == Lacing::kNone || value_.num_frames == 1) {
state_ = State::kValidatingSize;
} else if (value_.lacing == Lacing::kXiph) {
state_ = State::kReadingXiphLaceSizes;
} else if (value_.lacing == Lacing::kEbml) {
state_ = State::kReadingFirstEbmlLaceSize;
} else {
state_ = State::kCalculatingFixedLaceSizes;
}
continue;
}
case State::kReadingXiphLaceSizes:
assert(value_.num_frames > 0);
while (lace_sizes_.size() < value_.num_frames - 1) {
std::uint8_t byte;
do {
status = ReadByte(reader, &byte);
if (!status.completed_ok()) {
return status;
}
++*num_bytes_read;
++header_bytes_read_;
xiph_lace_size_ += byte;
} while (byte == 255);
lace_sizes_.push_back(xiph_lace_size_);
xiph_lace_size_ = 0;
}
state_ = State::kValidatingSize;
continue;
case State::kReadingFirstEbmlLaceSize:
assert(value_.num_frames > 0);
assert(lace_sizes_.empty());
status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
header_bytes_read_ += local_num_bytes_read;
if (!status.completed_ok()) {
return status;
}
lace_sizes_.push_back(uint_parser_.value());
uint_parser_ = {};
state_ = State::kReadingEbmlLaceSizes;
continue;
case State::kReadingEbmlLaceSizes:
assert(value_.num_frames > 0);
assert(!lace_sizes_.empty());
while (lace_sizes_.size() < value_.num_frames - 1) {
status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
header_bytes_read_ += local_num_bytes_read;
if (!status.completed_ok()) {
return status;
}
constexpr std::uint64_t one = 1; // Prettier than a static_cast.
std::uint64_t offset =
(one << (uint_parser_.encoded_length() * 7 - 1)) - 1;
lace_sizes_.push_back(lace_sizes_.back() + uint_parser_.value() -
offset);
uint_parser_ = {};
}
state_ = State::kValidatingSize;
continue;
case State::kCalculatingFixedLaceSizes: {
assert(value_.num_frames > 0);
assert(lace_sizes_.empty());
if (header_bytes_read_ >= frame_metadata_.parent_element.size) {
return Status(Status::kInvalidElementValue);
}
std::uint64_t laced_data_size =
frame_metadata_.parent_element.size - header_bytes_read_;
std::uint64_t frame_size = laced_data_size / value_.num_frames;
if (laced_data_size % value_.num_frames != 0) {
return Status(Status::kInvalidElementValue);
}
lace_sizes_.resize(value_.num_frames, frame_size);
frame_metadata_.position =
frame_metadata_.parent_element.position + header_bytes_read_;
frame_metadata_.size = frame_size;
state_ = State::kReadingFrames;
continue;
}
case State::kValidatingSize: {
std::uint64_t sum = std::accumulate(
lace_sizes_.begin(), lace_sizes_.end(), header_bytes_read_);
if (sum >= frame_metadata_.parent_element.size) {
return Status(Status::kInvalidElementValue);
}
lace_sizes_.push_back(frame_metadata_.parent_element.size - sum);
frame_metadata_.position = frame_metadata_.parent_element.position +
frame_metadata_.parent_element.header_size +
header_bytes_read_;
frame_metadata_.size = lace_sizes_[0];
state_ = State::kReadingFrames;
continue;
}
case State::kSkipping:
do {
// Skip the remaining part of the header and all of the frames.
status = reader->Skip(
frame_metadata_.parent_element.size - header_bytes_read_,
&local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
header_bytes_read_ += local_num_bytes_read;
} while (status.code == Status::kOkPartial);
return status;
case State::kReadingFrames:
assert(value_.num_frames > 0);
assert(lace_sizes_.size() == value_.num_frames);
for (; current_lace_ < lace_sizes_.size(); ++current_lace_) {
const std::uint64_t original = lace_sizes_[current_lace_];
status = callback->OnFrame(frame_metadata_, reader,
&lace_sizes_[current_lace_]);
*num_bytes_read += original - lace_sizes_[current_lace_];
if (!status.completed_ok()) {
return status;
}
assert(lace_sizes_[current_lace_] == 0);
if (current_lace_ + 1 < lace_sizes_.size()) {
frame_metadata_.position += frame_metadata_.size;
frame_metadata_.size = lace_sizes_[current_lace_ + 1];
}
}
state_ = State::kDone;
continue;
case State::kDone:
return BasicBlockEnd(frame_metadata_.parent_element, value_, callback);
}
}
}
template <typename T> bool BasicBlockParser<T>::WasSkipped() const {
return state_ == State::kSkipping;
}
template class BasicBlockParser<Block>;
template class BasicBlockParser<SimpleBlock>;
} // namespace webm

View File

@@ -0,0 +1,123 @@
// 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_BLOCK_PARSER_H_
#define SRC_BLOCK_PARSER_H_
#include <cassert>
#include <cstdint>
#include <type_traits>
#include <vector>
#include "src/block_header_parser.h"
#include "src/element_parser.h"
#include "src/var_int_parser.h"
#include "webm/callback.h"
#include "webm/dom_types.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses Block and SimpleBlock elements. It is recommended to use the
// BlockParser and SimpleBlockParser aliases.
// Spec reference:
// http://matroska.org/technical/specs/index.html#Block
// http://matroska.org/technical/specs/index.html#SimpleBlock
// http://www.webmproject.org/docs/container/#SimpleBlock
// http://www.webmproject.org/docs/container/#Block
// http://matroska.org/technical/specs/index.html#block_structure
// http://matroska.org/technical/specs/index.html#simpleblock_structure
template <typename T> class BasicBlockParser : public ElementParser {
static_assert(std::is_same<T, Block>::value ||
std::is_same<T, SimpleBlock>::value,
"T must be Block or SimpleBlock");
public:
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
bool WasSkipped() const override;
// Gets the parsed block header information. The frames are not included. This
// must not be called until the parse has been successfully completed.
const T& value() const {
assert(state_ == State::kDone);
return value_;
}
// Gets the parsed block header information. The frames are not included. This
// must not be called until the parse has been successfully completed.
T* mutable_value() {
assert(state_ == State::kDone);
return &value_;
}
private:
// The number of header bytes read (header meaning everything before the
// frames).
std::uint64_t header_bytes_read_ = 0;
// The parsed header value for the element.
T value_{};
// Metadata for the frame that is currently being read.
FrameMetadata frame_metadata_;
// Parser for parsing header metadata that is common between Block and
// SimpleBlock.
BlockHeaderParser header_parser_;
// Parser for parsing unsigned EBML variable-sized integers.
VarIntParser uint_parser_;
// The current lace size when parsing Xiph lace sizes.
std::uint64_t xiph_lace_size_ = 0;
// Lace (frame) sizes, where each entry represents the size of a frame.
std::vector<std::uint64_t> lace_sizes_;
// The current index into lace_sizes_ for the current frame being read.
std::size_t current_lace_ = 0;
// Parsing states for the finite-state machine.
enum class State {
// State Transitions to state When
kReadingHeader, // kGettingAction no lacing
// kReadingLaceCount yes lacing
kReadingLaceCount, // kGettingAction no errors
kGettingAction, // kSkipping action == skip
// kValidatingSize no lacing
// kReadingXiphLaceSizes xiph lacing
// kReadingFirstEbmlLaceSize ebml lacing
// kCalculatingFixedLaceSizes fixed lacing
kReadingXiphLaceSizes, // kValidatingSize all sizes read
kReadingFirstEbmlLaceSize, // kReadingEbmlLaceSizes first size read
kReadingEbmlLaceSizes, // kValidatingSize all sizes read
kCalculatingFixedLaceSizes, // kReadingFrames no errors
kValidatingSize, // kReadingFrames no errors
kSkipping, // No transitions from here (must call Init)
kReadingFrames, // kDone all frames read
kDone, // No transitions from here (must call Init)
};
// The current state of the parser.
State state_ = State::kReadingHeader;
};
extern template class BasicBlockParser<Block>;
extern template class BasicBlockParser<SimpleBlock>;
using BlockParser = BasicBlockParser<Block>;
using SimpleBlockParser = BasicBlockParser<SimpleBlock>;
} // namespace webm
#endif // SRC_BLOCK_PARSER_H_

View File

@@ -0,0 +1,95 @@
// 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_BOOL_PARSER_H_
#define SRC_BOOL_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/element_parser.h"
#include "src/parser_utils.h"
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses a boolean from a byte stream. EBML does not have a boolean type, but
// the Matroska spec defines some unsigned integer elements that have a range of
// [0, 1]. The BoolParser parses these unsigned integer elements into
// true/false, and reports a Status::kInvalidElementValue error if the integer
// is outside of its permitted range.
class BoolParser : public ElementParser {
public:
explicit BoolParser(bool default_value = false)
: default_value_(default_value) {}
Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) override {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
// Booleans are really just unsigned integers with a range limit of 0-1.
// Unsigned integers can't be encoded with more than 8 bytes.
if (metadata.size > 8) {
return Status(Status::kInvalidElementSize);
}
size_ = num_bytes_remaining_ = static_cast<int>(metadata.size);
value_ = default_value_;
return Status(Status::kOkCompleted);
}
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
std::uint64_t uint_value = 0;
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
&uint_value, num_bytes_read);
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
// Only the last byte should have a value, and it should only be 0 or 1.
if ((num_bytes_remaining_ != 0 && uint_value != 0) || uint_value > 1) {
return Status(Status::kInvalidElementValue);
}
if (size_ > 0) {
value_ = uint_value == 1;
}
return status;
}
// Gets the parsed bool. This must not be called until the parse had been
// successfully completed.
bool value() const {
assert(num_bytes_remaining_ == 0);
return value_;
}
// Gets the parsed bool. This must not be called until the parse had been
// successfully completed.
bool* mutable_value() {
assert(num_bytes_remaining_ == 0);
return &value_;
}
private:
bool value_;
bool default_value_;
int num_bytes_remaining_ = -1;
int size_;
};
} // namespace webm
#endif // SRC_BOOL_PARSER_H_

View File

@@ -0,0 +1,110 @@
// 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.
#include "webm/buffer_reader.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <utility>
#include <vector>
#include "webm/status.h"
namespace webm {
BufferReader::BufferReader(std::initializer_list<std::uint8_t> bytes)
: data_(bytes) {}
BufferReader::BufferReader(const std::vector<std::uint8_t>& vector)
: data_(vector) {}
BufferReader::BufferReader(std::vector<std::uint8_t>&& vector)
: data_(std::move(vector)) {}
BufferReader::BufferReader(BufferReader&& other)
: data_(std::move(other.data_)), pos_(other.pos_) {
other.pos_ = 0;
}
BufferReader& BufferReader::operator=(BufferReader&& other) {
if (this != &other) {
data_ = std::move(other.data_);
pos_ = other.pos_;
other.pos_ = 0;
}
return *this;
}
BufferReader& BufferReader::operator=(
std::initializer_list<std::uint8_t> bytes) {
data_ = std::vector<std::uint8_t>(bytes);
pos_ = 0;
return *this;
}
Status BufferReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
std::uint64_t* num_actually_read) {
assert(num_to_read > 0);
assert(buffer != nullptr);
assert(num_actually_read != nullptr);
*num_actually_read = 0;
std::size_t expected = num_to_read;
std::size_t num_remaining = data_.size() - pos_;
if (num_remaining == 0) {
return Status(Status::kEndOfFile);
}
if (num_to_read > num_remaining) {
num_to_read = static_cast<std::size_t>(num_remaining);
}
std::copy_n(data_.data() + pos_, num_to_read, buffer);
*num_actually_read = num_to_read;
pos_ += num_to_read;
if (*num_actually_read != expected) {
return Status(Status::kOkPartial);
}
return Status(Status::kOkCompleted);
}
Status BufferReader::Skip(std::uint64_t num_to_skip,
std::uint64_t* num_actually_skipped) {
assert(num_to_skip > 0);
assert(num_actually_skipped != nullptr);
*num_actually_skipped = 0;
std::uint64_t expected = num_to_skip;
std::size_t num_remaining = data_.size() - pos_;
if (num_remaining == 0) {
return Status(Status::kEndOfFile);
}
if (num_to_skip > num_remaining) {
num_to_skip = static_cast<std::uint64_t>(num_remaining);
}
*num_actually_skipped = num_to_skip;
pos_ += num_to_skip;
if (*num_actually_skipped != expected) {
return Status(Status::kOkPartial);
}
return Status(Status::kOkCompleted);
}
std::uint64_t BufferReader::Position() const { return pos_; }
} // namespace webm

View File

@@ -0,0 +1,143 @@
// 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_BYTE_PARSER_H_
#define SRC_BYTE_PARSER_H_
#include <cassert>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses an EBML string (UTF-8 and ASCII) or binary element from a byte stream.
// Spec reference for string/binary elements:
// http://matroska.org/technical/specs/index.html#EBML_ex
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-element-types
template <typename T> class ByteParser : public ElementParser {
public:
static_assert(std::is_same<T, std::vector<std::uint8_t>>::value ||
std::is_same<T, std::string>::value,
"T must be std::vector<std::uint8_t> or std::string");
// Constructs a new parser which will use the given default_value as the
// value for the element if its size is zero. Defaults to the empty string
// or empty binary element (as the EBML spec indicates).
explicit ByteParser(T default_value = {})
: default_value_(std::move(default_value)) {}
ByteParser(ByteParser&&) = default;
ByteParser& operator=(ByteParser&&) = default;
ByteParser(const ByteParser&) = delete;
ByteParser& operator=(const ByteParser&) = delete;
Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) override {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == kUnknownElementSize) {
return Status(Status::kInvalidElementSize);
}
if (metadata.size > std::numeric_limits<std::size_t>::max() ||
metadata.size > value_.max_size()) {
return Status(Status::kNotEnoughMemory);
}
#if WEBM_FUZZER_BYTE_ELEMENT_SIZE_LIMIT
// AFL and ASan just kill the process if too much memory is allocated, so
// let's cap the maximum size of the element. It's too easy for the fuzzer
// to make an element with a ridiculously huge size, and that just creates
// uninteresting false positives.
if (metadata.size > WEBM_FUZZER_BYTE_ELEMENT_SIZE_LIMIT) {
return Status(Status::kNotEnoughMemory);
}
#endif
if (metadata.size == 0) {
value_ = default_value_;
total_read_ = default_value_.size();
} else {
value_.resize(static_cast<std::size_t>(metadata.size));
total_read_ = 0;
}
return Status(Status::kOkCompleted);
}
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 (total_read_ == value_.size()) {
return Status(Status::kOkCompleted);
}
Status status;
do {
std::uint64_t local_num_bytes_read = 0;
std::uint8_t* buffer =
reinterpret_cast<std::uint8_t*>(&value_.front()) + total_read_;
std::size_t buffer_size = value_.size() - total_read_;
status = reader->Read(buffer_size, buffer, &local_num_bytes_read);
assert((status.completed_ok() && local_num_bytes_read == buffer_size) ||
(status.ok() && local_num_bytes_read < buffer_size) ||
(!status.ok() && local_num_bytes_read == 0));
*num_bytes_read += local_num_bytes_read;
total_read_ += static_cast<std::size_t>(local_num_bytes_read);
} while (status.code == Status::kOkPartial);
// UTF-8 and ASCII string elements can be padded with NUL characters at the
// end, which should be ignored.
if (std::is_same<T, std::string>::value && status.completed_ok()) {
while (!value_.empty() && value_.back() == '\0') {
value_.pop_back();
}
}
return status;
}
// Gets the parsed value. This must not be called until the parse has been
// successfully completed.
const T& value() const {
assert(total_read_ >= value_.size());
return value_;
}
// Gets the parsed value. This must not be called until the parse has been
// successfully completed.
T* mutable_value() {
assert(total_read_ >= value_.size());
return &value_;
}
private:
T value_;
T default_value_;
std::size_t total_read_;
};
using StringParser = ByteParser<std::string>;
using BinaryParser = ByteParser<std::vector<std::uint8_t>>;
} // namespace webm
#endif // SRC_BYTE_PARSER_H_

150
webm_parser/src/callback.cc Normal file
View File

@@ -0,0 +1,150 @@
// 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.
#include "webm/callback.h"
#include <cassert>
namespace webm {
Status Callback::OnElementBegin(const ElementMetadata& metadata,
Action* action) {
assert(action != nullptr);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status Callback::OnUnknownElement(const ElementMetadata& metadata,
Reader* reader,
std::uint64_t* bytes_remaining) {
assert(reader != nullptr);
assert(bytes_remaining != nullptr);
return Skip(reader, bytes_remaining);
}
Status Callback::OnEbml(const ElementMetadata& metadata, const Ebml& ebml) {
return Status(Status::kOkCompleted);
}
Status Callback::OnVoid(const ElementMetadata& metadata, Reader* reader,
std::uint64_t* bytes_remaining) {
assert(reader != nullptr);
assert(bytes_remaining != nullptr);
return Skip(reader, bytes_remaining);
}
Status Callback::OnSegmentBegin(const ElementMetadata& metadata,
Action* action) {
assert(action != nullptr);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status Callback::OnSeek(const ElementMetadata& metadata, const Seek& seek) {
return Status(Status::kOkCompleted);
}
Status Callback::OnInfo(const ElementMetadata& metadata, const Info& info) {
return Status(Status::kOkCompleted);
}
Status Callback::OnClusterBegin(const ElementMetadata& metadata,
const Cluster& cluster, Action* action) {
assert(action != nullptr);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status Callback::OnSimpleBlockBegin(const ElementMetadata& metadata,
const SimpleBlock& simple_block,
Action* action) {
assert(action != nullptr);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status Callback::OnSimpleBlockEnd(const ElementMetadata& metadata,
const SimpleBlock& simple_block) {
return Status(Status::kOkCompleted);
}
Status Callback::OnBlockGroupBegin(const ElementMetadata& metadata,
Action* action) {
assert(action != nullptr);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status Callback::OnBlockBegin(const ElementMetadata& metadata,
const Block& block, Action* action) {
assert(action != nullptr);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status Callback::OnBlockEnd(const ElementMetadata& metadata,
const Block& block) {
return Status(Status::kOkCompleted);
}
Status Callback::OnBlockGroupEnd(const ElementMetadata& metadata,
const BlockGroup& block_group) {
return Status(Status::kOkCompleted);
}
Status Callback::OnFrame(const FrameMetadata& metadata, Reader* reader,
std::uint64_t* bytes_remaining) {
assert(reader != nullptr);
assert(bytes_remaining != nullptr);
return Skip(reader, bytes_remaining);
}
Status Callback::OnClusterEnd(const ElementMetadata& metadata,
const Cluster& cluster) {
return Status(Status::kOkCompleted);
}
Status Callback::OnTrackEntry(const ElementMetadata& metadata,
const TrackEntry& track_entry) {
return Status(Status::kOkCompleted);
}
Status Callback::OnCuePoint(const ElementMetadata& metadata,
const CuePoint& cue_point) {
return Status(Status::kOkCompleted);
}
Status Callback::OnEditionEntry(const ElementMetadata& metadata,
const EditionEntry& edition_entry) {
return Status(Status::kOkCompleted);
}
Status Callback::OnTag(const ElementMetadata& metadata, const Tag& tag) {
return Status(Status::kOkCompleted);
}
Status Callback::OnSegmentEnd(const ElementMetadata& metadata) {
return Status(Status::kOkCompleted);
}
Status Callback::Skip(Reader* reader, std::uint64_t* bytes_remaining) {
assert(reader != nullptr);
assert(bytes_remaining != nullptr);
if (*bytes_remaining == 0) return Status(Status::kOkCompleted);
Status status;
do {
std::uint64_t num_actually_skipped;
status = reader->Skip(*bytes_remaining, &num_actually_skipped);
*bytes_remaining -= num_actually_skipped;
} while (status.code == Status::kOkPartial);
return status;
}
} // namespace webm

View File

@@ -0,0 +1,43 @@
// 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_CHAPTER_ATOM_PARSER_H_
#define SRC_CHAPTER_ATOM_PARSER_H_
#include "src/byte_parser.h"
#include "src/chapter_display_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "src/recursive_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#ChapterAtom
// http://www.webmproject.org/docs/container/#ChapterAtom
class ChapterAtomParser : public MasterValueParser<ChapterAtom> {
public:
ChapterAtomParser()
: MasterValueParser<ChapterAtom>(
MakeChild<UnsignedIntParser>(Id::kChapterUid, &ChapterAtom::uid),
MakeChild<StringParser>(Id::kChapterStringUid,
&ChapterAtom::string_uid),
MakeChild<UnsignedIntParser>(Id::kChapterTimeStart,
&ChapterAtom::time_start),
MakeChild<UnsignedIntParser>(Id::kChapterTimeEnd,
&ChapterAtom::time_end),
MakeChild<ChapterDisplayParser>(Id::kChapterDisplay,
&ChapterAtom::displays),
MakeChild<RecursiveParser<ChapterAtomParser>>(
Id::kChapterAtom, &ChapterAtom::atoms)) {}
};
} // namespace webm
#endif // SRC_CHAPTER_ATOM_PARSER_H_

View File

@@ -0,0 +1,34 @@
// 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_CHAPTER_DISPLAY_PARSER_H_
#define SRC_CHAPTER_DISPLAY_PARSER_H_
#include "src/byte_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#ChapterDisplay
// http://www.webmproject.org/docs/container/#ChapterDisplay
class ChapterDisplayParser : public MasterValueParser<ChapterDisplay> {
public:
ChapterDisplayParser()
: MasterValueParser<ChapterDisplay>(
MakeChild<StringParser>(Id::kChapString, &ChapterDisplay::string),
MakeChild<StringParser>(Id::kChapLanguage,
&ChapterDisplay::languages),
MakeChild<StringParser>(Id::kChapCountry,
&ChapterDisplay::countries)) {}
};
} // namespace webm
#endif // SRC_CHAPTER_DISPLAY_PARSER_H_

View File

@@ -0,0 +1,28 @@
// 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_CHAPTERS_PARSER_H_
#define SRC_CHAPTERS_PARSER_H_
#include "src/edition_entry_parser.h"
#include "src/master_parser.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Chapters
// http://www.webmproject.org/docs/container/#Chapters
class ChaptersParser : public MasterParser {
public:
ChaptersParser()
: MasterParser(MakeChild<EditionEntryParser>(Id::kEditionEntry)) {}
};
} // namespace webm
#endif // SRC_CHAPTERS_PARSER_H_

View File

@@ -0,0 +1,48 @@
// 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_CLUSTER_PARSER_H_
#define SRC_CLUSTER_PARSER_H_
#include "src/block_group_parser.h"
#include "src/block_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Cluster
// http://www.webmproject.org/docs/container/#Cluster
class ClusterParser : public MasterValueParser<Cluster> {
public:
ClusterParser()
: MasterValueParser<Cluster>(
MakeChild<UnsignedIntParser>(Id::kTimecode, &Cluster::timecode),
MakeChild<UnsignedIntParser>(Id::kPrevSize,
&Cluster::previous_size),
MakeChild<SimpleBlockParser>(Id::kSimpleBlock,
&Cluster::simple_blocks)
.UseAsStartEvent(),
MakeChild<BlockGroupParser>(Id::kBlockGroup, &Cluster::block_groups)
.UseAsStartEvent()) {}
protected:
Status OnParseStarted(Callback* callback, Action* action) override {
return callback->OnClusterBegin(metadata(Id::kCluster), value(), action);
}
Status OnParseCompleted(Callback* callback) override {
return callback->OnClusterEnd(metadata(Id::kCluster), value());
}
};
} // namespace webm
#endif // SRC_CLUSTER_PARSER_H_

View File

@@ -0,0 +1,55 @@
// 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_COLOUR_PARSER_H_
#define SRC_COLOUR_PARSER_H_
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "src/mastering_metadata_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Colour
// http://www.webmproject.org/docs/container/#Colour
class ColourParser : public MasterValueParser<Colour> {
public:
ColourParser()
: MasterValueParser<Colour>(
MakeChild<IntParser<MatrixCoefficients>>(
Id::kMatrixCoefficients, &Colour::matrix_coefficients),
MakeChild<UnsignedIntParser>(Id::kBitsPerChannel,
&Colour::bits_per_channel),
MakeChild<UnsignedIntParser>(Id::kChromaSubsamplingHorz,
&Colour::chroma_subsampling_x),
MakeChild<UnsignedIntParser>(Id::kChromaSubsamplingVert,
&Colour::chroma_subsampling_y),
MakeChild<UnsignedIntParser>(Id::kCbSubsamplingHorz,
&Colour::cb_subsampling_x),
MakeChild<UnsignedIntParser>(Id::kCbSubsamplingVert,
&Colour::cb_subsampling_y),
MakeChild<UnsignedIntParser>(Id::kChromaSitingHorz,
&Colour::chroma_siting_x),
MakeChild<UnsignedIntParser>(Id::kChromaSitingVert,
&Colour::chroma_siting_y),
MakeChild<IntParser<Range>>(Id::kRange, &Colour::range),
MakeChild<IntParser<TransferCharacteristics>>(
Id::kTransferCharacteristics,
&Colour::transfer_characteristics),
MakeChild<IntParser<Primaries>>(Id::kPrimaries, &Colour::primaries),
MakeChild<UnsignedIntParser>(Id::kMaxCll, &Colour::max_cll),
MakeChild<UnsignedIntParser>(Id::kMaxFall, &Colour::max_fall),
MakeChild<MasteringMetadataParser>(Id::kMasteringMetadata,
&Colour::mastering_metadata)) {}
};
} // namespace webm
#endif // SRC_COLOUR_PARSER_H_

View File

@@ -0,0 +1,32 @@
// 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_CONTENT_ENC_AES_SETTINGS_PARSER_H_
#define SRC_CONTENT_ENC_AES_SETTINGS_PARSER_H_
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://www.webmproject.org/docs/webm-encryption/#42-new-matroskawebm-elements
class ContentEncAesSettingsParser
: public MasterValueParser<ContentEncAesSettings> {
public:
ContentEncAesSettingsParser()
: MasterValueParser<ContentEncAesSettings>(
MakeChild<IntParser<AesSettingsCipherMode>>(
Id::kAesSettingsCipherMode,
&ContentEncAesSettings::aes_settings_cipher_mode)) {}
};
} // namespace webm
#endif // SRC_CONTENT_ENC_AES_SETTINGS_PARSER_H_

View File

@@ -0,0 +1,38 @@
// 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_CONTENT_ENCODING_PARSER_H_
#define SRC_CONTENT_ENCODING_PARSER_H_
#include "src/content_encryption_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#ContentEncoding
// http://www.webmproject.org/docs/container/#ContentEncoding
class ContentEncodingParser : public MasterValueParser<ContentEncoding> {
public:
ContentEncodingParser()
: MasterValueParser<ContentEncoding>(
MakeChild<UnsignedIntParser>(Id::kContentEncodingOrder,
&ContentEncoding::order),
MakeChild<UnsignedIntParser>(Id::kContentEncodingScope,
&ContentEncoding::scope),
MakeChild<IntParser<ContentEncodingType>>(Id::kContentEncodingType,
&ContentEncoding::type),
MakeChild<ContentEncryptionParser>(Id::kContentEncryption,
&ContentEncoding::encryption)) {}
};
} // namespace webm
#endif // SRC_CONTENT_ENCODING_PARSER_H_

View File

@@ -0,0 +1,30 @@
// 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_CONTENT_ENCODINGS_PARSER_H_
#define SRC_CONTENT_ENCODINGS_PARSER_H_
#include "src/content_encoding_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#ContentEncodings
// http://www.webmproject.org/docs/container/#ContentEncodings
class ContentEncodingsParser : public MasterValueParser<ContentEncodings> {
public:
ContentEncodingsParser()
: MasterValueParser<ContentEncodings>(MakeChild<ContentEncodingParser>(
Id::kContentEncoding, &ContentEncodings::encodings)) {}
};
} // namespace webm
#endif // SRC_CONTENT_ENCODINGS_PARSER_H_

View File

@@ -0,0 +1,37 @@
// 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_CONTENT_ENCRYPTION_PARSER_H_
#define SRC_CONTENT_ENCRYPTION_PARSER_H_
#include "src/byte_parser.h"
#include "src/content_enc_aes_settings_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#ContentEncryption
// http://www.webmproject.org/docs/container/#ContentEncryption
class ContentEncryptionParser : public MasterValueParser<ContentEncryption> {
public:
ContentEncryptionParser()
: MasterValueParser<ContentEncryption>(
MakeChild<IntParser<ContentEncAlgo>>(Id::kContentEncAlgo,
&ContentEncryption::algorithm),
MakeChild<BinaryParser>(Id::kContentEncKeyId,
&ContentEncryption::key_id),
MakeChild<ContentEncAesSettingsParser>(
Id::kContentEncAesSettings, &ContentEncryption::aes_settings)) {
}
};
} // namespace webm
#endif // SRC_CONTENT_ENCRYPTION_PARSER_H_

View File

@@ -0,0 +1,38 @@
// 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_CUE_POINT_PARSER_H_
#define SRC_CUE_POINT_PARSER_H_
#include "src/cue_track_positions_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#CuePoint
// http://www.webmproject.org/docs/container/#CuePoint
class CuePointParser : public MasterValueParser<CuePoint> {
public:
CuePointParser()
: MasterValueParser<CuePoint>(
MakeChild<UnsignedIntParser>(Id::kCueTime, &CuePoint::time),
MakeChild<CueTrackPositionsParser>(
Id::kCueTrackPositions, &CuePoint::cue_track_positions)) {}
protected:
Status OnParseCompleted(Callback* callback) override {
return callback->OnCuePoint(metadata(Id::kCuePoint), value());
}
};
} // namespace webm
#endif // SRC_CUE_POINT_PARSER_H_

View File

@@ -0,0 +1,39 @@
// 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_CUE_TRACK_POSITIONS_PARSER_H_
#define SRC_CUE_TRACK_POSITIONS_PARSER_H_
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#CueTrackPositions
// http://www.webmproject.org/docs/container/#CueTrackPositions
class CueTrackPositionsParser : public MasterValueParser<CueTrackPositions> {
public:
CueTrackPositionsParser()
: MasterValueParser<CueTrackPositions>(
MakeChild<UnsignedIntParser>(Id::kCueTrack,
&CueTrackPositions::track),
MakeChild<UnsignedIntParser>(Id::kCueClusterPosition,
&CueTrackPositions::cluster_position),
MakeChild<UnsignedIntParser>(Id::kCueRelativePosition,
&CueTrackPositions::relative_position),
MakeChild<UnsignedIntParser>(Id::kCueDuration,
&CueTrackPositions::duration),
MakeChild<UnsignedIntParser>(Id::kCueBlockNumber,
&CueTrackPositions::block_number)) {}
};
} // namespace webm
#endif // SRC_CUE_TRACK_POSITIONS_PARSER_H_

View File

@@ -0,0 +1,27 @@
// 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_CUES_PARSER_H_
#define SRC_CUES_PARSER_H_
#include "src/cue_point_parser.h"
#include "src/master_parser.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Cues
// http://www.webmproject.org/docs/container/#Cues
class CuesParser : public MasterParser {
public:
CuesParser() : MasterParser(MakeChild<CuePointParser>(Id::kCuePoint)) {}
};
} // namespace webm
#endif // SRC_CUES_PARSER_H_

View File

@@ -0,0 +1,72 @@
// 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.
#include "src/date_parser.h"
#include <cassert>
#include <cstdint>
#include <limits>
#include "src/parser_utils.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#EBML_ex
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-element-types
DateParser::DateParser(std::int64_t default_value)
: default_value_(default_value) {}
Status DateParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size != 0 && metadata.size != 8) {
return Status(Status::kInvalidElementSize);
}
num_bytes_remaining_ = static_cast<int>(metadata.size);
// The meaning of a 0-byte element is still being debated. EBML says the value
// is zero; Matroska says it's the default according to whatever the document
// spec says. Neither specifies what a 0-byte mandatory element means. I've
// asked about this on the Matroska mailing list. I'm going to assume a 0-byte
// mandatory element should be treated the same as a 0-byte optional element,
// meaning that they both get their default value (which may be some value
// other than zero). This applies to all non-master-elements (not just dates).
// This parser is an EBML-level parser, and so will default to a value of
// zero. The Matroska-level parser can reset this default value to something
// else after parsing (as needed).
// See:
// https://github.com/Matroska-Org/ebml-specification/pull/17
// http://lists.matroska.org/pipermail/matroska-devel/2015-October/004866.html
if (metadata.size == 0) {
value_ = default_value_;
} else {
value_ = 0;
}
return Status(Status::kOkCompleted);
}
Status DateParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
&value_, num_bytes_read);
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
return status;
}
} // namespace webm

View File

@@ -0,0 +1,64 @@
// 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_DATE_PARSER_H_
#define SRC_DATE_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses an EBML date from a byte stream. EBML dates are signed integer values
// that represent the offset, in nanoseconds, from 2001-01-01T00:00:00.00 UTC.
class DateParser : public ElementParser {
public:
// Constructs a new parser which will use the given default_value as the
// value for the element if its size is zero. Defaults to the value zero (as
// the EBML spec indicates).
explicit DateParser(std::int64_t default_value = 0);
DateParser(DateParser&&) = default;
DateParser& operator=(DateParser&&) = default;
DateParser(const DateParser&) = delete;
DateParser& operator=(const DateParser&) = delete;
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed date. This must not be called until the parse had been
// successfully completed.
std::int64_t value() const {
assert(num_bytes_remaining_ == 0);
return value_;
}
// Gets the parsed date. This must not be called until the parse had been
// successfully completed.
std::int64_t* mutable_value() {
assert(num_bytes_remaining_ == 0);
return &value_;
}
private:
std::int64_t value_;
std::int64_t default_value_;
int num_bytes_remaining_ = -1;
};
} // namespace webm
#endif // SRC_DATE_PARSER_H_

View File

@@ -0,0 +1,48 @@
// 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_EBML_PARSER_H_
#define SRC_EBML_PARSER_H_
#include "src/byte_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec references:
// http://matroska.org/technical/specs/index.html#EBML
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-header-elements
// http://www.webmproject.org/docs/container/#EBML
class EbmlParser : public MasterValueParser<Ebml> {
public:
EbmlParser()
: MasterValueParser<Ebml>(
MakeChild<UnsignedIntParser>(Id::kEbmlVersion, &Ebml::ebml_version),
MakeChild<UnsignedIntParser>(Id::kEbmlReadVersion,
&Ebml::ebml_read_version),
MakeChild<UnsignedIntParser>(Id::kEbmlMaxIdLength,
&Ebml::ebml_max_id_length),
MakeChild<UnsignedIntParser>(Id::kEbmlMaxSizeLength,
&Ebml::ebml_max_size_length),
MakeChild<StringParser>(Id::kDocType, &Ebml::doc_type),
MakeChild<UnsignedIntParser>(Id::kDocTypeVersion,
&Ebml::doc_type_version),
MakeChild<UnsignedIntParser>(Id::kDocTypeReadVersion,
&Ebml::doc_type_read_version)) {}
protected:
Status OnParseCompleted(Callback* callback) override {
return callback->OnEbml(metadata(Id::kEbml), value());
}
};
} // namespace webm
#endif // SRC_EBML_PARSER_H_

View File

@@ -0,0 +1,35 @@
// 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_EDITION_ENTRY_PARSER_H_
#define SRC_EDITION_ENTRY_PARSER_H_
#include "src/chapter_atom_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#EditionEntry
// http://www.webmproject.org/docs/container/#EditionEntry
class EditionEntryParser : public MasterValueParser<EditionEntry> {
public:
EditionEntryParser()
: MasterValueParser<EditionEntry>(MakeChild<ChapterAtomParser>(
Id::kChapterAtom, &EditionEntry::atoms)) {}
protected:
Status OnParseCompleted(Callback* callback) override {
return callback->OnEditionEntry(metadata(Id::kEditionEntry), value());
}
};
} // namespace webm
#endif // SRC_EDITION_ENTRY_PARSER_H_

View File

@@ -0,0 +1,102 @@
// 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_ELEMENT_PARSER_H_
#define SRC_ELEMENT_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/ancestory.h"
#include "src/parser.h"
#include "webm/callback.h"
#include "webm/element.h"
namespace webm {
// Parses an element from a WebM byte stream. Objects that implement this
// interface are expected to be used as follows in order to parse the specific
// WebM element that they are designed to handle.
//
// Reader* reader = ...; // Create some Reader.
// Callback* callback = ...; // Create some Callback.
//
// ElementMetadata metadata = {
// id, // Element parsed from the reader.
// header_size, // The number of bytes used to encode the id and size.
// size_in_bytes, // The number of bytes in the element body.
// position, // The position of the element (starting at the ID).
// };
//
// std::uint64_t max_size = ...; // Some upper bound on this element's size.
// ElementParser* parser = ...; // Create some parser capable of handling
// // elements that match id.
//
// Status status = parser->Init(metadata, max_size);
// if (!status.completed_ok()) {
// // An error occurred. See status.code for the reason.
// } else {
// do {
// std::uint64_t num_bytes_read = 0;
// status = parser->Feed(callback, reader, &num_bytes_read);
// } while (status.code == Status::kOkPartial);
//
// if (status.completed_ok()) {
// // Parsing successfully completed.
// } else {
// // An error occurred. If status.code is a parsing error (see status.h for
// // errors that are considered parsing errors), do not call Feed again;
// // parsing has already failed and further progress can't be made. If
// // status.code is not a parsing error (i.e. Status::kWouldBlock), then
// // Feed may be called again to attempt resuming parsing.
// }
// }
class ElementParser : public Parser {
public:
// Initializes the parser and prepares it for parsing its element. Returns
// Status::kOkCompleted if successful. Must not return Status::kOkPartial (it
// is not resumable). metadata is the metadata associated with this element.
// max_size must be <= metadata.size (unless metadata.size is
// kUnknownElementSize).
virtual Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) = 0;
// Initializes the parser after a seek was done and prepares it for parsing.
// The reader is now at the position of the child element indicated by
// child_metadata, whose ancestory is child_ancestory. The child element for
// this parser is the first element in child_ancestory, or if that is empty,
// then child_metadata itself. If the child is not a valid child of this
// parser, then a debug assertion is made (because that indicates a bug).
virtual void InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) {
assert(false);
}
// Returns true and sets metadata if this parser read too far and read the
// element metadata for an element that is not its child. This may happen, for
// example, when an element with unknown size is being read (because its end
// is considered the first element that is not a valid child, so it must read
// further to detect this). If this did not happen and false is returned, then
// metadata will not be modified. metadata must not be null.
virtual bool GetCachedMetadata(ElementMetadata* metadata) {
assert(metadata != nullptr);
return false;
}
// Returns true if this parser skipped the element instead of fully parsing
// it. This will be true if the user requested a kSkip action from the
// Callback in Feed(). This method should only be called after Feed() has
// returned kOkCompleted. If the element was skipped, do not try to access its
// value; it has no meaningful value and doing so will likely result in an
// assertion failing.
virtual bool WasSkipped() const { return false; }
};
} // namespace webm
#endif // SRC_ELEMENT_PARSER_H_

View File

@@ -0,0 +1,122 @@
// 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.
#include "webm/file_reader.h"
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <memory>
#include "webm/status.h"
namespace webm {
FileReader::FileReader(FILE* file) : file_(file) { assert(file); }
FileReader::FileReader(FileReader&& other)
: file_(std::move(other.file_)), position_(other.position_) {
other.position_ = 0;
}
FileReader& FileReader::operator=(FileReader&& other) {
if (this != &other) {
file_ = std::move(other.file_);
position_ = other.position_;
other.position_ = 0;
}
return *this;
}
Status FileReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
std::uint64_t* num_actually_read) {
assert(num_to_read > 0);
assert(buffer != nullptr);
assert(num_actually_read != nullptr);
if (file_ == nullptr) {
*num_actually_read = 0;
return Status(Status::kEndOfFile);
}
std::size_t actual =
std::fread(static_cast<void*>(buffer), 1, num_to_read, file_.get());
*num_actually_read = static_cast<std::uint64_t>(actual);
position_ += *num_actually_read;
if (actual == 0) {
return Status(Status::kEndOfFile);
}
if (actual == num_to_read) {
return Status(Status::kOkCompleted);
} else {
return Status(Status::kOkPartial);
}
}
Status FileReader::Skip(std::uint64_t num_to_skip,
std::uint64_t* num_actually_skipped) {
assert(num_to_skip > 0);
assert(num_actually_skipped != nullptr);
*num_actually_skipped = 0;
if (file_ == nullptr) {
return Status(Status::kEndOfFile);
}
// Try seeking forward first.
long seek_offset = std::numeric_limits<long>::max(); // NOLINT
if (num_to_skip < static_cast<unsigned long>(seek_offset)) { // NOLINT
seek_offset = static_cast<long>(num_to_skip); // NOLINT
}
// TODO(mjbshaw): Use fseeko64/_fseeki64 if available.
if (!std::fseek(file_.get(), seek_offset, SEEK_CUR)) {
*num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
position_ += static_cast<std::uint64_t>(seek_offset);
if (static_cast<unsigned long>(seek_offset) == num_to_skip) { // NOLINT
return Status(Status::kOkCompleted);
} else {
return Status(Status::kOkPartial);
}
}
std::clearerr(file_.get());
// Seeking doesn't work on things like pipes, so if seeking failed then fall
// back to reading the data into a junk buffer.
std::size_t actual = 0;
do {
std::uint8_t junk[1024];
std::size_t num_to_read = sizeof(junk);
if (num_to_skip < num_to_read) {
num_to_read = static_cast<std::size_t>(num_to_skip);
}
std::size_t actual =
std::fread(static_cast<void*>(junk), 1, num_to_read, file_.get());
*num_actually_skipped += static_cast<std::uint64_t>(actual);
position_ += static_cast<std::uint64_t>(actual);
num_to_skip -= static_cast<std::uint64_t>(actual);
} while (actual > 0 && num_to_skip > 0);
if (*num_actually_skipped == 0) {
return Status(Status::kEndOfFile);
}
if (num_to_skip == 0) {
return Status(Status::kOkCompleted);
} else {
return Status(Status::kOkPartial);
}
}
std::uint64_t FileReader::Position() const { return position_; }
} // namespace webm

View File

@@ -0,0 +1,77 @@
// 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.
#include "src/float_parser.h"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <limits>
#include "src/parser_utils.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
FloatParser::FloatParser(double default_value)
: default_value_(default_value) {}
Status FloatParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == 0) {
value_ = default_value_;
} else if (metadata.size == 4 || metadata.size == 8) {
uint64_value_ = 0;
} else {
return Status(Status::kInvalidElementSize);
}
num_bytes_remaining_ = static_cast<int>(metadata.size);
use_32_bits_ = metadata.size == 4;
return Status(Status::kOkCompleted);
}
Status FloatParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
if (num_bytes_remaining_ == 0) {
return Status(Status::kOkCompleted);
}
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
&uint64_value_, num_bytes_read);
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
if (num_bytes_remaining_ == 0) {
if (use_32_bits_) {
static_assert(std::numeric_limits<float>::is_iec559,
"Your compiler does not support 32-bit IEC 559/IEEE 754 "
"floating point types");
std::uint32_t uint32_value = static_cast<std::uint32_t>(uint64_value_);
float float32_value;
std::memcpy(&float32_value, &uint32_value, 4);
value_ = float32_value;
} else {
static_assert(std::numeric_limits<double>::is_iec559,
"Your compiler does not support 64-bit IEC 559/IEEE 754 "
"floating point types");
std::memcpy(&value_, &uint64_value_, 8);
}
}
return status;
}
} // namespace webm

View File

@@ -0,0 +1,65 @@
// 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_FLOAT_PARSER_H_
#define SRC_FLOAT_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses an EBML float from a byte stream.
class FloatParser : public ElementParser {
public:
// Constructs a new parser which will use the given default_value as the
// value for the element if its size is zero. Defaults to the value zero (as
// the EBML spec indicates).
explicit FloatParser(double default_value = 0.0);
FloatParser(FloatParser&&) = default;
FloatParser& operator=(FloatParser&&) = default;
FloatParser(const FloatParser&) = delete;
FloatParser& operator=(const FloatParser&) = delete;
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed float. This must not be called until the parse had been
// successfully completed.
double value() const {
assert(num_bytes_remaining_ == 0);
return value_;
}
// Gets the parsed float. This must not be called until the parse had been
// successfully completed.
double* mutable_value() {
assert(num_bytes_remaining_ == 0);
return &value_;
}
private:
double value_;
double default_value_;
std::uint64_t uint64_value_;
int num_bytes_remaining_ = -1;
bool use_32_bits_;
};
} // namespace webm
#endif // SRC_FLOAT_PARSER_H_

View File

@@ -0,0 +1,49 @@
// 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.
#include "src/id_element_parser.h"
#include <cassert>
#include <cstdint>
#include "src/element_parser.h"
#include "src/parser_utils.h"
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
Status IdElementParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == 0 || metadata.size > 4) {
return Status(Status::kInvalidElementSize);
}
num_bytes_remaining_ = static_cast<int>(metadata.size);
value_ = static_cast<Id>(0);
return Status(Status::kOkCompleted);
}
Status IdElementParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
&value_, num_bytes_read);
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
return status;
}
} // namespace webm

View File

@@ -0,0 +1,56 @@
// 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_ID_ELEMENT_PARSER_H_
#define SRC_ID_ELEMENT_PARSER_H_
#include <cstdint>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
class IdElementParser : public ElementParser {
public:
IdElementParser() = default;
IdElementParser(IdElementParser&&) = default;
IdElementParser& operator=(IdElementParser&&) = default;
IdElementParser(const IdElementParser&) = delete;
IdElementParser& operator=(const IdElementParser&) = delete;
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed Id. This must not be called until the parse had been
// successfully completed.
Id value() const {
assert(num_bytes_remaining_ == 0);
return value_;
}
// Gets the parsed Id. This must not be called until the parse had been
// successfully completed.
Id* mutable_value() {
assert(num_bytes_remaining_ == 0);
return &value_;
}
private:
Id value_;
int num_bytes_remaining_ = -1;
};
} // namespace webm
#endif // SRC_ID_ELEMENT_PARSER_H_

View File

@@ -0,0 +1,75 @@
// 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.
#include "src/id_parser.h"
#include <cassert>
#include <cstdint>
#include "src/bit_utils.h"
#include "src/parser_utils.h"
#include "webm/id.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
Status IdParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
assert(num_bytes_remaining_ != 0);
*num_bytes_read = 0;
// Spec references:
// http://matroska.org/technical/specs/index.html#EBML_ex
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#variable-size-integer
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#element-id
// IDs are encoded like so (big-endian):
// 0b1xxx xxxx
// 0b01xx xxxx xxxx xxxx
// 0b001x xxxx xxxx xxxx xxxx xxxx
// 0b0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
if (num_bytes_remaining_ == -1) {
std::uint8_t first_byte;
const Status status = ReadByte(reader, &first_byte);
if (!status.completed_ok()) {
return status;
}
++*num_bytes_read;
// The marker bit is the first 1-bit. It indicates the length of the ID.
// If there is no marker bit in the first half-octet, this isn't a valid
// ID, since IDs can't be more than 4 octets in MKV/WebM.
if (!(first_byte & 0xf0)) {
return Status(Status::kInvalidElementId);
}
num_bytes_remaining_ = CountLeadingZeros(first_byte);
id_ = static_cast<Id>(first_byte);
}
std::uint64_t local_num_bytes_read;
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
&id_, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
num_bytes_remaining_ -= static_cast<int>(local_num_bytes_read);
return status;
}
Id IdParser::id() const {
assert(num_bytes_remaining_ == 0);
return id_;
}
} // namespace webm

View File

@@ -0,0 +1,45 @@
// 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_ID_PARSER_H_
#define SRC_ID_PARSER_H_
#include <cstdint>
#include "src/parser.h"
#include "webm/callback.h"
#include "webm/id.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses an EBML ID from a byte stream.
class IdParser : public Parser {
public:
IdParser() = default;
IdParser(IdParser&&) = default;
IdParser& operator=(IdParser&&) = default;
IdParser(const IdParser&) = delete;
IdParser& operator=(const IdParser&) = delete;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed ID. This must not be called until the parse had been
// successfully completed.
Id id() const;
private:
int num_bytes_remaining_ = -1;
Id id_;
};
} // namespace webm
#endif // SRC_ID_PARSER_H_

View File

@@ -0,0 +1,44 @@
// 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_INFO_PARSER_H_
#define SRC_INFO_PARSER_H_
#include "src/byte_parser.h"
#include "src/date_parser.h"
#include "src/float_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Info
// http://www.webmproject.org/docs/container/#Info
class InfoParser : public MasterValueParser<Info> {
public:
InfoParser()
: MasterValueParser<Info>(
MakeChild<UnsignedIntParser>(Id::kTimecodeScale,
&Info::timecode_scale),
MakeChild<FloatParser>(Id::kDuration, &Info::duration),
MakeChild<DateParser>(Id::kDateUtc, &Info::date_utc),
MakeChild<StringParser>(Id::kTitle, &Info::title),
MakeChild<StringParser>(Id::kMuxingApp, &Info::muxing_app),
MakeChild<StringParser>(Id::kWritingApp, &Info::writing_app)) {}
protected:
Status OnParseCompleted(Callback* callback) override {
return callback->OnInfo(metadata(Id::kInfo), value());
}
};
} // namespace webm
#endif // SRC_INFO_PARSER_H_

View File

@@ -0,0 +1,120 @@
// 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_INT_PARSER_H_
#define SRC_INT_PARSER_H_
#include <cassert>
#include <cstdint>
#include <limits>
#include <type_traits>
#include "src/element_parser.h"
#include "src/parser_utils.h"
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses an EBML signed/unsigned int from a byte stream.
// Spec reference:
// http://matroska.org/technical/specs/index.html#EBML_ex
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#element-data-size
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-element-types
template <typename T> class IntParser : public ElementParser {
public:
static_assert(
std::is_same<T, std::int64_t>::value ||
std::is_same<T, std::uint64_t>::value ||
(std::is_enum<T>::value && sizeof(T) == 8),
"T must be either std::int64_t, std::uint64_t, or a 64-bit enum");
// Constructs a new parser which will use the given default_value as the
// value for the element if its size is zero. Defaults to the value zero (as
// the EBML spec indicates).
explicit IntParser(T default_value = {}) : default_value_(default_value) {}
IntParser(IntParser&&) = default;
IntParser& operator=(IntParser&&) = default;
IntParser(const IntParser&) = delete;
IntParser& operator=(const IntParser&) = delete;
Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) override {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
// Matroska requires integers to be 0-8 bytes in size.
if (metadata.size > 8) {
return Status(Status::kInvalidElementSize);
}
size_ = num_bytes_remaining_ = static_cast<int>(metadata.size);
if (metadata.size == 0) {
value_ = default_value_;
} else {
value_ = {};
}
return Status(Status::kOkCompleted);
}
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
&value_, num_bytes_read);
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
// Sign extend the integer if it's a negative value. EBML allows for
// negative integers to drop superfluous sign bytes (i.e. -1 can be encoded
// as 0xFF instead of 0xFFFFFFFFFFFFFFFF).
if (std::is_signed<T>::value && num_bytes_remaining_ == 0 && size_ > 0) {
std::uint64_t sign_bits = std::numeric_limits<std::uint64_t>::max()
<< (8 * size_ - 1);
std::uint64_t unsigned_value = static_cast<std::uint64_t>(value_);
if (unsigned_value & sign_bits) {
value_ = static_cast<T>(unsigned_value | sign_bits);
}
}
return status;
}
// Gets the parsed int. This must not be called until the parse had been
// successfully completed.
T value() const {
assert(num_bytes_remaining_ == 0);
return value_;
}
// Gets the parsed int. This must not be called until the parse had been
// successfully completed.
T* mutable_value() {
assert(num_bytes_remaining_ == 0);
return &value_;
}
private:
T value_;
T default_value_;
int num_bytes_remaining_ = -1;
int size_;
};
using SignedIntParser = IntParser<std::int64_t>;
using UnsignedIntParser = IntParser<std::uint64_t>;
} // namespace webm
#endif // SRC_INT_PARSER_H_

View File

@@ -0,0 +1,133 @@
// 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.
#include "webm/istream_reader.h"
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <memory>
#include "webm/status.h"
namespace webm {
IstreamReader::IstreamReader(IstreamReader&& other)
: istream_(std::move(other.istream_)), position_(other.position_) {
other.position_ = 0;
}
IstreamReader& IstreamReader::operator=(IstreamReader&& other) {
if (this != &other) {
istream_ = std::move(other.istream_);
position_ = other.position_;
other.position_ = 0;
}
return *this;
}
Status IstreamReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
std::uint64_t* num_actually_read) {
assert(num_to_read > 0);
assert(buffer != nullptr);
assert(num_actually_read != nullptr);
if (istream_ == nullptr) {
*num_actually_read = 0;
return Status(Status::kEndOfFile);
}
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
constexpr std::streamsize streamsize_max =
std::numeric_limits<std::streamsize>::max();
std::streamsize limited_num_to_read;
if (num_to_read > static_cast<unsigned_streamsize>(streamsize_max)) {
limited_num_to_read = streamsize_max;
} else {
limited_num_to_read = static_cast<std::streamsize>(num_to_read);
}
istream_->read(reinterpret_cast<char*>(buffer), limited_num_to_read);
std::streamsize actual = istream_->gcount();
*num_actually_read = static_cast<std::uint64_t>(actual);
position_ += *num_actually_read;
if (actual == 0) {
return Status(Status::kEndOfFile);
}
if (actual == num_to_read) {
return Status(Status::kOkCompleted);
} else {
return Status(Status::kOkPartial);
}
}
Status IstreamReader::Skip(std::uint64_t num_to_skip,
std::uint64_t* num_actually_skipped) {
assert(num_to_skip > 0);
assert(num_actually_skipped != nullptr);
*num_actually_skipped = 0;
if (istream_ == nullptr || !istream_->good()) {
return Status(Status::kEndOfFile);
}
// Try seeking forward first.
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
constexpr std::streamsize streamsize_max =
std::numeric_limits<std::streamsize>::max();
std::streamsize seek_offset;
if (num_to_skip > static_cast<unsigned_streamsize>(streamsize_max)) {
seek_offset = streamsize_max;
} else {
seek_offset = static_cast<std::streamsize>(num_to_skip);
}
if (istream_->seekg(seek_offset, std::ios_base::cur)) {
*num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
position_ += static_cast<std::uint64_t>(seek_offset);
if (static_cast<std::uint64_t>(seek_offset) == num_to_skip) {
return Status(Status::kOkCompleted);
} else {
return Status(Status::kOkPartial);
}
}
istream_->clear();
// Seeking doesn't work on things like pipes, so if seeking failed then fall
// back to reading the data into a junk buffer.
std::size_t actual = 0;
do {
char junk[1024];
std::streamsize num_to_read = static_cast<std::streamsize>(sizeof(junk));
if (num_to_skip < static_cast<std::uint64_t>(num_to_read)) {
num_to_read = static_cast<std::streamsize>(num_to_skip);
}
istream_->read(junk, num_to_read);
std::streamsize actual = istream_->gcount();
*num_actually_skipped += static_cast<std::uint64_t>(actual);
position_ += static_cast<std::uint64_t>(actual);
num_to_skip -= static_cast<std::uint64_t>(actual);
} while (actual > 0 && num_to_skip > 0);
if (*num_actually_skipped == 0) {
return Status(Status::kEndOfFile);
}
if (num_to_skip == 0) {
return Status(Status::kOkCompleted);
} else {
return Status(Status::kOkPartial);
}
}
std::uint64_t IstreamReader::Position() const { return position_; }
} // namespace webm

View File

@@ -0,0 +1,298 @@
// 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.
#include "src/master_parser.h"
#include <cassert>
#include <cstdint>
#include <limits>
#include "src/element_parser.h"
#include "src/skip_callback.h"
#include "webm/element.h"
#include "webm/id.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#EBML_ex
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown
Status MasterParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
InitSetup(metadata.header_size, metadata.size, metadata.position);
if (metadata.size != kUnknownElementSize) {
max_size_ = metadata.size;
} else {
max_size_ = max_size;
}
if (metadata.size == 0) {
state_ = State::kEndReached;
} else {
state_ = State::kFirstReadOfChildId;
}
return Status(Status::kOkCompleted);
}
void MasterParser::InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) {
InitSetup(kUnknownHeaderSize, kUnknownElementSize, kUnknownElementPosition);
max_size_ = std::numeric_limits<std::uint64_t>::max();
if (child_ancestory.empty()) {
child_metadata_ = child_metadata;
auto iter = parsers_.find(child_metadata_.id);
assert(iter != parsers_.end());
child_parser_ = iter->second.get();
state_ = State::kGettingAction;
} else {
child_metadata_.id = child_ancestory.id();
child_metadata_.header_size = kUnknownHeaderSize;
child_metadata_.size = kUnknownElementSize;
child_metadata_.position = kUnknownElementPosition;
auto iter = parsers_.find(child_metadata_.id);
assert(iter != parsers_.end());
child_parser_ = iter->second.get();
child_parser_->InitAfterSeek(child_ancestory.next(), child_metadata);
state_ = State::kReadingChildBody;
}
}
Status MasterParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
*num_bytes_read = 0;
Callback* const original_callback = callback;
SkipCallback skip_callback;
if (action_ == Action::kSkip) {
callback = &skip_callback;
}
Status status;
std::uint64_t local_num_bytes_read;
while (true) {
switch (state_) {
case State::kFirstReadOfChildId: {
// This separate case for the first read of the child ID is needed to
// avoid potential bugs where calling Feed() twice in a row on an
// unsized element at the end of the stream would return
// Status::kOkCompleted instead of Status::kEndOfFile (since we convert
// Status::kEndOfFile to Status::kOkCompleted when EOF is hit for an
// unsized element after its children have been fully parsed). Once
// the ID parser consumes > 0 bytes, this state must be exited.
assert(child_parser_ == nullptr);
assert(my_size_ == kUnknownElementSize || total_bytes_read_ < my_size_);
child_metadata_.position = reader->Position();
child_metadata_.header_size = 0;
status = id_parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
total_bytes_read_ += local_num_bytes_read;
child_metadata_.header_size +=
static_cast<std::uint32_t>(local_num_bytes_read);
if (status.code == Status::kEndOfFile &&
my_size_ == kUnknownElementSize && local_num_bytes_read == 0) {
state_ = State::kEndReached;
} else if (!status.ok()) {
if (local_num_bytes_read > 0) {
state_ = State::kFinishingReadingChildId;
}
return status;
} else if (status.completed_ok()) {
state_ = State::kReadingChildSize;
} else {
state_ = State::kFinishingReadingChildId;
}
continue;
}
case State::kFinishingReadingChildId: {
assert(child_parser_ == nullptr);
assert(my_size_ == kUnknownElementSize || total_bytes_read_ < my_size_);
status = id_parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
total_bytes_read_ += local_num_bytes_read;
child_metadata_.header_size +=
static_cast<std::uint32_t>(local_num_bytes_read);
if (!status.completed_ok()) {
return status;
}
state_ = State::kReadingChildSize;
continue;
}
case State::kReadingChildSize: {
assert(child_parser_ == nullptr);
assert(total_bytes_read_ > 0);
status = size_parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
total_bytes_read_ += local_num_bytes_read;
child_metadata_.header_size +=
static_cast<std::uint32_t>(local_num_bytes_read);
if (!status.completed_ok()) {
return status;
}
child_metadata_.id = id_parser_.id();
child_metadata_.size = size_parser_.size();
state_ = State::kValidatingChildSize;
continue;
}
case State::kValidatingChildSize: {
assert(child_parser_ == nullptr);
std::uint64_t byte_count = total_bytes_read_;
if (child_metadata_.size != kUnknownElementSize) {
byte_count += child_metadata_.size;
}
std::uint64_t byte_cap = max_size_;
// my_size_ is <= max_size_ if it's known, so pick the smaller value.
if (my_size_ != kUnknownElementSize) {
byte_cap = my_size_;
}
if (byte_count > byte_cap) {
return Status(Status::kElementOverflow);
}
auto iter = parsers_.find(child_metadata_.id);
bool unknown_child = iter == parsers_.end();
if (my_size_ == kUnknownElementSize && unknown_child) {
// The end of an unsized master element is considered to be the first
// instance of an element that isn't a known/valid child element.
has_cached_metadata_ = true;
state_ = State::kEndReached;
continue;
} else if (unknown_child &&
child_metadata_.size == kUnknownElementSize) {
// We can't skip or otherwise handle unknown elements with an unknown
// size.
return Status(Status::kIndefiniteUnknownElement);
}
if (unknown_child) {
child_parser_ = &unknown_parser_;
} else {
child_parser_ = iter->second.get();
}
state_ = State::kGettingAction;
continue;
}
case State::kGettingAction: {
assert(child_parser_ != nullptr);
status = callback->OnElementBegin(child_metadata_, &action_);
if (!status.completed_ok()) {
return status;
}
if (action_ == Action::kSkip) {
callback = &skip_callback;
if (child_metadata_.size != kUnknownElementSize) {
child_parser_ = &skip_parser_;
}
}
state_ = State::kInitializingChildParser;
continue;
}
case State::kInitializingChildParser: {
assert(child_parser_ != nullptr);
status =
child_parser_->Init(child_metadata_, max_size_ - total_bytes_read_);
if (!status.completed_ok()) {
return status;
}
state_ = State::kReadingChildBody;
continue;
}
case State::kReadingChildBody: {
assert(child_parser_ != nullptr);
status = child_parser_->Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
total_bytes_read_ += local_num_bytes_read;
if (!status.completed_ok()) {
return status;
}
state_ = State::kChildFullyParsed;
continue;
}
case State::kChildFullyParsed: {
assert(child_parser_ != nullptr);
std::uint64_t byte_cap = max_size_;
// my_size_ is <= max_size_ if it's known, so pick the smaller value.
if (my_size_ != kUnknownElementSize) {
byte_cap = my_size_;
}
if (total_bytes_read_ > byte_cap) {
return Status(Status::kElementOverflow);
} else if (total_bytes_read_ == byte_cap) {
state_ = State::kEndReached;
continue;
}
if (child_parser_->GetCachedMetadata(&child_metadata_)) {
state_ = State::kValidatingChildSize;
} else {
state_ = State::kFirstReadOfChildId;
}
PrepareForNextChild();
callback = original_callback;
continue;
}
case State::kEndReached: {
return Status(Status::kOkCompleted);
}
}
}
}
bool MasterParser::GetCachedMetadata(ElementMetadata* metadata) {
assert(metadata != nullptr);
if (has_cached_metadata_) {
*metadata = child_metadata_;
}
return has_cached_metadata_;
}
void MasterParser::InitSetup(std::uint32_t header_size,
std::uint64_t size_in_bytes,
std::uint64_t position) {
PrepareForNextChild();
header_size_ = header_size;
my_size_ = size_in_bytes;
my_position_ = position;
total_bytes_read_ = 0;
has_cached_metadata_ = false;
}
void MasterParser::PrepareForNextChild() {
// Do not reset child_metadata_ here.
id_parser_ = {};
size_parser_ = {};
child_parser_ = nullptr;
action_ = Action::kRead;
}
} // namespace webm

View File

@@ -0,0 +1,223 @@
// 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_PARSER_H_
#define SRC_MASTER_PARSER_H_
#include <cassert>
#include <cstdint>
#include <functional>
#include <memory>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include "src/element_parser.h"
#include "src/id_parser.h"
#include "src/size_parser.h"
#include "src/skip_parser.h"
#include "src/unknown_parser.h"
#include "src/void_parser.h"
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/id.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// A general purpose parser for EBML master elements.
//
// For example, if a document specification defines a Foo master element that
// has two boolean children (Bar and Baz), then a FooParser capable of parsing
// the Foo master element could be defined as follows:
//
// struct FooParser : public MasterParser {
// FooParser()
// : MasterParser(MakeChild<BoolParser>(Id::kBar),
// MakeChild<BoolParser>(Id::kBaz)) {}
// };
//
// See the MasterValueParser for an alternative class for parsing master
// elements into a data structure.
class MasterParser : public ElementParser {
public:
// Constructs a new MasterParser that uses the given
// {Id, std::unique_ptr<ElementParser>} pairs to map child IDs to the
// appropriate parser/handler. Each argument must be of type
// std::pair<Id, std::unique_ptr<ElementParser>>. If a parser is not
// explicitly provided for Id::kVoid, a VoidParser will automatically be used
// for it.
//
// Initializer lists don't support move-only types (i.e. std::unique_ptr), so
// instead a variadic template is used.
template <typename... T> explicit MasterParser(T&&... parser_pairs) {
// Prefer an odd reserve size. This makes libc++ use a prime number for the
// bucket count. Otherwise, if it happens to be a power of 2, then libc++
// will use a power-of-2 bucket count (and since Matroska EBML IDs have low
// entropy in the low bits, there will be a lot of collisions). libstdc++
// always prefers a prime bucket count. I'm not sure how MSVC or others are
// implemented, but this shouldn't adversely affect them even if they are
// implemented differently. Add one to the count because we'll likely need
// to insert a parser for Id::kVoid.
parsers_.reserve((sizeof...(T) + 1) | 1);
// This dummy initializer list is just used to force the parameter pack to
// be expanded, which turns the expression into a for-each "loop" that
// inserts each argument into the map.
auto dummy = {0, (InsertParser(std::forward<T>(parser_pairs)), 0)...};
(void)dummy; // Silence unused variable warning.
if (parsers_.find(Id::kVoid) == parsers_.end()) {
InsertParser(MakeChild<VoidParser>(Id::kVoid));
}
}
MasterParser(const MasterParser&) = delete;
MasterParser& operator=(const MasterParser&) = delete;
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
void InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
bool GetCachedMetadata(ElementMetadata* metadata) override;
std::uint32_t header_size() const { return header_size_; }
// Gets the size of this element. May be called before the parse is fully
// complete (but only after Init() has already been called and successfully
// returned).
std::uint64_t size() const { return my_size_; }
// Gets absolute byte position of the start of the element in the byte stream.
// May be called before the parse is fully complete (but only after Init() has
// already been called and successfully returned).
std::uint64_t position() const { return my_position_; }
// Gets the metadata for the child that is currently being parsed. This may
// only be called while the child's body (not its header information like ID
// and size) is being parsed.
const ElementMetadata& child_metadata() const {
assert(state_ == State::kValidatingChildSize ||
state_ == State::kGettingAction ||
state_ == State::kInitializingChildParser ||
state_ == State::kReadingChildBody);
return child_metadata_;
}
protected:
// Allocates a new parser of type T, forwarding args to the constructor, and
// creates a std::pair<Id, std::unique_ptr<ElementParser>> using the given id
// and the allocated parser.
template <typename T, typename... Args>
static std::pair<Id, std::unique_ptr<ElementParser>> MakeChild(
Id id, Args&&... args) {
std::unique_ptr<ElementParser> ptr(new T(std::forward<Args>(args)...));
return std::pair<Id, std::unique_ptr<ElementParser>>(id, std::move(ptr));
}
private:
// Parsing states for the finite-state machine.
enum class State {
// State Transitions to state When
kFirstReadOfChildId, // kFinishingReadingChildId size(id) > 1
// kReadingChildSize size(id) == 1
// kEndReached EOF
kFinishingReadingChildId, // kReadingChildSize done
kReadingChildSize, // kValidatingChildSize done
kValidatingChildSize, // kGettingAction done
// kEndReached unknown id & unsized
kGettingAction, // kInitializingChildParser done
kInitializingChildParser, // kReadingChildBody done
kReadingChildBody, // kChildFullyParsed child parse done
kChildFullyParsed, // kValidatingChildSize cached metadata
// kFirstReadOfChildId read < my_size_
// kEndReached read == my_size_
kEndReached, // No transitions from here (must call Init)
};
using StdHashId = std::hash<std::underlying_type<Id>::type>;
// Hash functor for hashing Id enums for storage in std::unordered_map.
struct IdHash : StdHashId {
// Type aliases for conforming to the std::hash interface.
using argument_type = Id;
using result_type = StdHashId::result_type;
// Returns the hash of the given id.
result_type operator()(argument_type id) const {
return StdHashId::operator()(static_cast<StdHashId::argument_type>(id));
}
};
// The parser for parsing element Ids.
IdParser id_parser_;
// The parser for parsing element sizes.
SizeParser size_parser_;
// Metadata for the child element that is currently being parsed.
ElementMetadata child_metadata_;
// Maps child IDs to the appropriate parser that can handle that child.
std::unordered_map<Id, std::unique_ptr<ElementParser>, IdHash> parsers_;
// The parser that is used to parse unknown children.
UnknownParser unknown_parser_;
// The parser that is used to skip over children.
SkipParser skip_parser_;
// The parser that is being used to parse the current child. This must be null
// or a pointer in parsers_.
ElementParser* child_parser_;
// The current parsing action for the child that is currently being parsed.
Action action_;
// The current state of the parser.
State state_;
std::uint32_t header_size_;
// The size of this element.
std::uint64_t my_size_;
std::uint64_t my_position_;
std::uint64_t max_size_;
// The total number of bytes read by this parser.
std::uint64_t total_bytes_read_;
// Set to true if parsing has completed and this parser consumed an extra
// element header (ID and size) that wasn't from a child.
bool has_cached_metadata_ = false;
// Inserts the parser into the parsers_ map and asserts it is the only parser
// registers to parse the corresponding Id.
template <typename T> void InsertParser(T&& parser) {
bool inserted = parsers_.insert(std::forward<T>(parser)).second;
(void)inserted; // Silence unused variable warning.
assert(inserted); // Make sure there aren't duplicates.
}
// Common initialization logic for Init/InitAfterseek.
void InitSetup(std::uint32_t header_size, std::uint64_t size_in_bytes,
std::uint64_t position);
// Resets the internal parsers in preparation for parsing the next child.
void PrepareForNextChild();
};
} // namespace webm
#endif // SRC_MASTER_PARSER_H_

View File

@@ -0,0 +1,465 @@
// 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/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_;
};
// 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");
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");
return RepeatedChildFactory<Parser, Value>(id, member);
}
// 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_;
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 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_

View File

@@ -0,0 +1,57 @@
// 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_MASTERING_METADATA_PARSER_H_
#define SRC_MASTERING_METADATA_PARSER_H_
#include "src/float_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#MasteringMetadata
// http://www.webmproject.org/docs/container/#MasteringMetadata
class MasteringMetadataParser : public MasterValueParser<MasteringMetadata> {
public:
MasteringMetadataParser()
: MasterValueParser<MasteringMetadata>(
MakeChild<FloatParser>(
Id::kPrimaryRChromaticityX,
&MasteringMetadata::primary_r_chromaticity_x),
MakeChild<FloatParser>(
Id::kPrimaryRChromaticityY,
&MasteringMetadata::primary_r_chromaticity_y),
MakeChild<FloatParser>(
Id::kPrimaryGChromaticityX,
&MasteringMetadata::primary_g_chromaticity_x),
MakeChild<FloatParser>(
Id::kPrimaryGChromaticityY,
&MasteringMetadata::primary_g_chromaticity_y),
MakeChild<FloatParser>(
Id::kPrimaryBChromaticityX,
&MasteringMetadata::primary_b_chromaticity_x),
MakeChild<FloatParser>(
Id::kPrimaryBChromaticityY,
&MasteringMetadata::primary_b_chromaticity_y),
MakeChild<FloatParser>(
Id::kWhitePointChromaticityX,
&MasteringMetadata::white_point_chromaticity_x),
MakeChild<FloatParser>(
Id::kWhitePointChromaticityY,
&MasteringMetadata::white_point_chromaticity_y),
MakeChild<FloatParser>(Id::kLuminanceMax,
&MasteringMetadata::luminance_max),
MakeChild<FloatParser>(Id::kLuminanceMin,
&MasteringMetadata::luminance_min)) {}
};
} // namespace webm
#endif // SRC_MASTERING_METADATA_PARSER_H_

34
webm_parser/src/parser.h Normal file
View File

@@ -0,0 +1,34 @@
// 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_PARSER_H_
#define SRC_PARSER_H_
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
class Parser {
public:
virtual ~Parser() = default;
// Feeds data into the parser, with the number of bytes read from the reader
// returned in num_bytes_read. Returns Status::kOkCompleted when parsing is
// complete, or an appropriate error code if the data is malformed and cannot
// be parsed. Otherwise, the status of Reader::Read is returned if only a
// partial parse could be done because the reader couldn't immediately provide
// all the needed data. reader and num_bytes_read must not be null. Do not
// call again once the parse is complete.
virtual Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) = 0;
};
} // namespace webm
#endif // SRC_PARSER_H_

View File

@@ -0,0 +1,34 @@
// 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.
#include "src/parser_utils.h"
#include <cassert>
#include <cstdint>
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
Status ReadByte(Reader* reader, std::uint8_t* byte) {
assert(reader != nullptr);
assert(byte != nullptr);
std::uint64_t num_bytes_read;
const Status status = reader->Read(1, byte, &num_bytes_read);
if (!status.completed_ok()) {
assert(num_bytes_read == 0);
} else {
assert(num_bytes_read == 1);
}
return status;
}
} // namespace webm

View File

@@ -0,0 +1,64 @@
// 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_PARSER_UTILS_H_
#define SRC_PARSER_UTILS_H_
#include <cassert>
#include <cstdint>
#include <type_traits>
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Reads a single byte from the reader, and returns the status of the read. If
// the status is not Status::kOkCompleted, then no data was read.
Status ReadByte(Reader* reader, std::uint8_t* byte);
// Accumulates bytes from the reader into the integer. The integer will be
// extracted as a big-endian integer and stored with the native
// host-endianness. num_bytes_remaining is the number of bytes to
template <typename T>
Status AccumulateIntegerBytes(int num_to_read, Reader* reader, T* integer,
std::uint64_t* num_actually_read) {
static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
"T must be an integer or enum type");
// Use unsigned integers for bitwise arithmetic because it's well-defined (as
// opposed to signed integers, where left shifting a negative integer is
// undefined, for example).
using UnsignedT = typename std::make_unsigned<T>::type;
assert(reader != nullptr);
assert(integer != nullptr);
assert(num_actually_read != nullptr);
assert(num_to_read >= 0);
assert(num_to_read <= sizeof(T));
*num_actually_read = 0;
if (num_to_read < 0 || num_to_read > sizeof(T)) {
return Status(Status::kInvalidElementSize);
}
for (; num_to_read > 0; --num_to_read) {
std::uint8_t byte;
const Status status = ReadByte(reader, &byte);
if (!status.completed_ok()) {
return status;
}
++*num_actually_read;
*integer = static_cast<T>((static_cast<UnsignedT>(*integer) << 8) | byte);
}
return Status(Status::kOkCompleted);
}
} // namespace webm
#endif // SRC_PARSER_UTILS_H_

View File

@@ -0,0 +1,85 @@
// 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_RECURSIVE_PARSER_H_
#define SRC_RECURSIVE_PARSER_H_
#include <cassert>
#include <cstdint>
#include <memory>
#include <utility>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Lazily instantiates a parser of type T, and uses that parser to handle all
// parsing operations. The parser is allocated when Init is called. This class
// is intended to be used with recursive elements, where a parser needs to
// recursively instantiate parsers of the same type.
template <typename T> class RecursiveParser : public ElementParser {
public:
RecursiveParser() = default;
RecursiveParser(RecursiveParser&&) = default;
RecursiveParser& operator=(RecursiveParser&&) = default;
RecursiveParser(const RecursiveParser&) = delete;
RecursiveParser& operator=(const RecursiveParser&) = delete;
Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) override {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (!impl_) {
impl_.reset(new T);
}
return impl_->Init(metadata, max_size);
}
void InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) override {
if (!impl_) {
impl_.reset(new T);
}
impl_->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);
assert(impl_ != nullptr);
return impl_->Feed(callback, reader, num_bytes_read);
}
decltype(std::declval<T>().value()) value() const {
assert(impl_ != nullptr);
return impl_->value();
}
decltype(std::declval<T>().mutable_value()) mutable_value() {
assert(impl_ != nullptr);
return impl_->mutable_value();
}
private:
std::unique_ptr<T> impl_;
};
} // namespace webm
#endif // SRC_RECURSIVE_PARSER_H_

View File

@@ -0,0 +1,27 @@
// 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_SEEK_HEAD_PARSER_H_
#define SRC_SEEK_HEAD_PARSER_H_
#include "src/master_parser.h"
#include "src/seek_parser.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#SeekHead
// http://www.webmproject.org/docs/container/#SeekHead
class SeekHeadParser : public MasterParser {
public:
SeekHeadParser() : MasterParser(MakeChild<SeekParser>(Id::kSeek)) {}
};
} // namespace webm
#endif // SRC_SEEK_HEAD_PARSER_H_

View File

@@ -0,0 +1,37 @@
// 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_SEEK_PARSER_H_
#define SRC_SEEK_PARSER_H_
#include "src/id_element_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Seek
// http://www.webmproject.org/docs/container/#Seek
class SeekParser : public MasterValueParser<Seek> {
public:
SeekParser()
: MasterValueParser<Seek>(
MakeChild<IdElementParser>(Id::kSeekId, &Seek::id),
MakeChild<UnsignedIntParser>(Id::kSeekPosition, &Seek::position)) {}
protected:
Status OnParseCompleted(Callback* callback) override {
return callback->OnSeek(metadata(Id::kSeek), value());
}
};
} // namespace webm
#endif // SRC_SEEK_PARSER_H_

View File

@@ -0,0 +1,86 @@
// 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.
#include "src/segment_parser.h"
#include "src/chapters_parser.h"
#include "src/cluster_parser.h"
#include "src/cues_parser.h"
#include "src/info_parser.h"
#include "src/seek_head_parser.h"
#include "src/skip_callback.h"
#include "src/tags_parser.h"
#include "src/tracks_parser.h"
#include "webm/id.h"
namespace webm {
SegmentParser::SegmentParser()
: MasterParser(MakeChild<ChaptersParser>(Id::kChapters),
MakeChild<ClusterParser>(Id::kCluster),
MakeChild<CuesParser>(Id::kCues),
MakeChild<InfoParser>(Id::kInfo),
MakeChild<SeekHeadParser>(Id::kSeekHead),
MakeChild<TagsParser>(Id::kTags),
MakeChild<TracksParser>(Id::kTracks)) {}
Status SegmentParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
begin_done_ = false;
parse_completed_ = false;
return MasterParser::Init(metadata, max_size);
}
void SegmentParser::InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) {
MasterParser::InitAfterSeek(child_ancestory, child_metadata);
begin_done_ = true;
parse_completed_ = false;
action_ = Action::kRead;
}
Status SegmentParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
*num_bytes_read = 0;
if (!begin_done_) {
const ElementMetadata metadata{Id::kSegment, header_size(), size(),
position()};
const Status status = callback->OnSegmentBegin(metadata, &action_);
if (!status.completed_ok()) {
return status;
}
begin_done_ = true;
}
SkipCallback skip_callback;
if (action_ == Action::kSkip) {
callback = &skip_callback;
}
if (!parse_completed_) {
const Status status = MasterParser::Feed(callback, reader, num_bytes_read);
if (!status.completed_ok()) {
return status;
}
parse_completed_ = true;
}
return callback->OnSegmentEnd(
{Id::kSegment, header_size(), size(), position()});
}
bool SegmentParser::WasSkipped() const { return action_ == Action::kSkip; }
} // namespace webm

View File

@@ -0,0 +1,53 @@
// 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_SEGMENT_PARSER_H_
#define SRC_SEGMENT_PARSER_H_
#include <cstdint>
#include "src/master_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses Segment elements from a WebM byte stream. This class adheres to the
// ElementParser interface; see element_parser.h for further documentation on
// how it should be used.
// Spec reference:
// http://matroska.org/technical/specs/index.html#Segment
// http://www.webmproject.org/docs/container/#Segment
class SegmentParser : public MasterParser {
public:
SegmentParser();
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
void InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
bool WasSkipped() const override;
private:
// Set to true iff Callback::OnSegmentBegin has completed.
bool begin_done_;
// Set to true iff the base class has completed parsing.
bool parse_completed_;
// The action requested by Callback::OnSegmentBegin.
Action action_;
};
} // namespace webm
#endif // SRC_SEGMENT_PARSER_H_

View File

@@ -0,0 +1,38 @@
// 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_SIMPLE_TAG_PARSER_H_
#define SRC_SIMPLE_TAG_PARSER_H_
#include "src/bool_parser.h"
#include "src/byte_parser.h"
#include "src/master_value_parser.h"
#include "src/recursive_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#SimpleTag
// http://www.webmproject.org/docs/container/#SimpleTag
class SimpleTagParser : public MasterValueParser<SimpleTag> {
public:
SimpleTagParser()
: MasterValueParser<SimpleTag>(
MakeChild<StringParser>(Id::kTagName, &SimpleTag::name),
MakeChild<StringParser>(Id::kTagLanguage, &SimpleTag::language),
MakeChild<BoolParser>(Id::kTagDefault, &SimpleTag::is_default),
MakeChild<StringParser>(Id::kTagString, &SimpleTag::string),
MakeChild<BinaryParser>(Id::kTagBinary, &SimpleTag::binary),
MakeChild<RecursiveParser<SimpleTagParser>>(Id::kSimpleTag,
&SimpleTag::tags)) {}
};
} // namespace webm
#endif // SRC_SIMPLE_TAG_PARSER_H_

View File

@@ -0,0 +1,56 @@
// 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.
#include "src/size_parser.h"
#include <cassert>
#include <cstdint>
#include <limits>
#include "src/bit_utils.h"
#include "src/parser_utils.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Spec references:
// http://matroska.org/technical/specs/index.html#EBML_ex
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#element-data-size
Status SizeParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
// Within the EBML header, the size can be encoded with 1-4 octets. After
// the EBML header, the size can be encoded with 1-8 octets (though not more
// than EBMLMaxSizeLength).
Status status = uint_parser_.Feed(callback, reader, num_bytes_read);
if (status.code == Status::kInvalidElementValue) {
status.code = Status::kInvalidElementSize;
}
return status;
}
std::uint64_t SizeParser::size() const {
// If all data bits are set, then it represents an unknown element size.
const std::uint64_t data_bits =
std::numeric_limits<std::uint64_t>::max() >>
(57 - 7 * (uint_parser_.encoded_length() - 1));
if (uint_parser_.value() == data_bits) {
return kUnknownElementSize;
}
return uint_parser_.value();
}
} // namespace webm

View File

@@ -0,0 +1,43 @@
// 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_SIZE_PARSER_H_
#define SRC_SIZE_PARSER_H_
#include <cstdint>
#include "src/parser.h"
#include "src/var_int_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
class SizeParser : public Parser {
public:
SizeParser() = default;
SizeParser(SizeParser&&) = default;
SizeParser& operator=(SizeParser&&) = default;
SizeParser(const SizeParser&) = delete;
SizeParser& operator=(const SizeParser&) = delete;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed size. This must not be called until the parse had been
// successfully completed.
std::uint64_t size() const;
private:
VarIntParser uint_parser_;
};
} // namespace webm
#endif // SRC_SIZE_PARSER_H_

View File

@@ -0,0 +1,63 @@
// 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_SKIP_CALLBACK_H_
#define SRC_SKIP_CALLBACK_H_
#include "webm/callback.h"
#include "webm/dom_types.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// An implementation of Callback that skips all elements. Every method that
// yields an action will yield Action::kSkip, and Reader::Skip will be called
// if the callback ever needs to process data from the byte stream.
class SkipCallback : public Callback {
public:
Status OnElementBegin(const ElementMetadata& metadata,
Action* action) override {
*action = Action::kSkip;
return Status(Status::kOkCompleted);
}
Status OnSegmentBegin(const ElementMetadata& metadata,
Action* action) override {
*action = Action::kSkip;
return Status(Status::kOkCompleted);
}
Status OnClusterBegin(const ElementMetadata& metadata, const Cluster& cluster,
Action* action) override {
*action = Action::kSkip;
return Status(Status::kOkCompleted);
}
Status OnSimpleBlockBegin(const ElementMetadata& metadata,
const SimpleBlock& simple_block,
Action* action) override {
*action = Action::kSkip;
return Status(Status::kOkCompleted);
}
Status OnBlockGroupBegin(const ElementMetadata& metadata,
Action* action) override {
*action = Action::kSkip;
return Status(Status::kOkCompleted);
}
Status OnBlockBegin(const ElementMetadata& metadata, const Block& block,
Action* action) override {
*action = Action::kSkip;
return Status(Status::kOkCompleted);
}
};
} // namespace webm
#endif // SRC_SKIP_CALLBACK_H_

View File

@@ -0,0 +1,59 @@
// 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.
#include "src/skip_parser.h"
#include <cassert>
#include <cstdint>
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
Status SkipParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == kUnknownElementSize) {
return Status(Status::kInvalidElementSize);
}
num_bytes_remaining_ = metadata.size;
return Status(Status::kOkCompleted);
}
Status SkipParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
*num_bytes_read = 0;
if (num_bytes_remaining_ == 0) {
return Status(Status::kOkCompleted);
}
Status status;
do {
std::uint64_t local_num_bytes_read = 0;
status = reader->Skip(num_bytes_remaining_, &local_num_bytes_read);
assert((status.completed_ok() &&
local_num_bytes_read == num_bytes_remaining_) ||
(status.ok() && local_num_bytes_read < num_bytes_remaining_) ||
(!status.ok() && local_num_bytes_read == 0));
*num_bytes_read += local_num_bytes_read;
num_bytes_remaining_ -= local_num_bytes_read;
} while (status.code == Status::kOkPartial);
return status;
}
} // namespace webm

View File

@@ -0,0 +1,35 @@
// 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_SKIP_PARSER_H_
#define SRC_SKIP_PARSER_H_
#include <cstdint>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// A simple parser that merely skips (via Reader::Skip) ahead in the stream
// until the element has been fully skipped.
class SkipParser : public ElementParser {
public:
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
private:
std::uint64_t num_bytes_remaining_;
};
} // namespace webm
#endif // SRC_SKIP_PARSER_H_

View File

@@ -0,0 +1,30 @@
// 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_SLICES_PARSER_H_
#define SRC_SLICES_PARSER_H_
#include "src/master_value_parser.h"
#include "src/time_slice_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Slices
// http://www.webmproject.org/docs/container/#Slices
class SlicesParser : public MasterValueParser<Slices> {
public:
SlicesParser()
: MasterValueParser<Slices>(
MakeChild<TimeSliceParser>(Id::kTimeSlice, &Slices::slices)) {}
};
} // namespace webm
#endif // SRC_SLICES_PARSER_H_

View File

@@ -0,0 +1,37 @@
// 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_TAG_PARSER_H_
#define SRC_TAG_PARSER_H_
#include "src/master_value_parser.h"
#include "src/simple_tag_parser.h"
#include "src/targets_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Tag
// http://www.webmproject.org/docs/container/#Tag
class TagParser : public MasterValueParser<Tag> {
public:
TagParser()
: MasterValueParser<Tag>(
MakeChild<TargetsParser>(Id::kTargets, &Tag::targets),
MakeChild<SimpleTagParser>(Id::kSimpleTag, &Tag::tags)) {}
protected:
Status OnParseCompleted(Callback* callback) override {
return callback->OnTag(metadata(Id::kTag), value());
}
};
} // namespace webm
#endif // SRC_TAG_PARSER_H_

View File

@@ -0,0 +1,27 @@
// 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_TAGS_PARSER_H_
#define SRC_TAGS_PARSER_H_
#include "src/master_parser.h"
#include "src/tag_parser.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Tags
// http://www.webmproject.org/docs/container/#Tags
class TagsParser : public MasterParser {
public:
TagsParser() : MasterParser(MakeChild<TagParser>(Id::kTag)) {}
};
} // namespace webm
#endif // SRC_TAGS_PARSER_H_

View File

@@ -0,0 +1,35 @@
// 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_TARGETS_PARSER_H_
#define SRC_TARGETS_PARSER_H_
#include "src/byte_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Targets
// http://www.webmproject.org/docs/container/#Targets
class TargetsParser : public MasterValueParser<Targets> {
public:
TargetsParser()
: MasterValueParser<Targets>(
MakeChild<UnsignedIntParser>(Id::kTargetTypeValue,
&Targets::type_value),
MakeChild<StringParser>(Id::kTargetType, &Targets::type),
MakeChild<UnsignedIntParser>(Id::kTagTrackUid,
&Targets::track_uids)) {}
};
} // namespace webm
#endif // SRC_TARGETS_PARSER_H_

View File

@@ -0,0 +1,30 @@
// 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_TIME_SLICE_PARSER_H_
#define SRC_TIME_SLICE_PARSER_H_
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#TimeSlice
// http://www.webmproject.org/docs/container/#TimeSlice
class TimeSliceParser : public MasterValueParser<TimeSlice> {
public:
TimeSliceParser()
: MasterValueParser<TimeSlice>(MakeChild<UnsignedIntParser>(
Id::kLaceNumber, &TimeSlice::lace_number)) {}
};
} // namespace webm
#endif // SRC_TIME_SLICE_PARSER_H_

View File

@@ -0,0 +1,65 @@
// 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_TRACK_ENTRY_PARSER_H_
#define SRC_TRACK_ENTRY_PARSER_H_
#include "src/audio_parser.h"
#include "src/bool_parser.h"
#include "src/byte_parser.h"
#include "src/content_encodings_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "src/video_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#TrackEntry
// http://www.webmproject.org/docs/container/#TrackEntry
class TrackEntryParser : public MasterValueParser<TrackEntry> {
public:
TrackEntryParser()
: MasterValueParser<TrackEntry>(
MakeChild<UnsignedIntParser>(Id::kTrackNumber,
&TrackEntry::track_number),
MakeChild<UnsignedIntParser>(Id::kTrackUid, &TrackEntry::track_uid),
MakeChild<IntParser<TrackType>>(Id::kTrackType,
&TrackEntry::track_type),
MakeChild<BoolParser>(Id::kFlagEnabled, &TrackEntry::is_enabled),
MakeChild<BoolParser>(Id::kFlagDefault, &TrackEntry::is_default),
MakeChild<BoolParser>(Id::kFlagForced, &TrackEntry::is_forced),
MakeChild<BoolParser>(Id::kFlagLacing, &TrackEntry::uses_lacing),
MakeChild<UnsignedIntParser>(Id::kDefaultDuration,
&TrackEntry::default_duration),
MakeChild<StringParser>(Id::kName, &TrackEntry::name),
MakeChild<StringParser>(Id::kLanguage, &TrackEntry::language),
MakeChild<StringParser>(Id::kCodecId, &TrackEntry::codec_id),
MakeChild<BinaryParser>(Id::kCodecPrivate,
&TrackEntry::codec_private),
MakeChild<StringParser>(Id::kCodecName, &TrackEntry::codec_name),
MakeChild<UnsignedIntParser>(Id::kCodecDelay,
&TrackEntry::codec_delay),
MakeChild<UnsignedIntParser>(Id::kSeekPreRoll,
&TrackEntry::seek_pre_roll),
MakeChild<VideoParser>(Id::kVideo, &TrackEntry::video),
MakeChild<AudioParser>(Id::kAudio, &TrackEntry::audio),
MakeChild<ContentEncodingsParser>(
Id::kContentEncodings, &TrackEntry::content_encodings)) {}
protected:
Status OnParseCompleted(Callback* callback) override {
return callback->OnTrackEntry(metadata(Id::kTrackEntry), value());
}
};
} // namespace webm
#endif // SRC_TRACK_ENTRY_PARSER_H_

View File

@@ -0,0 +1,27 @@
// 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_TRACKS_PARSER_H_
#define SRC_TRACKS_PARSER_H_
#include "src/master_parser.h"
#include "src/track_entry_parser.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Tracks
// http://www.webmproject.org/docs/container/#Tracks
class TracksParser : public MasterParser {
public:
TracksParser() : MasterParser(MakeChild<TrackEntryParser>(Id::kTrackEntry)) {}
};
} // namespace webm
#endif // SRC_TRACKS_PARSER_H_

View File

@@ -0,0 +1,49 @@
// 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.
#include "src/unknown_parser.h"
#include <cassert>
#include <cstdint>
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
Status UnknownParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == kUnknownElementSize) {
return Status(Status::kIndefiniteUnknownElement);
}
metadata_ = metadata;
bytes_remaining_ = metadata.size;
return Status(Status::kOkCompleted);
}
Status UnknownParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
const std::uint64_t original_bytes_remaining = bytes_remaining_;
const Status status =
callback->OnUnknownElement(metadata_, reader, &bytes_remaining_);
assert(bytes_remaining_ <= original_bytes_remaining);
*num_bytes_read = original_bytes_remaining - bytes_remaining_;
return status;
}
} // namespace webm

View File

@@ -0,0 +1,38 @@
// 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_UNKNOWN_PARSER_H_
#define SRC_UNKNOWN_PARSER_H_
#include <cstdint>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses unknown elements by delegating to Callback::OnUnknownElement.
class UnknownParser : public ElementParser {
public:
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
private:
// The metadata for this element.
ElementMetadata metadata_;
// The number of bytes remaining that have not been read in the element.
std::uint64_t bytes_remaining_;
};
} // namespace webm
#endif // SRC_UNKNOWN_PARSER_H_

View File

@@ -0,0 +1,71 @@
// 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.
#include "src/var_int_parser.h"
#include <cassert>
#include <cstdint>
#include <limits>
#include "src/bit_utils.h"
#include "src/parser_utils.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Spec references:
// http://matroska.org/technical/specs/index.html#EBML_ex
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#variable-size-integer
Status VarIntParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
assert(num_bytes_remaining_ != 0);
*num_bytes_read = 0;
if (num_bytes_remaining_ == -1) {
std::uint8_t first_byte;
const Status status = ReadByte(reader, &first_byte);
if (!status.completed_ok()) {
return status;
}
++*num_bytes_read;
// The first byte must have a marker bit set to indicate how many octets are
// used.
if (first_byte == 0) {
return Status(Status::kInvalidElementValue);
}
total_data_bytes_ = CountLeadingZeros(first_byte);
num_bytes_remaining_ = total_data_bytes_;
value_ = first_byte;
}
std::uint64_t local_num_bytes_read;
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
&value_, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
num_bytes_remaining_ -= static_cast<int>(local_num_bytes_read);
if (!status.completed_ok()) {
return status;
}
// Clear the marker bit.
constexpr std::uint64_t all_bits = std::numeric_limits<std::uint64_t>::max();
const std::uint64_t data_bits = all_bits >> (57 - 7 * total_data_bytes_);
value_ &= data_bits;
return Status(Status::kOkCompleted);
}
} // namespace webm

View File

@@ -0,0 +1,56 @@
// 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_VAR_INT_PARSER_H_
#define SRC_VAR_INT_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
class VarIntParser : public Parser {
public:
VarIntParser() = default;
VarIntParser(VarIntParser&&) = default;
VarIntParser& operator=(VarIntParser&&) = default;
VarIntParser(const VarIntParser&) = delete;
VarIntParser& operator=(const VarIntParser&) = delete;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed value. This must not be called until the parse had been
// successfully completed.
std::uint64_t value() const {
assert(num_bytes_remaining_ == 0);
return value_;
}
// Gets the number of bytes which were used to encode the integer value in the
// byte stream. This must not be called until the parse had been successfully
// completed.
int encoded_length() const {
assert(num_bytes_remaining_ == 0);
return total_data_bytes_ + 1;
}
private:
int num_bytes_remaining_ = -1;
int total_data_bytes_;
std::uint64_t value_;
};
} // namespace webm
#endif // SRC_VAR_INT_PARSER_H_

View File

@@ -0,0 +1,120 @@
// 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_VIDEO_PARSER_H_
#define SRC_VIDEO_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/bool_parser.h"
#include "src/colour_parser.h"
#include "src/float_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/callback.h"
#include "webm/dom_types.h"
#include "webm/id.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#Video
// http://www.webmproject.org/docs/container/#Video
class VideoParser : public MasterValueParser<Video> {
public:
VideoParser()
: MasterValueParser<Video>(
MakeChild<IntParser<FlagInterlaced>>(Id::kFlagInterlaced,
&Video::interlaced),
MakeChild<IntParser<StereoMode>>(Id::kStereoMode,
&Video::stereo_mode),
MakeChild<UnsignedIntParser>(Id::kAlphaMode, &Video::alpha_mode),
MakeChild<UnsignedIntParser>(Id::kPixelWidth, &Video::pixel_width),
MakeChild<UnsignedIntParser>(Id::kPixelHeight,
&Video::pixel_height),
MakeChild<UnsignedIntParser>(Id::kPixelCropBottom,
&Video::pixel_crop_bottom),
MakeChild<UnsignedIntParser>(Id::kPixelCropTop,
&Video::pixel_crop_top),
MakeChild<UnsignedIntParser>(Id::kPixelCropLeft,
&Video::pixel_crop_left),
MakeChild<UnsignedIntParser>(Id::kPixelCropRight,
&Video::pixel_crop_right),
MakeChild<UnsignedIntParser>(Id::kDisplayWidth,
&Video::display_width)
.NotifyOnParseComplete(),
MakeChild<UnsignedIntParser>(Id::kDisplayHeight,
&Video::display_height)
.NotifyOnParseComplete(),
MakeChild<IntParser<DisplayUnit>>(Id::kDisplayUnit,
&Video::display_unit),
MakeChild<IntParser<AspectRatioType>>(Id::kAspectRatioType,
&Video::aspect_ratio_type),
MakeChild<FloatParser>(Id::kFrameRate, &Video::frame_rate),
MakeChild<ColourParser>(Id::kColour, &Video::colour)) {}
Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) override {
display_width_has_value_ = false;
display_height_has_value_ = false;
return MasterValueParser::Init(metadata, max_size);
}
void InitAfterSeek(const Ancestory& child_ancestory,
const ElementMetadata& child_metadata) override {
display_width_has_value_ = false;
display_height_has_value_ = false;
return MasterValueParser::InitAfterSeek(child_ancestory, child_metadata);
}
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override {
const Status status =
MasterValueParser::Feed(callback, reader, num_bytes_read);
if (status.completed_ok()) {
FixMissingDisplaySize();
}
return status;
}
protected:
void OnChildParsed(const ElementMetadata& metadata) override {
assert(metadata.id == Id::kDisplayWidth ||
metadata.id == Id::kDisplayHeight);
if (metadata.id == Id::kDisplayWidth) {
display_width_has_value_ = metadata.size > 0;
} else {
display_height_has_value_ = metadata.size > 0;
}
}
private:
bool display_width_has_value_;
bool display_height_has_value_;
void FixMissingDisplaySize() {
if (!display_width_has_value_) {
*mutable_value()->display_width.mutable_value() =
value().pixel_width.value();
}
if (!display_height_has_value_) {
*mutable_value()->display_height.mutable_value() =
value().pixel_height.value();
}
}
};
} // namespace webm
#endif // SRC_VIDEO_PARSER_H_

View File

@@ -0,0 +1,72 @@
// 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.
#include "src/virtual_block_parser.h"
#include <cassert>
#include <cstdint>
#include "webm/element.h"
namespace webm {
Status VirtualBlockParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == kUnknownElementSize || metadata.size < 4) {
return Status(Status::kInvalidElementSize);
}
*this = {};
my_size_ = metadata.size;
return Status(Status::kOkCompleted);
}
Status VirtualBlockParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
*num_bytes_read = 0;
Status status;
std::uint64_t local_num_bytes_read;
while (true) {
switch (state_) {
case State::kReadingHeader: {
status = parser_.Feed(callback, reader, &local_num_bytes_read);
*num_bytes_read += local_num_bytes_read;
total_bytes_read_ += local_num_bytes_read;
if (!status.completed_ok()) {
return status;
}
value_.track_number = parser_.value().track_number;
value_.timecode = parser_.value().timecode;
state_ = State::kValidatingSize;
continue;
}
case State::kValidatingSize: {
if (my_size_ < total_bytes_read_) {
return Status(Status::kInvalidElementValue);
}
state_ = State::kDone;
continue;
}
case State::kDone: {
return Status(Status::kOkCompleted);
}
}
}
}
} // namespace webm

View File

@@ -0,0 +1,67 @@
// 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_VIRTUAL_BLOCK_PARSER_H_
#define SRC_VIRTUAL_BLOCK_PARSER_H_
#include <cassert>
#include <cstdint>
#include "src/block_header_parser.h"
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/dom_types.h"
#include "webm/element.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Spec reference:
// http://matroska.org/technical/specs/index.html#BlockVirtual
// http://www.webmproject.org/docs/container/#BlockVirtual
// http://matroska.org/technical/specs/index.html#block_virtual
class VirtualBlockParser : public ElementParser {
public:
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
// Gets the parsed block header information. This must not be called until the
// parse has been successfully completed.
const VirtualBlock& value() const {
assert(state_ == State::kDone);
return value_;
}
// Gets the parsed block header information. This must not be called until the
// parse has been successfully completed.
VirtualBlock* mutable_value() {
assert(state_ == State::kDone);
return &value_;
}
private:
std::uint64_t my_size_;
std::uint64_t total_bytes_read_ = 0;
VirtualBlock value_{};
BlockHeaderParser parser_;
enum class State {
// State Transitions to state When
kReadingHeader, // kValidatingSize header parsed
kValidatingSize, // kDone no errors
kDone, // No transitions from here (must call Init)
} state_ = State::kReadingHeader;
};
} // namespace webm
#endif // SRC_VIRTUAL_BLOCK_PARSER_H_

View File

@@ -0,0 +1,49 @@
// 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.
#include "src/void_parser.h"
#include <cassert>
#include <cstdint>
#include "webm/callback.h"
#include "webm/element.h"
#include "webm/id.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
Status VoidParser::Init(const ElementMetadata& metadata,
std::uint64_t max_size) {
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
if (metadata.size == kUnknownElementSize) {
return Status(Status::kInvalidElementSize);
}
metadata_ = metadata;
bytes_remaining_ = metadata.size;
return Status(Status::kOkCompleted);
}
Status VoidParser::Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) {
assert(callback != nullptr);
assert(reader != nullptr);
assert(num_bytes_read != nullptr);
const std::uint64_t original_bytes_remaining = bytes_remaining_;
const Status status = callback->OnVoid(metadata_, reader, &bytes_remaining_);
assert(bytes_remaining_ <= original_bytes_remaining);
*num_bytes_read = original_bytes_remaining - bytes_remaining_;
return status;
}
} // namespace webm

View File

@@ -0,0 +1,41 @@
// 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_VOID_PARSER_H_
#define SRC_VOID_PARSER_H_
#include <cstdint>
#include "src/element_parser.h"
#include "webm/callback.h"
#include "webm/reader.h"
#include "webm/status.h"
namespace webm {
// Parses a Void element by delegating to Callback::OnVoid.
// Spec reference:
// http://matroska.org/technical/specs/index.html#Void
// http://www.webmproject.org/docs/container/#Void
class VoidParser : public ElementParser {
public:
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
Status Feed(Callback* callback, Reader* reader,
std::uint64_t* num_bytes_read) override;
private:
// The metadata for this element.
ElementMetadata metadata_;
// The number of bytes remaining that have not been read in the element.
std::uint64_t bytes_remaining_ = 0;
};
} // namespace webm
#endif // SRC_VOID_PARSER_H_

View File

@@ -0,0 +1,276 @@
// 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.
#include "webm/webm_parser.h"
#include <cassert>
#include <cstdint>
#include "src/ebml_parser.h"
#include "src/master_parser.h"
#include "src/segment_parser.h"
#include "webm/element.h"
namespace webm {
// Parses WebM EBML documents (i.e. level-0 WebM elements).
class WebmParser::DocumentParser {
public:
// Resets the parser after a seek to a new position in the reader.
void DidSeek() {
PrepareForNextChild();
did_seek_ = true;
state_ = State::kBegin;
}
// Feeds the parser; will return Status::kOkCompleted when the reader returns
// Status::kEndOfFile, but only if the parser has already completed parsing
// its child elements.
Status Feed(Callback* callback, Reader* reader) {
assert(callback != nullptr);
assert(reader != nullptr);
Callback* const original_callback = callback;
if (action_ == Action::kSkip) {
callback = &skip_callback_;
}
Status status;
std::uint64_t num_bytes_read;
while (true) {
switch (state_) {
case State::kBegin: {
child_metadata_.header_size = 0;
child_metadata_.position = reader->Position();
state_ = State::kReadingChildId;
continue;
}
case State::kReadingChildId: {
assert(child_parser_ == nullptr);
status = id_parser_.Feed(callback, reader, &num_bytes_read);
child_metadata_.header_size += num_bytes_read;
if (!status.completed_ok()) {
if (status.code == Status::kEndOfFile &&
reader->Position() == child_metadata_.position) {
state_ = State::kEndReached;
continue;
}
return status;
}
state_ = State::kReadingChildSize;
continue;
}
case State::kReadingChildSize: {
assert(child_parser_ == nullptr);
status = size_parser_.Feed(callback, reader, &num_bytes_read);
child_metadata_.header_size += num_bytes_read;
if (!status.completed_ok()) {
return status;
}
child_metadata_.id = id_parser_.id();
child_metadata_.size = size_parser_.size();
state_ = State::kValidatingChildSize;
continue;
}
case State::kValidatingChildSize: {
assert(child_parser_ == nullptr);
if (child_metadata_.id == Id::kSegment) {
child_parser_ = &segment_parser_;
did_seek_ = false;
state_ = State::kGettingAction;
continue;
} else if (child_metadata_.id == Id::kEbml) {
child_parser_ = &ebml_parser_;
did_seek_ = false;
state_ = State::kGettingAction;
continue;
}
Ancestory ancestory;
if (did_seek_ && Ancestory::ById(child_metadata_.id, &ancestory)) {
assert(!ancestory.empty());
assert(ancestory.id() == Id::kSegment ||
ancestory.id() == Id::kEbml);
if (ancestory.id() == Id::kSegment) {
child_parser_ = &segment_parser_;
} else {
child_parser_ = &ebml_parser_;
}
child_parser_->InitAfterSeek(ancestory.next(), child_metadata_);
child_metadata_.id = ancestory.id();
child_metadata_.header_size = kUnknownHeaderSize;
child_metadata_.size = kUnknownElementSize;
child_metadata_.position = kUnknownElementPosition;
did_seek_ = false;
action_ = Action::kRead;
state_ = State::kReadingChildBody;
continue;
}
if (child_metadata_.id == Id::kVoid) {
child_parser_ = &void_parser_;
} else {
if (child_metadata_.size == kUnknownElementSize) {
return Status(Status::kIndefiniteUnknownElement);
}
child_parser_ = &skip_parser_;
}
state_ = State::kGettingAction;
continue;
}
case State::kGettingAction: {
assert(child_parser_ != nullptr);
status = callback->OnElementBegin(child_metadata_, &action_);
if (!status.completed_ok()) {
return status;
}
if (action_ == Action::kSkip) {
callback = &skip_callback_;
if (child_metadata_.size != kUnknownElementSize) {
child_parser_ = &skip_parser_;
}
}
state_ = State::kInitializingChildParser;
continue;
}
case State::kInitializingChildParser: {
assert(child_parser_ != nullptr);
status = child_parser_->Init(child_metadata_, child_metadata_.size);
if (!status.completed_ok()) {
return status;
}
state_ = State::kReadingChildBody;
continue;
}
case State::kReadingChildBody: {
assert(child_parser_ != nullptr);
status = child_parser_->Feed(callback, reader, &num_bytes_read);
if (!status.completed_ok()) {
return status;
}
if (child_parser_->GetCachedMetadata(&child_metadata_)) {
state_ = State::kValidatingChildSize;
} else {
child_metadata_.header_size = 0;
state_ = State::kReadingChildId;
}
PrepareForNextChild();
callback = original_callback;
child_metadata_.position = reader->Position();
continue;
}
case State::kEndReached: {
return Status(Status::kOkCompleted);
}
}
}
}
private:
// Parsing states for the finite-state machine.
enum class State {
// State Transitions to state When
kBegin, // kReadingChildId done
kReadingChildId, // kReadingChildSize done
// kEndReached EOF
kReadingChildSize, // kValidatingChildSize done
kValidatingChildSize, // kGettingAction done
kGettingAction, // kInitializingChildParser done
kInitializingChildParser, // kReadingChildBody done
kReadingChildBody, // kValidatingChildSize cached metadata
// kReadingChildId otherwise
kEndReached, // No transitions from here
};
// The parser for parsing child element Ids.
IdParser id_parser_;
// The parser for parsing child element sizes.
SizeParser size_parser_;
// The parser for Id::kEbml elements.
EbmlParser ebml_parser_;
// The parser for Id::kSegment child elements.
SegmentParser segment_parser_;
// The parser for Id::kVoid child elements.
VoidParser void_parser_;
// The parser used when skipping elements (if the element's size is known).
SkipParser skip_parser_;
// The callback used when skipping elements.
SkipCallback skip_callback_;
// The parser that is parsing the current child element.
ElementParser* child_parser_ = nullptr;
// Metadata for the current child being parsed.
ElementMetadata child_metadata_ = {};
// Action for the current child being parsed.
Action action_ = Action::kRead;
// True if a seek was performed and the parser needs to handle it.
bool did_seek_ = false;
// The current state of the finite state machine.
State state_ = State::kBegin;
// Resets state in preparation for parsing a child element.
void PrepareForNextChild() {
id_parser_ = {};
size_parser_ = {};
child_parser_ = nullptr;
action_ = Action::kRead;
}
};
// We have to explicitly declare a destructor (even if it's just defaulted)
// because using the pimpl idiom with std::unique_ptr requires it. See Herb
// Sutter's GotW #100 for further explanation.
WebmParser::~WebmParser() = default;
WebmParser::WebmParser() : parser_(new DocumentParser) {}
void WebmParser::DidSeek() {
parser_->DidSeek();
parsing_status_ = Status(Status::kOkPartial);
}
Status WebmParser::Feed(Callback* callback, Reader* reader) {
assert(callback != nullptr);
assert(reader != nullptr);
if (parsing_status_.is_parsing_error()) {
return parsing_status_;
}
parsing_status_ = parser_->Feed(callback, reader);
return parsing_status_;
}
void WebmParser::Swap(WebmParser* other) {
assert(other != nullptr);
parser_.swap(other->parser_);
std::swap(parsing_status_, other->parsing_status_);
}
void swap(WebmParser& left, WebmParser& right) { left.Swap(&right); }
} // namespace webm