AK: Fix MemoryStream seek from end

The seek offset is still applied positively when seeking from the end;
see the Kernel's seek implementation.
This commit is contained in:
kleines Filmröllchen 2023-09-14 11:24:55 +02:00 committed by Andrew Kaster
parent 784ac6b9f2
commit 8bcf25561b
Notes: sideshowbarker 2024-07-16 23:57:20 +09:00
2 changed files with 98 additions and 2 deletions

View File

@ -81,10 +81,10 @@ ErrorOr<size_t> FixedMemoryStream::seek(i64 offset, SeekMode seek_mode)
m_offset += offset;
break;
case SeekMode::FromEndPosition:
if (offset > static_cast<i64>(m_bytes.size()))
if (-offset > static_cast<i64>(m_bytes.size()))
return Error::from_string_view_or_print_error_and_return_errno("Offset past the start of the stream memory"sv, EINVAL);
m_offset = m_bytes.size() - offset;
m_offset = m_bytes.size() + offset;
break;
}
return m_offset;

View File

@ -151,3 +151,99 @@ TEST_CASE(allocating_memory_stream_offset_of_with_write_offset_multiple_of_chunk
EXPECT_EQ(offset.value(), AllocatingMemoryStream::CHUNK_SIZE - 32 - 1);
}
}
TEST_CASE(fixed_memory_read_write)
{
constexpr auto some_words = "These are some words"sv;
auto empty = TRY_OR_FAIL(ByteBuffer::create_uninitialized(some_words.length()));
FixedMemoryStream stream { empty.bytes() };
ReadonlyBytes buffer { some_words.characters_without_null_termination(), some_words.length() };
TRY_OR_FAIL(stream.write_some(buffer));
EXPECT_EQ(TRY_OR_FAIL(stream.tell()), some_words.length());
EXPECT(stream.is_eof());
TRY_OR_FAIL(stream.seek(0));
auto contents = TRY_OR_FAIL(stream.read_until_eof());
EXPECT_EQ(contents.bytes(), some_words.bytes());
}
TEST_CASE(fixed_memory_close)
{
auto empty = TRY_OR_FAIL(ByteBuffer::create_uninitialized(64));
FixedMemoryStream stream { empty.bytes() };
EXPECT(stream.is_open());
stream.close();
EXPECT(stream.is_open());
}
TEST_CASE(fixed_memory_read_only)
{
constexpr auto some_words = "These are some words"sv;
FixedMemoryStream stream { ReadonlyBytes { some_words.bytes() } };
auto contents = TRY_OR_FAIL(stream.read_until_eof());
EXPECT_EQ(contents.bytes(), some_words.bytes());
TRY_OR_FAIL(stream.seek(0));
ReadonlyBytes buffer { some_words.characters_without_null_termination(), some_words.length() };
EXPECT_CRASH("Write protection assert", [&] {
(void)stream.write_some(buffer);
return Test::Crash::Failure::DidNotCrash;
});
EXPECT_EQ(TRY_OR_FAIL(stream.tell()), 0ull);
EXPECT(!stream.is_eof());
}
TEST_CASE(fixed_memory_seeking_around)
{
auto stream_buffer = TRY_OR_FAIL(ByteBuffer::create_uninitialized(8702ul));
FixedMemoryStream stream { ReadonlyBytes { stream_buffer.bytes() } };
auto buffer = TRY_OR_FAIL(ByteBuffer::create_uninitialized(16));
TRY_OR_FAIL(stream.seek(500, SeekMode::SetPosition));
EXPECT_EQ(stream.tell().release_value(), 500ul);
TRY_OR_FAIL(stream.read_until_filled(buffer));
TRY_OR_FAIL(stream.seek(234, SeekMode::FromCurrentPosition));
EXPECT_EQ(stream.tell().release_value(), 750ul);
TRY_OR_FAIL(stream.read_until_filled(buffer));
TRY_OR_FAIL(stream.seek(-105, SeekMode::FromEndPosition));
EXPECT_EQ(stream.tell().release_value(), 8597ul);
TRY_OR_FAIL(stream.read_until_filled(buffer));
}
BENCHMARK_CASE(fixed_memory_tell)
{
auto stream_buffer = TRY_OR_FAIL(ByteBuffer::create_uninitialized(10 * KiB));
FixedMemoryStream stream { ReadonlyBytes { stream_buffer.bytes() } };
auto expected_fixed_memory_offset = 0u;
auto ten_byte_buffer = TRY_OR_FAIL(ByteBuffer::create_uninitialized(1));
for (auto i = 0u; i < 4000; ++i) {
TRY_OR_FAIL(stream.read_until_filled(ten_byte_buffer));
expected_fixed_memory_offset += 1u;
EXPECT_EQ(expected_fixed_memory_offset, TRY_OR_FAIL(stream.tell()));
}
for (auto i = 0u; i < 4000; ++i) {
auto seek_fixed_memory_offset = TRY_OR_FAIL(stream.seek(-1, SeekMode::FromCurrentPosition));
expected_fixed_memory_offset -= 1;
EXPECT_EQ(seek_fixed_memory_offset, TRY_OR_FAIL(stream.tell()));
EXPECT_EQ(expected_fixed_memory_offset, TRY_OR_FAIL(stream.tell()));
}
}
TEST_CASE(fixed_memory_truncate)
{
auto stream_buffer = TRY_OR_FAIL(ByteBuffer::create_uninitialized(10 * KiB));
FixedMemoryStream stream { ReadonlyBytes { stream_buffer.bytes() } };
EXPECT(stream.truncate(999).is_error());
}