diff options
Diffstat (limited to 'euler/source/euler/stream.cpp')
-rw-r--r-- | euler/source/euler/stream.cpp | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/euler/source/euler/stream.cpp b/euler/source/euler/stream.cpp new file mode 100644 index 0000000..950f3c5 --- /dev/null +++ b/euler/source/euler/stream.cpp @@ -0,0 +1,151 @@ +#include <euler/stream.hpp> +#include <cstring> + +namespace euler { + + stream::~stream() {} + + void file_stream::write_buffer() { + if (__euler_write_to_stream(handle, buffer_size, buffer) + != __EULER_SR_SUCCESS) + good = false;//TODO: more precise error reporting + else + buffer_dirty = false; + } + + file_stream::file_stream( + __euler_stream_handle handle, bool is_readable, bool is_writable, + bool clear, bool seek_to_end) + + : handle(handle), is_readable(is_readable), is_writable(is_writable), + buffer(0), good(true) { + + if (clear) { + if (__euler_set_stream_length(handle, 0) != __EULER_SR_SUCCESS) { + good = false; + return; + } + length = 0; + } + + else if (__euler_get_stream_length(handle, length) != __EULER_SR_SUCCESS) { + good = false; + return; + } + + if (seek_to_end) { + if (__euler_seek_stream(handle, __EULER_SF_END, 0) + != __EULER_SR_SUCCESS) { + good = false; + return; + } + offset = length; + } + + else + offset = 0; + + } + + file_stream::~file_stream() { + if (buffer) { + if (buffer_dirty) + write_buffer(); + delete[] buffer; + } + __euler_close_stream(handle); + } + + bool file_stream::try_read(void *into, uint64_t bytes) { + + if (bytes == 0) + return true; + + if (offset + bytes > length) + return false; + + if (buffer) { + uint64_t start = offset > buffer_offset ? offset : buffer_offset; + uint64_t end = offset + bytes < buffer_offset + buffer_size + ? offset + bytes : buffer_offset + buffer_size; + if (end > start) { + + uint64_t real_end = offset + bytes; + + std::memcpy( + (uint8_t *)into + start - offset, buffer + start - buffer_offset, + end - start); + if (start != offset) + if (!try_read(into, start - offset)) + return false; + + if (end != real_end) { + if (!try_seek(__EULER_SF_BEGINNING, end)) + return false; + if (!try_read((uint8_t *)into + end, real_end - end)) + return false; + } + + else if (offset != real_end) + if (!try_seek(__EULER_SF_BEGINNING, real_end)) + return false; + + return true; + + } + } + + if (buffer_dirty) { + write_buffer(); + if (!good) + return false; + } + + //1024 is arbitrary + buffer_size = length - offset < 1024 ? length - offset : 1024; + + if (buffer != 0) + delete[] buffer; + + buffer = new uint8_t[buffer_size]; + buffer_dirty = false; + buffer_offset = offset; + + if (__euler_read_from_stream(handle, buffer_size, buffer) + != __EULER_SR_SUCCESS) { + delete[] buffer; + buffer = 0; + return false; + } + + uint64_t read_this_buffer = buffer_size < bytes ? buffer_size : bytes; + std::memcpy(into, buffer, read_this_buffer); + offset += read_this_buffer; + + if (read_this_buffer == bytes) + return true; + + return try_read( + (uint8_t *)into + read_this_buffer, bytes - read_this_buffer); + + } + + bool file_stream::try_seek(__euler_seek_from from, int64_t offset) { + if (__euler_seek_stream(handle, from, offset) != __EULER_SR_SUCCESS) + return false; + switch (from) { + case __EULER_SF_BEGINNING: + this->offset = offset; + return true; + case __EULER_SF_END: + this->offset = length + offset; + return true; + case __EULER_SF_CURRENT_POSITION: + this->offset += offset; + return true; + default: + return false; + } + } + +} |