Initial release

This commit is contained in:
civ
2026-08-16 18:27:57 +07:00
commit 8ff9ca0fc0
3800 changed files with 848933 additions and 0 deletions
@@ -0,0 +1,138 @@
// 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 INCLUDE_WEBM_BUFFER_READER_H_
#define INCLUDE_WEBM_BUFFER_READER_H_
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <vector>
#include "./reader.h"
#include "./status.h"
/**
\file
A `Reader` implementation that reads from a `std::vector<std::uint8_t>`.
*/
namespace webm {
/**
\addtogroup PUBLIC_API
@{
*/
/**
A simple reader that reads data from a buffer of bytes.
*/
class BufferReader : public Reader {
public:
/**
Constructs a new, empty reader.
*/
BufferReader() = default;
/**
Constructs a new reader by copying the provided reader into the new reader.
\param other The source reader to copy.
*/
BufferReader(const BufferReader& other) = default;
/**
Copies the provided reader into this reader.
\param other The source reader to copy. May be equal to `*this`, in which
case this is a no-op.
\return `*this`.
*/
BufferReader& operator=(const BufferReader& other) = default;
/**
Constructs a new reader by moving the provided reader into the new reader.
\param other The source reader to move. After moving, it will be reset to an
empty stream.
*/
BufferReader(BufferReader&&);
/**
Moves the provided reader into this reader.
\param other The source reader to move. After moving, it will be reset to an
empty stream. May be equal to `*this`, in which case this is a no-op.
\return `*this`.
*/
BufferReader& operator=(BufferReader&&);
/**
Creates a new `BufferReader` populated with the provided bytes.
\param bytes Bytes that are assigned to the internal buffer and used as the
source which is read from.
*/
BufferReader(std::initializer_list<std::uint8_t> bytes);
/**
Creates a new `BufferReader` populated with the provided data.
\param vector A vector of bytes that is copied to the internal buffer and
used as the source which is read from.
*/
explicit BufferReader(const std::vector<std::uint8_t>& vector);
/**
Creates a new `BufferReader` populated with the provided data.
\param vector A vector of bytes that is moved to the internal buffer and used
as the source which is read from.
*/
explicit BufferReader(std::vector<std::uint8_t>&& vector);
/**
Resets the reader to read from the given list of bytes, starting at the
beginning.
This makes `reader = {1, 2, 3};` effectively equivalent to `reader =
BufferReader({1, 2, 3});`.
\param bytes Bytes that are assigned to the internal buffer and used as the
source which is read from.
\return `*this`.
*/
BufferReader& operator=(std::initializer_list<std::uint8_t> bytes);
Status Read(std::size_t num_to_read, std::uint8_t* buffer,
std::uint64_t* num_actually_read) override;
Status Skip(std::uint64_t num_to_skip,
std::uint64_t* num_actually_skipped) override;
std::uint64_t Position() const override;
/**
Gets the total size of the buffer.
*/
std::size_t size() const { return data_.size(); }
private:
// Stores the byte buffer from which data is read.
std::vector<std::uint8_t> data_;
// The position of the reader in the byte buffer.
std::size_t pos_ = 0;
};
/**
@}
*/
} // namespace webm
#endif // INCLUDE_WEBM_BUFFER_READER_H_
+363
View File
@@ -0,0 +1,363 @@
// 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 INCLUDE_WEBM_CALLBACK_H_
#define INCLUDE_WEBM_CALLBACK_H_
#include <cstdint>
#include "./dom_types.h"
#include "./reader.h"
#include "./status.h"
/**
\file
The main callback type that receives parsing events.
*/
namespace webm {
/**
\addtogroup PUBLIC_API
@{
*/
/**
The action to be performed when parsing an element.
*/
enum class Action {
/**
Read and parse the element.
*/
kRead,
/**
Skip the element. Skipped elements are not parsed or stored, and the callback
is not given any further notifications regarding the element.
*/
kSkip,
};
/**
A callback that receives parsing events.
Every method that returns a `Status` should return `Status::kOkCompleted` when
the method has completed and parsing should continue. Returning any other value
will cause parsing to stop. Parsing may be resumed if the returned status was
not a parsing error (see `Status::is_parsing_error()`). When parsing is
resumed, the same `Callback` method will be called again.
Methods that take a `Reader` expect the implementation to consume (either via
`Reader::Read()` or `Reader::Skip()`) the specified number of bytes before
returning `Status::kOkCompleted`. Default implementations will call
`Reader::Skip()` to skip the specified number of bytes and the resulting
`Status` will be returned (unless it's `Status::kOkPartial`, in which case
`Reader::Skip()` will be called again to skip more data).
Throwing an exception from the member functions is permitted, though if the
exception will be caught and parsing resumed, then the reader should not
advance its position (for methods that take a `Reader`) before the exception is
thrown. When parsing is resumed, the same `Callback` method will be called
again.
Users should derive from this class and override member methods as needed.
*/
class Callback {
public:
virtual ~Callback() = default;
/**
Called when the parser starts a new element. This is called after the
elements ID and size has been parsed, but before any of its body has been
read (or validated).
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
\param metadata Metadata about the element that has just been encountered.
\param[out] action The action that should be taken when handling this
element. Will not be null.
*/
virtual Status OnElementBegin(const ElementMetadata& metadata,
Action* action);
/**
Called when the parser encounters an unknown element.
Defaults to calling (and returning the result of) `Reader::Skip()`.
\param metadata Metadata about the element.
\param reader The reader that should be used to consume data. Will not be
null.
\param[in,out] bytes_remaining The number of remaining bytes that need to be
consumed for the element. Will not be null.
\return `Status::kOkCompleted` when the element has been fully consumed and
`bytes_remaining` is now zero.
*/
virtual Status OnUnknownElement(const ElementMetadata& metadata,
Reader* reader,
std::uint64_t* bytes_remaining);
/**
Called when the parser encounters an `Id::kEbml` element and it has been
fully parsed.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param ebml The parsed element.
*/
virtual Status OnEbml(const ElementMetadata& metadata, const Ebml& ebml);
/**
Called when the parser encounters an Id::kVoid element.
Defaults to calling (and returning the result of) Reader::Skip.
\param metadata Metadata about the element.
\param reader The reader that should be used to consume data. Will not be
null.
\param[in,out] bytes_remaining The number of remaining bytes that need to be
consumed for the element. Will not be null.
\return `Status::kOkCompleted` when the element has been fully consumed and
`bytes_remaining` is now zero.
*/
virtual Status OnVoid(const ElementMetadata& metadata, Reader* reader,
std::uint64_t* bytes_remaining);
/**
Called when the parser starts an `Id::kSegment` element.
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
\param metadata Metadata about the element that has just been encountered.
\param[out] action The action that should be taken when handling this
element. Will not be null.
*/
virtual Status OnSegmentBegin(const ElementMetadata& metadata,
Action* action);
/**
Called when the parser encounters an `Id::kSeek` element and it has been
fully parsed.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param seek The parsed element.
*/
virtual Status OnSeek(const ElementMetadata& metadata, const Seek& seek);
/**
Called when the parser encounters an `Id::kInfo` element and it has been
fully parsed.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param info The parsed element.
*/
virtual Status OnInfo(const ElementMetadata& metadata, const Info& info);
/**
Called when the parser starts an `Id::kCluster` element.
Because Cluster elements should start with a Timecode (and optionally
PrevSize) child, this method is not invoked until a child BlockGroup or
SimpleBlock element is encountered (or the Cluster ends if no such child
exists).
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param cluster The element, as it has currently been parsed.
\param[out] action The action that should be taken when handling this
element. Will not be null.
*/
virtual Status OnClusterBegin(const ElementMetadata& metadata,
const Cluster& cluster, Action* action);
/**
Called when the parser starts an `Id::kSimpleBlock` element.
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param simple_block The parsed SimpleBlock header.
\param[out] action The action that should be taken when handling this
element. Will not be null.
*/
virtual Status OnSimpleBlockBegin(const ElementMetadata& metadata,
const SimpleBlock& simple_block,
Action* action);
/**
Called when the parser finishes an `Id::kSimpleBlock` element.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param simple_block The parsed SimpleBlock header.
*/
virtual Status OnSimpleBlockEnd(const ElementMetadata& metadata,
const SimpleBlock& simple_block);
/**
Called when the parser starts an `Id::kBlockGroup` element.
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param[out] action The action that should be taken when handling this
element. Will not be null.
*/
virtual Status OnBlockGroupBegin(const ElementMetadata& metadata,
Action* action);
/**
Called when the parser starts an `Id::kBlock` element.
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param block The parsed Block header.
\param[out] action The action that should be taken when handling this
element. Will not be null.
*/
virtual Status OnBlockBegin(const ElementMetadata& metadata,
const Block& block, Action* action);
/**
Called when the parser finishes an `Id::Block` element.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param block The parsed Block header.
*/
virtual Status OnBlockEnd(const ElementMetadata& metadata,
const Block& block);
/**
Called when the parser finishes an `Id::kBlockGroup` element.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param block_group The parsed element.
*/
virtual Status OnBlockGroupEnd(const ElementMetadata& metadata,
const BlockGroup& block_group);
/**
Called when the parser encounters a frame within a `Id::kBlock` or
`Id::kSimpleBlock` element.
Defaults to calling (and returning the result of) `Reader::Skip`.
\param metadata Metadata about the frame.
\param reader The reader that should be used to consume data. Will not be
null.
\param[in,out] bytes_remaining The number of remaining bytes that need to be
consumed for the frame. Will not be null.
\return `Status::kOkCompleted` when the frame has been fully consumed and
`bytes_remaining` is now zero.
*/
virtual Status OnFrame(const FrameMetadata& metadata, Reader* reader,
std::uint64_t* bytes_remaining);
/**
Called when the parser finishes an `Id::kCluster` element.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param cluster The parsed element.
*/
virtual Status OnClusterEnd(const ElementMetadata& metadata,
const Cluster& cluster);
/**
Called when the parser starts an `Id::kTrackEntry` element.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param track_entry The parsed element.
*/
virtual Status OnTrackEntry(const ElementMetadata& metadata,
const TrackEntry& track_entry);
/**
Called when the parser encounters an `Id::kCuePoint` element and it has been
fully parsed.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param cue_point The parsed element.
*/
virtual Status OnCuePoint(const ElementMetadata& metadata,
const CuePoint& cue_point);
/**
Called when the parser encounters an `Id::kEditionEntry` element and it has
been fully parsed.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param edition_entry The parsed element.
*/
virtual Status OnEditionEntry(const ElementMetadata& metadata,
const EditionEntry& edition_entry);
/**
Called when the parser encounters an `Id::kTag` element and it has been fully
parsed.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
\param tag The parsed element.
*/
virtual Status OnTag(const ElementMetadata& metadata, const Tag& tag);
/**
Called when the parser finishes an `Id::kSegment` element.
Defaults to returning `Status::kOkCompleted`.
\param metadata Metadata about the element.
*/
virtual Status OnSegmentEnd(const ElementMetadata& metadata);
protected:
/**
Calls (and returns the result of) `Reader::Skip()`, skipping (up to) the
requested number of bytes.
Unlike `Reader::Skip()`, this method may be called with `*bytes_remaining ==
0`, which will result in `Status::kOkCompleted`. `Reader::Skip()` will be
called multiple times if it returns `Status::kOkPartial` until it returns a
different status (indicating the requested number of bytes has been fully
skipped or some error occurred).
\param reader The reader that should be used to skip data. Must not be null.
\param[in,out] bytes_remaining The number of remaining bytes that need to be
skipped. Must not be null. May be zero.
\return The result of `Reader::Skip()`.
*/
static Status Skip(Reader* reader, std::uint64_t* bytes_remaining);
};
/**
@}
*/
} // namespace webm
#endif // INCLUDE_WEBM_CALLBACK_H_
File diff suppressed because it is too large Load Diff
+208
View File
@@ -0,0 +1,208 @@
// 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 INCLUDE_WEBM_ELEMENT_H_
#define INCLUDE_WEBM_ELEMENT_H_
#include <cstdint>
#include <limits>
#include <utility>
#include "./id.h"
/**
\file
A wrapper around an object that represents a WebM element, including its parsed
metadata.
*/
namespace webm {
/**
\addtogroup PUBLIC_API
@{
*/
/**
A wrapper around an object that represents a WebM element.
Since some elements may be absent, this wrapper is used to indicate the
presence (or lack thereof) of an element in a WebM document. If the element is
encoded in the file and it has been parsed, `is_present()` will return true.
Otherwise it will return false since the element was ommitted or skipped when
parsing.
*/
template <typename T>
class Element {
public:
/**
Value-initializes the element's value and makes `is_present()` false.
*/
constexpr Element() = default;
/**
Creates an element with the given value and makes `is_present()` false.
\param value The value of the element.
*/
explicit constexpr Element(const T& value) : value_(value) {}
/**
Creates an element with the given value and makes `is_present()` false.
\param value The value of the element.
*/
explicit constexpr Element(T&& value) : value_(std::move(value)) {}
/**
Creates an element with the given value and presence state.
\param value The value of the element.
\param is_present True if the element is present, false if it is absent.
*/
constexpr Element(const T& value, bool is_present)
: value_(value), is_present_(is_present) {}
/**
Creates an element with the given value and presence state.
\param value The value of the element.
\param is_present True if the element is present, false if it is absent.
*/
constexpr Element(T&& value, bool is_present)
: value_(std::move(value)), is_present_(is_present) {}
constexpr Element(const Element<T>& other) = default;
constexpr Element(Element<T>&& other) = default;
~Element() = default;
Element<T>& operator=(const Element<T>& other) = default;
Element<T>& operator=(Element<T>&& other) = default;
/**
Sets the element's value and state.
\param value The new value for the element.
\param is_present The new presence state for the element.
*/
void Set(const T& value, bool is_present) {
value_ = value;
is_present_ = is_present;
}
/**
Sets the element's value and state.
\param value The new value for the element.
\param is_present The new presence state for the element.
*/
void Set(T&& value, bool is_present) {
value_ = std::move(value);
is_present_ = is_present;
}
/**
Gets the element's value.
*/
constexpr const T& value() const { return value_; }
/**
Gets a mutuable pointer to the element's value (will never be null).
*/
T* mutable_value() { return &value_; }
/**
Returns true if the element is present, false otherwise.
*/
constexpr bool is_present() const { return is_present_; }
bool operator==(const Element<T>& other) const {
return is_present_ == other.is_present_ && value_ == other.value_;
}
private:
T value_{};
bool is_present_ = false;
};
/**
Metadata for WebM elements that are encountered when parsing.
*/
struct ElementMetadata {
/**
The EBML ID of the element.
*/
Id id;
/**
The number of bytes that were used to encode the EBML ID and element size.
If the size of the header is unknown (which is only the case if a seek was
performed to the middle of an element, so its header was not parsed), this
will be the value `kUnknownHeaderSize`.
*/
std::uint32_t header_size;
/**
The size of the element.
This is number of bytes in the element's body, which excludes the header
bytes.
If the size of the element's body is unknown, this will be the value
`kUnknownElementSize`.
*/
std::uint64_t size;
/**
The absolute byte position of the element, starting at the first byte of the
element's header.
If the position of the element is unknown (which is only the case if a seek
was performed to the middle of an element), this will be the value
`kUnknownElementPosition`.
*/
std::uint64_t position;
/**
Returns true if every member within the two objects are equal.
*/
bool operator==(const ElementMetadata& other) const {
return id == other.id && header_size == other.header_size &&
size == other.size && position == other.position;
}
};
/**
A special value for `ElementMetadata::header_size` indicating the header size
is not known.
*/
constexpr std::uint64_t kUnknownHeaderSize =
std::numeric_limits<std::uint32_t>::max();
/**
A special value for `ElementMetadata::size` indicating the element's size is
not known.
*/
constexpr std::uint64_t kUnknownElementSize =
std::numeric_limits<std::uint64_t>::max();
/**
A special value for `ElementMetadata::position` indicating the element's
position is not known.
*/
constexpr std::uint64_t kUnknownElementPosition =
std::numeric_limits<std::uint64_t>::max();
/**
@}
*/
} // namespace webm
#endif // INCLUDE_WEBM_ELEMENT_H_
@@ -0,0 +1,103 @@
// 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 INCLUDE_WEBM_FILE_READER_H_
#define INCLUDE_WEBM_FILE_READER_H_
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include "./reader.h"
#include "./status.h"
/**
\file
A `Reader` implementation that reads from a `FILE*`.
*/
namespace webm {
/**
A `Reader` implementation that can read from `FILE*` resources.
*/
class FileReader : public Reader {
public:
/**
Constructs a new, empty reader.
*/
FileReader() = default;
/**
Constructs a new reader, using the provided file as the data source.
Ownership of the file is taken, and `std::fclose()` will be called when the
object is destroyed.
\param file The file to use as a data source. Must not be null. The file will
be closed (via `std::fclose()`) when the `FileReader`'s destructor runs.
*/
explicit FileReader(FILE* file);
/**
Constructs a new reader by moving the provided reader into the new reader.
\param other The source reader to move. After moving, it will be reset to an
empty stream.
*/
FileReader(FileReader&& other);
/**
Moves the provided reader into this reader.
\param other The source reader to move. After moving, it will be reset to an
empty stream. May be equal to `*this`, in which case this is a no-op.
\return `*this`.
*/
FileReader& operator=(FileReader&& other);
Status Read(std::size_t num_to_read, std::uint8_t* buffer,
std::uint64_t* num_actually_read) override;
Status Skip(std::uint64_t num_to_skip,
std::uint64_t* num_actually_skipped) override;
/**
Moves the reader to a new absolute byte position in the file.
It is required to call DidSeek() on the parser after successfully seeking.
Seeking will only work on actual files, not stdin or pipes.
\param seek_position The new absolute byte position in the file.
\return `Status::kOkCompleted` if reader position is now `seek_position`.
`Status::kSeekFailed` if the reader was unable to seek to `seek_position`
such as when the file is stdin.
*/
Status Seek(std::uint64_t seek_position);
std::uint64_t Position() const override;
private:
struct FileCloseFunctor {
void operator()(FILE* file) const {
if (file)
std::fclose(file);
}
};
std::unique_ptr<FILE, FileCloseFunctor> file_;
// We can't rely on ftell() for the position (since it only returns long, and
// doesn't work on things like pipes); we need to manually track the reading
// position.
std::uint64_t position_ = 0;
};
} // namespace webm
#endif // INCLUDE_WEBM_FILE_READER_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,99 @@
// 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 INCLUDE_WEBM_ISTREAM_READER_H_
#define INCLUDE_WEBM_ISTREAM_READER_H_
#include <cstdint>
#include <cstdlib>
#include <istream>
#include <memory>
#include <type_traits>
#include "./reader.h"
#include "./status.h"
/**
\file
A `Reader` implementation that reads from a `std::istream`.
*/
namespace webm {
/**
A `Reader` implementation that can read from `std::istream`-based resources.
*/
class IstreamReader : public Reader {
public:
/**
Constructs a new, empty reader.
*/
IstreamReader() = default;
/**
Constructs a new reader, using the provided `std::istream` as the data
source.
Ownership of the stream is taken, and it will be moved into a new internal
instance.
\param istream The stream to use as a data source. Must be an rvalue
reference derived from `std::istream`.
*/
template <typename T>
explicit IstreamReader(T&& istream) : istream_(new T(std::move(istream))) {}
/**
Constructs a new reader by moving the provided reader into the new reader.
\param other The source reader to move. After moving, it will be reset to an
empty stream.
*/
IstreamReader(IstreamReader&& other);
/**
Moves the provided reader into this reader.
\param other The source reader to move. After moving, it will be reset to an
empty stream. May be equal to `*this`, in which case this is a no-op.
\return `*this`.
*/
IstreamReader& operator=(IstreamReader&& other);
Status Read(std::size_t num_to_read, std::uint8_t* buffer,
std::uint64_t* num_actually_read) override;
Status Skip(std::uint64_t num_to_skip,
std::uint64_t* num_actually_skipped) override;
std::uint64_t Position() const override;
/**
Constructs a new reader and its data source in place.
`T` must be derived from `std::istream` and constructible from the provided
arguments.
\param args Arguments that will be forwarded to the `T`'s constructor.
\return A new `IstreamReader` backed by the underlying data source equivalent
to `T(std::forward<Args>(args)...`.
*/
template <typename T, typename... Args>
static IstreamReader Emplace(Args&&... args) {
IstreamReader reader;
reader.istream_.reset(new T(std::forward<Args>(args)...));
return reader;
}
private:
std::unique_ptr<std::istream> istream_;
std::uint64_t position_ = 0;
};
} // namespace webm
#endif // INCLUDE_WEBM_ISTREAM_READER_H_
+94
View File
@@ -0,0 +1,94 @@
// 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 INCLUDE_WEBM_READER_H_
#define INCLUDE_WEBM_READER_H_
#include <cstddef>
#include <cstdint>
#include "./status.h"
/**
\file
An interface that acts as a data source for the parser to read from.
*/
namespace webm {
/**
\addtogroup PUBLIC_API
@{
*/
/**
A generic interface for reading from a data source.
Throwing an exception from the member functions is permitted, though if the
exception will be caught and parsing resumed, then the reader should not
advance its position before throwing the exception.
*/
class Reader {
public:
virtual ~Reader() = default;
/**
Reads data from the source and advances the reader's position by the number
of bytes read.
Short reads are permitted, as is reading no data.
\param num_to_read The number of bytes that should be read. Must not be 0.
\param buffer The buffer to store the read bytes. Must be large enough to
store at least `num_to_read` bytes. Must not be null.
\param[out] num_actually_read The number of bytes that were actually read is
stored in this integer. Must not be null.
\return `Status::kOkCompleted` if `num_to_read` bytes were read.
`Status::kOkPartial` if the number of bytes read is > 0 and < `num_to_read`.
If no bytes are read, then some status other than `Status::kOkCompleted` and
`Status::kOkPartial` must be returned and `num_actually_read` must be set to
0.
*/
virtual Status Read(std::size_t num_to_read, std::uint8_t* buffer,
std::uint64_t* num_actually_read) = 0;
/**
Skips data from the source and advances the reader's position by the number
of bytes skipped.
Short skips are permitted, as is skipping no data. This is similar to the
`Read()` method, but does not store data in an output buffer.
\param num_to_skip The number of bytes that should be skipped. Must not be 0.
\param[out] num_actually_skipped The number of bytes that were actually
skipped is stored in this integer. Must not be null.
\return `Status::kOkCompleted` if `num_to_skip` bytes were skipped.
`Status::kOkPartial` if the number of bytes skipped is > 0 and <
`num_to_skip`. If no bytes are skipped, then some status other than
`Status::kOkCompleted` and `Status::kOkPartial` must be returned and
`num_actually_skipped` must be set to 0.
*/
virtual Status Skip(std::uint64_t num_to_skip,
std::uint64_t* num_actually_skipped) = 0;
/**
Gets the Reader's current absolute byte position in the stream.
Implementations don't necessarily need to start from 0 (which might be the
case if parsing is starting in the middle of a data source). The value
`kUnknownElementPosition` must not be returned.
*/
virtual std::uint64_t Position() const = 0;
};
/**
@}
*/
} // namespace webm
#endif // INCLUDE_WEBM_READER_H_
+166
View File
@@ -0,0 +1,166 @@
// 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 INCLUDE_WEBM_STATUS_H_
#define INCLUDE_WEBM_STATUS_H_
#include <cstdint>
/**
\file
Status information that represents success, failure, etc. for operations
throughout the API.
*/
namespace webm {
/**
\addtogroup PUBLIC_API
@{
*/
/**
An object used to represent the resulting status of various operations,
indicating success, failure, or some other result.
*/
struct Status {
/**
A list of generic status codes used by the parser. Users are encouraged to
reuse these values as needed in the derivations of `Callback`. These values
will always be <= 0.
*/
enum Code : std::int32_t {
// General status codes. Range: 0 to -1024.
/**
The operation successfully completed.
*/
kOkCompleted = 0,
/**
The operation was successful but only partially completed (for example, a
read that resulted in fewer bytes than requested).
*/
kOkPartial = -1,
/**
The operation would block, and should be tried again later.
*/
kWouldBlock = -2,
/**
More data was requested but the file has ended.
*/
kEndOfFile = -3,
/**
The reader was unable to seek to the requested location.
*/
kSeekFailed = -4,
// Parsing errors. Range: -1025 to -2048.
/**
An element's ID is malformed.
*/
kInvalidElementId = -1025,
/**
An element's size is malformed.
*/
kInvalidElementSize = -1026,
/**
An unknown element has unknown size.
*/
kIndefiniteUnknownElement = -1027,
/**
A child element overflowed the parent element's bounds.
*/
kElementOverflow = -1028,
/**
An element's size exceeds the system's memory limits.
*/
kNotEnoughMemory = -1029,
/**
An element's value is illegal/malformed.
*/
kInvalidElementValue = -1030,
/**
A recursive element was so deeply nested that exceeded the parser's limit.
*/
kExceededRecursionDepthLimit = -1031,
// The following codes are internal-only and should not be used by users.
// Additionally, these codes should never be returned to the user; doing so
// is considered a bug.
/**
\internal Parsing should switch from reading to skipping elements.
*/
kSwitchToSkip = INT32_MIN,
};
/**
Status codes <= 0 are reserved by the parsing library. User error codes
should be positive (> 0). Users are encouraged to use codes from the `Code`
enum, but may use a positive error code if some application-specific error is
encountered.
*/
std::int32_t code;
Status() = default;
Status(const Status&) = default;
Status(Status&&) = default;
Status& operator=(const Status&) = default;
Status& operator=(Status&&) = default;
/**
Creates a new `Status` object with the given status code.
\param code The status code which will be used to set the `code` member.
*/
constexpr explicit Status(Code code) : code(code) {}
/**
Creates a new `Status` object with the given status code.
\param code The status code which will be used to set the `code` member.
*/
constexpr explicit Status(std::int32_t code) : code(code) {}
/**
Returns true if the status code is either `kOkCompleted` or `kOkPartial`.
Provided for convenience.
*/
constexpr bool ok() const {
return code == kOkCompleted || code == kOkPartial;
}
/**
Returns true if the status code is `kOkCompleted`. Provided for convenience.
*/
constexpr bool completed_ok() const { return code == kOkCompleted; }
/**
Returns true if the status is considered a parsing error. Parsing errors
represent unrecoverable errors due to malformed data. Only status codes in
the range -2048 to -1025 (inclusive) are considered parsing errors.
*/
constexpr bool is_parsing_error() const {
return -2048 <= code && code <= -1025;
}
};
/**
@}
*/
} // namespace webm
#endif // INCLUDE_WEBM_STATUS_H_
@@ -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.
#ifndef INCLUDE_WEBM_WEBM_PARSER_H_
#define INCLUDE_WEBM_WEBM_PARSER_H_
#include <memory>
#include "./callback.h"
#include "./reader.h"
#include "./status.h"
/**
\file
The main parser class for parsing WebM files.
*/
namespace webm {
/**
\defgroup PUBLIC_API Public API
Public types and header files intended for use by users.
*/
/**
\addtogroup PUBLIC_API
@{
*/
/**
Incrementally parses a WebM document encoded in a byte stream.
It is expected that the parsing will begin at the start of the WebM
file/document. Otherwise, the `DidSeek()` method should be used to inform the
parser that reading may not necessarily begin at the beginning of the document
and the parser should be prepared to handle data at an arbitrary point in the
document.
WebM files are mostly a subset of Matroska, with a few small modifications.
Matroska is a format built on top of EBML.
*/
// Spec references:
// http://www.webmproject.org/docs/container/
// https://matroska.org/technical/specs/index.html
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown
class WebmParser {
public:
/**
Constructs the object and prepares it for parsing.
*/
WebmParser();
/*
Cleans up the parser. No further cleanup is required from the user.
*/
~WebmParser();
// Non-copyable and non-movable.
WebmParser(const WebmParser&) = delete;
WebmParser& operator=(const WebmParser&) = delete;
/**
Resets the parser after a seek was performed on the reader, which prepares
the parser for starting at an arbitrary point in the stream.
The seek must be to the start of an element (that is, it can't be any random
byte) or parsing will fail.
*/
void DidSeek();
/**
Feeds data into the parser from the provided reader.
If a parsing error code has been returned (which indicates a malformed
document), calling Feed() again will just result in the same error; parsing
has already failed at that point and further progress can't be made.
\param callback The callback which receives parsing events. No internal
references are maintained to `callback`, so it may be modified or freed after
this method returns.
\param reader The reader the parser will use to request data. No internal
references are maintained to `reader`, so it may be modified or freed after
this method returns.
\return `Status::kOkCompleted` when parsing completes successfully.
`Status::kOkPartial` or another non-parsing error code (see status.h for
error codes classified as parsing errors) will be returned if parsing has
only partially completed, and Feed() should be called again to resume
parsing.
*/
Status Feed(Callback* callback, Reader* reader);
/**
Swaps this parser and the provided parser.
\param other The parser to swap values/states with. Must not be null.
*/
void Swap(WebmParser* other);
private:
// This header can only rely on sources in the public API.
class DocumentParser;
// The internal implementation of the parser.
std::unique_ptr<DocumentParser> parser_;
// The status of the parser, used to prevent further progress if an
// unrecoverable parsing error has already been encountered.
Status parsing_status_ = Status(Status::kOkPartial);
};
/**
Swaps the two parsers.
This is provided so code can use argument dependent lookup in an idiomatic way
when swapping (especially since `std::swap` won't work since the parser is
non-movable).
\param left The first parser to swap.
\param right The second parser to swap.
*/
void swap(WebmParser& left, WebmParser& right);
/**
@}
*/
} // namespace webm
#endif // INCLUDE_WEBM_WEBM_PARSER_H_