ladybird/Libraries/LibMedia/Containers/Matroska/Streamer.cpp

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);
}
}