#include #include #include namespace euler { file_stream::file_stream( syscall::stream_handle handle, bool may_read, uint64_t length, uint64_t position) : handle(handle), may_read(may_read), buffer_loaded(false), length(length), position(position) {} syscall::stream_result file_stream::seek( syscall::seek_from from, int64_t offset) { int64_t new_position = offset + (from == syscall::seek_from::beginning ? 0 : from == syscall::seek_from::end ? length : position); if (new_position < 0 || (uint64_t)new_position > length) return syscall::stream_result::out_of_bounds; position = new_position; return syscall::stream_result::success; } std::pair file_stream::read(uint64_t bytes, void *into) { if (!may_read) return {0, syscall::stream_result::not_readable}; uint64_t have_read = 0; syscall::stream_result result = syscall::stream_result::success; uint64_t end = position + bytes; if (end > length) { end = length; result = syscall::stream_result::out_of_bounds; } uint64_t block_start = (position / 1024) * 1024; while (position < end) { uint64_t length_in_this_block = std::min(end, block_start + 1024) - position; if (buffer_loaded && buffer_start == block_start) memcpy(into, buffer + position - block_start, length_in_this_block); else if (length_in_this_block == 1024) { syscall::stream_result seek_result = syscall::seek_stream( handle, syscall::seek_from::beginning, block_start); if (seek_result != syscall::stream_result::success) return {have_read, seek_result}; syscall::stream_result read_result = syscall::read_from_stream(handle, 1024, into); if (read_result != syscall::stream_result::success) return {have_read, read_result}; } else { syscall::stream_result seek_result = syscall::seek_stream( handle, syscall::seek_from::beginning, block_start); if (seek_result != syscall::stream_result::success) return {have_read, seek_result}; uint64_t buffer_length = std::min(1024UL, length - block_start); syscall::stream_result read_result = syscall::read_from_stream(handle, buffer_length, buffer); if (read_result != syscall::stream_result::success) { buffer_loaded = false; return {have_read, read_result}; } buffer_loaded = true; buffer_start = block_start; memcpy(into, buffer + position - block_start, length_in_this_block); } into = (uint8_t *)into + length_in_this_block; have_read += length_in_this_block; position += length_in_this_block; block_start += 1024; } return {have_read, result}; } void file_stream::close() { syscall::close_stream(handle); } }