1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 21:47:46 +00:00

AK: Port LEB128 to the new AK::Stream

This commit is contained in:
Tim Schumacher 2023-01-29 13:09:25 +01:00 committed by Andrew Kaster
parent 31f59855b4
commit 787f4d639a
10 changed files with 120 additions and 209 deletions

View file

@ -6,36 +6,32 @@
#pragma once
#include <AK/DeprecatedStream.h>
#include <AK/NumericLimits.h>
#include <AK/Stream.h>
#include <AK/Types.h>
namespace AK {
struct LEB128 {
template<typename ValueType = size_t>
static bool read_unsigned(DeprecatedInputStream& stream, ValueType& result)
static ErrorOr<void> read_unsigned(AK::Stream& stream, ValueType& result)
{
result = 0;
size_t num_bytes = 0;
while (true) {
if (stream.unreliable_eof()) {
stream.set_fatal_error();
return false;
}
u8 byte = 0;
stream >> byte;
if (stream.has_any_error())
return false;
if (stream.is_eof())
return Error::from_string_literal("Stream reached end-of-file while reading LEB128 value");
auto byte = TRY(stream.read_value<u8>());
ValueType masked_byte = byte & ~(1 << 7);
bool const shift_too_large_for_result = num_bytes * 7 > sizeof(ValueType) * 8;
if (shift_too_large_for_result)
return false;
return Error::from_string_literal("Read value contains more bits than fit the chosen ValueType");
bool const shift_too_large_for_byte = ((masked_byte << (num_bytes * 7)) >> (num_bytes * 7)) != masked_byte;
if (shift_too_large_for_byte)
return false;
return Error::from_string_literal("Read byte is too large to fit the chosen ValueType");
result = (result) | (masked_byte << (num_bytes * 7));
if (!(byte & (1 << 7)))
@ -43,11 +39,11 @@ struct LEB128 {
++num_bytes;
}
return true;
return {};
}
template<typename ValueType = ssize_t>
static bool read_signed(DeprecatedInputStream& stream, ValueType& result)
static ErrorOr<void> read_signed(AK::Stream& stream, ValueType& result)
{
// Note: We read into a u64 to simplify the parsing logic;
// result is range checked into ValueType after parsing.
@ -59,24 +55,20 @@ struct LEB128 {
result = 0;
do {
if (stream.unreliable_eof()) {
stream.set_fatal_error();
return false;
}
if (stream.is_eof())
return Error::from_string_literal("Stream reached end-of-file while reading LEB128 value");
stream >> byte;
if (stream.has_any_error())
return false;
byte = TRY(stream.read_value<u8>());
// note: 64 bit assumptions!
u64 masked_byte = byte & ~(1 << 7);
bool const shift_too_large_for_result = num_bytes * 7 >= 64;
if (shift_too_large_for_result)
return false;
return Error::from_string_literal("Read value contains more bits than fit the chosen ValueType");
bool const shift_too_large_for_byte = (num_bytes * 7) == 63 && masked_byte != 0x00 && masked_byte != 0x7Fu;
if (shift_too_large_for_byte)
return false;
return Error::from_string_literal("Read byte is too large to fit the chosen ValueType");
temp = (temp) | (masked_byte << (num_bytes * 7));
++num_bytes;
@ -90,12 +82,12 @@ struct LEB128 {
// Now that we've accumulated into an i64, make sure it fits into result
if constexpr (sizeof(ValueType) < sizeof(u64)) {
if (temp > NumericLimits<ValueType>::max() || temp < NumericLimits<ValueType>::min())
return false;
return Error::from_string_literal("Temporary value does not fit the result type");
}
result = static_cast<ValueType>(temp);
return true;
return {};
}
};