mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 04:57:44 +00:00
AK: Allow rejecting BitStream reads beyond EOF
This commit is contained in:
parent
270b1176de
commit
cb03d3d78f
2 changed files with 47 additions and 8 deletions
|
@ -151,8 +151,14 @@ protected:
|
||||||
/// in little-endian order from another stream.
|
/// in little-endian order from another stream.
|
||||||
class LittleEndianInputBitStream : public LittleEndianBitStream {
|
class LittleEndianInputBitStream : public LittleEndianBitStream {
|
||||||
public:
|
public:
|
||||||
explicit LittleEndianInputBitStream(MaybeOwned<Stream> stream)
|
enum UnsatisfiableReadBehavior {
|
||||||
|
Reject,
|
||||||
|
FillWithZero,
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit LittleEndianInputBitStream(MaybeOwned<Stream> stream, UnsatisfiableReadBehavior unsatisfiable_read_behavior = UnsatisfiableReadBehavior::FillWithZero)
|
||||||
: LittleEndianBitStream(move(stream))
|
: LittleEndianBitStream(move(stream))
|
||||||
|
, m_unsatisfiable_read_behavior(unsatisfiable_read_behavior)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,8 +215,15 @@ public:
|
||||||
template<Unsigned T = u64>
|
template<Unsigned T = u64>
|
||||||
ErrorOr<T> peek_bits(size_t count)
|
ErrorOr<T> peek_bits(size_t count)
|
||||||
{
|
{
|
||||||
if (count > m_bit_count)
|
while (count > m_bit_count) {
|
||||||
TRY(refill_buffer_from_stream());
|
if (TRY(refill_buffer_from_stream()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m_unsatisfiable_read_behavior == UnsatisfiableReadBehavior::Reject)
|
||||||
|
return Error::from_string_literal("Reached end-of-stream without collecting the required number of bits");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return m_bit_buffer & lsb_mask<T>(min(count, m_bit_count));
|
return m_bit_buffer & lsb_mask<T>(min(count, m_bit_count));
|
||||||
}
|
}
|
||||||
|
@ -218,6 +231,7 @@ public:
|
||||||
ALWAYS_INLINE void discard_previously_peeked_bits(u8 count)
|
ALWAYS_INLINE void discard_previously_peeked_bits(u8 count)
|
||||||
{
|
{
|
||||||
// We allow "retrieving" more bits than we can provide, but we need to make sure that we don't underflow the current bit counter.
|
// We allow "retrieving" more bits than we can provide, but we need to make sure that we don't underflow the current bit counter.
|
||||||
|
// This only affects certain "modes", but all the relevant checks have been handled in the respective `peek_bits` call.
|
||||||
if (count > m_bit_count)
|
if (count > m_bit_count)
|
||||||
count = m_bit_count;
|
count = m_bit_count;
|
||||||
|
|
||||||
|
@ -240,8 +254,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorOr<void> refill_buffer_from_stream()
|
ErrorOr<bool> refill_buffer_from_stream()
|
||||||
{
|
{
|
||||||
|
if (m_stream->is_eof())
|
||||||
|
return false;
|
||||||
|
|
||||||
size_t bits_to_read = bit_buffer_size - m_bit_count;
|
size_t bits_to_read = bit_buffer_size - m_bit_count;
|
||||||
size_t bytes_to_read = bits_to_read / bits_per_byte;
|
size_t bytes_to_read = bits_to_read / bits_per_byte;
|
||||||
|
|
||||||
|
@ -251,8 +268,10 @@ private:
|
||||||
m_bit_buffer |= (buffer << m_bit_count);
|
m_bit_buffer |= (buffer << m_bit_count);
|
||||||
m_bit_count += bytes.size() * bits_per_byte;
|
m_bit_count += bytes.size() * bits_per_byte;
|
||||||
|
|
||||||
return {};
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnsatisfiableReadBehavior m_unsatisfiable_read_behavior;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A stream wrapper class that allows you to write arbitrary amounts of bits
|
/// A stream wrapper class that allows you to write arbitrary amounts of bits
|
||||||
|
|
|
@ -137,10 +137,30 @@ TEST_CASE(bit_reads_beyond_stream_limits)
|
||||||
Array<u8, 1> const test_data { 0xFF };
|
Array<u8, 1> const test_data { 0xFF };
|
||||||
|
|
||||||
{
|
{
|
||||||
// LittleEndianInputBitStream allows reading null bits beyond the original data
|
|
||||||
// for compatibility purposes.
|
|
||||||
auto memory_stream = make<FixedMemoryStream>(test_data);
|
auto memory_stream = make<FixedMemoryStream>(test_data);
|
||||||
auto bit_stream = make<LittleEndianInputBitStream>(move(memory_stream));
|
auto bit_stream = make<LittleEndianInputBitStream>(move(memory_stream), LittleEndianInputBitStream::UnsatisfiableReadBehavior::Reject);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
|
||||||
|
EXPECT_EQ(result, 0b111111);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bit_stream->read_bits<u8>(6);
|
||||||
|
EXPECT(result.is_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bit_stream->read_bits<u8>(6);
|
||||||
|
EXPECT(result.is_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// LittleEndianInputBitStream allows reading null bits beyond the original data
|
||||||
|
// for compatibility purposes if enabled.
|
||||||
|
auto memory_stream = make<FixedMemoryStream>(test_data);
|
||||||
|
auto bit_stream = make<LittleEndianInputBitStream>(move(memory_stream), LittleEndianInputBitStream::UnsatisfiableReadBehavior::FillWithZero);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
|
auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue