summaryrefslogtreecommitdiff
path: root/euler/source/stream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'euler/source/stream.cpp')
-rw-r--r--euler/source/stream.cpp106
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);
+ }
+
+}