203 lines
5.6 KiB
C++
203 lines
5.6 KiB
C++
/*
|
|
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
|
|
* Copyright (c) 2022-2026, Gregory Bertilson <gregory@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/IntegralMath.h>
|
|
#include <AK/String.h>
|
|
#include <AK/Utf8View.h>
|
|
#include <LibMedia/MediaStream.h>
|
|
|
|
#include "Streamer.h"
|
|
|
|
namespace Media::Matroska {
|
|
|
|
Streamer::Streamer(NonnullRefPtr<MediaStreamCursor> const& stream_cursor)
|
|
: m_stream_cursor(stream_cursor)
|
|
{
|
|
}
|
|
|
|
Streamer::~Streamer() = default;
|
|
|
|
DecoderErrorOr<String> Streamer::read_string()
|
|
{
|
|
auto string_length = TRY(read_variable_size_integer());
|
|
auto string_data = TRY(read_raw_octets(string_length));
|
|
auto const* string_data_raw = reinterpret_cast<char const*>(string_data.data());
|
|
auto string_value = String::from_utf8(ReadonlyBytes(string_data.data(), strnlen(string_data_raw, string_length)));
|
|
if (string_value.is_error())
|
|
return DecoderError::format(DecoderErrorCategory::Invalid, "String is not valid UTF-8");
|
|
return string_value.release_value();
|
|
}
|
|
|
|
DecoderErrorOr<u8> Streamer::read_octet()
|
|
{
|
|
u8 result;
|
|
Bytes bytes { &result, 1 };
|
|
auto bytes_read = TRY(m_stream_cursor->read_into(bytes));
|
|
if (bytes_read != 1)
|
|
return DecoderError::corrupted("Failed to read octet"sv);
|
|
return bytes[0];
|
|
}
|
|
|
|
DecoderErrorOr<i16> Streamer::read_i16()
|
|
{
|
|
return (TRY(read_octet()) << 8) | TRY(read_octet());
|
|
}
|
|
|
|
DecoderErrorOr<u32> Streamer::read_element_id()
|
|
{
|
|
auto length_byte = TRY(read_octet());
|
|
auto length = count_leading_zeroes_safe(length_byte) + 1;
|
|
if (length > 4)
|
|
return DecoderError::corrupted("Element ID must be 4 bytes or less"sv);
|
|
u32 result = length_byte;
|
|
auto bytes_left = length;
|
|
while (--bytes_left > 0) {
|
|
result <<= 8;
|
|
result |= TRY(read_octet());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
DecoderErrorOr<Optional<size_t>> Streamer::read_element_size()
|
|
{
|
|
auto length_byte = TRY(read_octet());
|
|
auto length = count_leading_zeroes_safe(length_byte) + 1;
|
|
if (length > 8)
|
|
return DecoderError::corrupted("Element Data Size 8 bytes or less"sv);
|
|
|
|
size_t result = length_byte;
|
|
auto bytes_left = length;
|
|
while (--bytes_left > 0) {
|
|
result <<= 8;
|
|
result |= TRY(read_octet());
|
|
}
|
|
|
|
auto mask = 0xFFFFFFFFFFFFFFFF >> (64 - (7 * length));
|
|
result &= mask;
|
|
|
|
if (result == mask)
|
|
return OptionalNone();
|
|
|
|
return result;
|
|
}
|
|
|
|
DecoderErrorOr<u64> Streamer::read_variable_size_integer()
|
|
{
|
|
auto length_byte = TRY(read_octet());
|
|
auto length = count_leading_zeroes_safe(length_byte) + 1;
|
|
if (length > 8)
|
|
return DecoderError::corrupted("VINT is too large"sv);
|
|
|
|
auto bytes_left = length;
|
|
auto result = length_byte & (0xFF >> length);
|
|
while (--bytes_left > 0) {
|
|
result <<= 8;
|
|
result |= TRY(read_octet());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DecoderErrorOr<i64> Streamer::read_variable_size_signed_integer()
|
|
{
|
|
auto length_byte = TRY(read_octet());
|
|
auto length = count_leading_zeroes_safe(length_byte) + 1;
|
|
if (length > 8)
|
|
return DecoderError::corrupted("VINT is too large"sv);
|
|
|
|
auto bytes_left = length;
|
|
i64 result = length_byte & (0xFF >> length);
|
|
while (--bytes_left > 0) {
|
|
result <<= 8;
|
|
result |= TRY(read_octet());
|
|
}
|
|
result -= AK::exp2<i64>((length * 7) - 1) - 1;
|
|
return result;
|
|
}
|
|
|
|
DecoderErrorOr<ByteBuffer> Streamer::read_raw_octets(size_t num_octets)
|
|
{
|
|
auto result = MUST(ByteBuffer::create_uninitialized(num_octets));
|
|
auto bytes = result.bytes();
|
|
TRY(m_stream_cursor->read_into(bytes));
|
|
return result;
|
|
}
|
|
|
|
DecoderErrorOr<u64> Streamer::read_u64()
|
|
{
|
|
auto integer_length = TRY(read_variable_size_integer());
|
|
if (integer_length == 0)
|
|
return 0;
|
|
if (integer_length > 8)
|
|
return DecoderError::corrupted("Integer Element is too large"sv);
|
|
u64 result = 0;
|
|
for (size_t i = 0; i < integer_length; i++) {
|
|
result <<= 8;
|
|
result |= TRY(read_octet());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DecoderErrorOr<i64> Streamer::read_i64()
|
|
{
|
|
auto integer_length = TRY(read_variable_size_integer());
|
|
if (integer_length == 0)
|
|
return 0;
|
|
if (integer_length > 8)
|
|
return DecoderError::corrupted("Signed Integer Element is too large"sv);
|
|
i64 result = 0;
|
|
for (size_t i = 0; i < integer_length; i++) {
|
|
result <<= 8;
|
|
result |= TRY(read_octet());
|
|
}
|
|
auto shift = 64 - (static_cast<i64>(integer_length) * 8);
|
|
result <<= shift;
|
|
result >>= shift;
|
|
return result;
|
|
}
|
|
|
|
DecoderErrorOr<double> Streamer::read_float()
|
|
{
|
|
auto length = TRY(read_variable_size_integer());
|
|
if (length == 0)
|
|
return 0;
|
|
if (length != 4u && length != 8u)
|
|
return DecoderError::format(DecoderErrorCategory::Invalid, "Float size must be 4 or 8 bytes");
|
|
|
|
union {
|
|
u64 value;
|
|
float float_value;
|
|
double double_value;
|
|
} read_data;
|
|
read_data.value = 0;
|
|
for (size_t i = 0; i < length; i++) {
|
|
read_data.value = (read_data.value << 8u) + TRY(read_octet());
|
|
}
|
|
if (length == 4u)
|
|
return read_data.float_value;
|
|
return read_data.double_value;
|
|
}
|
|
|
|
DecoderErrorOr<void> Streamer::read_unknown_element()
|
|
{
|
|
auto element_length = TRY(read_variable_size_integer());
|
|
dbgln_if(MATROSKA_TRACE_DEBUG, "Skipping unknown element of size {}.", element_length);
|
|
TRY(m_stream_cursor->seek(element_length, AK::SeekMode::FromCurrentPosition));
|
|
return {};
|
|
}
|
|
|
|
size_t Streamer::position() const
|
|
{
|
|
return m_stream_cursor->position();
|
|
}
|
|
|
|
DecoderErrorOr<void> Streamer::seek_to_position(size_t position)
|
|
{
|
|
return m_stream_cursor->seek(position, AK::SeekMode::SetPosition);
|
|
}
|
|
|
|
}
|