diff options
Diffstat (limited to 'euler/source/stream.cpp')
-rw-r--r-- | euler/source/stream.cpp | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/euler/source/stream.cpp b/euler/source/stream.cpp new file mode 100644 index 0000000..faf2907 --- /dev/null +++ b/euler/source/stream.cpp @@ -0,0 +1,106 @@ +#include <euler/stream.hpp> +#include <cstring> + +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<uint64_t, syscall::stream_result> + 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); + } + +} |