diff --git a/ostd/ext/sdl_rwops.hh b/ostd/ext/sdl_rwops.hh index 328dc99..c07f2ac 100644 --- a/ostd/ext/sdl_rwops.hh +++ b/ostd/ext/sdl_rwops.hh @@ -12,19 +12,18 @@ #include #endif -#include "ostd/types.hh" #include "ostd/stream.hh" namespace ostd { namespace sdl { #ifdef OSTD_EXT_SDL_USE_SDL1 -using SDLRWopsOffset = int; +using sdl_rwops_off_t = int; #else -using SDLRWopsOffset = int64_t; +using sdl_rwops_off_t = int64_t; #endif -inline SDL_RWops *stream_to_rwops(Stream &s) { +inline SDL_RWops *stream_to_rwops(stream &s) { SDL_RWops *rwr = SDL_AllocRW(); if (!rwr) { return nullptr; @@ -32,32 +31,52 @@ inline SDL_RWops *stream_to_rwops(Stream &s) { rwr->hidden.unknown.data1 = &s; - rwr->size = [](SDL_RWops *rw) -> SDLRWopsOffset { - Stream *is = static_cast(rw->hidden.unknown.data1); - return static_cast(is->size()); + rwr->size = [](SDL_RWops *rw) -> sdl_rwops_off_t { + auto &is = *static_cast(rw->hidden.unknown.data1); + try { + return static_cast(is.size()); + } catch (stream_error const &) { + return -1; + } }; - rwr->seek = [](SDL_RWops *rw, SDLRWopsOffset pos, int whence) -> - SDLRWopsOffset + rwr->seek = [](SDL_RWops *rw, sdl_rwops_off_t pos, int whence) -> + sdl_rwops_off_t { - Stream *is = static_cast(rw->hidden.unknown.data1); - if (!pos && whence == SEEK_CUR) { - return static_cast(is->tell()); - } - if (is->seek(((StreamOffset)pos, (StreamSeek)whence)) { - return static_cast(is->tell()); + auto &is = *static_cast(rw->hidden.unknown.data1); + try { + if (!pos && whence == SEEK_CUR) { + return static_castseek((stream_off_t(pos), stream_seek(whence)))) { + return static_cast(is.tell()); + } + } catch (stream_error const &) { + return -1; } return -1; }; - rwr->read = [](SDL_RWops *rw, void *buf, size_t size, size_t nb) -> size_t { - Stream *is = static_cast(rw->hidden.unknown.data1); - return is->read_bytes(buf, size * nb) / size; + rwr->read = [](SDL_RWops *rw, void *buf, size_t size, size_t nb) -> + size_t + { + auto &is = *static_cast(rw->hidden.unknown.data1); + try { + return is.read_bytes(buf, size * nb) / size; + } catch (stream_error const &) { + return 0; + } }; - rwr->write = [](SDL_RWops *rw, const void *buf, size_t size, size_t nb) -> size_t { - Stream *is = static_cast(rw->hidden.unknown.data1); - return is->write_bytes(buf, size * nb) / size; + rwr->write = [](SDL_RWops *rw, void const *buf, size_t size, size_t nb) -> + size_t + { + stream &is = *static_cast(rw->hidden.unknown.data1); + try { + return is->write_bytes(buf, size * nb) / size; + } catch (stream_error const &) { + return 0; + } }; rwr->close = [](SDL_RWops *) -> int { diff --git a/ostd/io.hh b/ostd/io.hh index 9f4d7d3..b631e39 100644 --- a/ostd/io.hh +++ b/ostd/io.hh @@ -61,7 +61,7 @@ struct OSTD_EXPORT file_stream: stream { void flush(); - void read_bytes(void *buf, size_t count); + size_t read_bytes(void *buf, size_t count); void write_bytes(void const *buf, size_t count); int get_char(); diff --git a/ostd/stream.hh b/ostd/stream.hh index 0cef044..3522bd3 100644 --- a/ostd/stream.hh +++ b/ostd/stream.hh @@ -6,6 +6,7 @@ #ifndef OSTD_STREAM_HH #define OSTD_STREAM_HH +#include #include #include #include @@ -66,18 +67,30 @@ struct stream { return e; } - virtual void seek(offset_type, stream_seek = stream_seek::SET) {} + virtual void seek(offset_type, stream_seek = stream_seek::SET) { + throw stream_error{EINVAL, std::generic_category()}; + } - virtual offset_type tell() const { return -1; } + virtual offset_type tell() const { + throw stream_error{EINVAL, std::generic_category()}; + } - virtual void flush() {} + virtual void flush() { + throw stream_error{EINVAL, std::generic_category()}; + } - virtual void read_bytes(void *, size_t) {} - virtual void write_bytes(void const *, size_t) {} + virtual size_t read_bytes(void *, size_t) { + throw stream_error{EINVAL, std::generic_category()}; + } + virtual void write_bytes(void const *, size_t) { + throw stream_error{EINVAL, std::generic_category()}; + } virtual int get_char() { unsigned char c; - read_bytes(&c, 1); + if (!read_bytes(&c, 1)) { + throw stream_error{EIO, std::generic_category()}; + } return c; } @@ -150,13 +163,16 @@ struct stream { } template - void get(T *v, size_t count) { - read_bytes(v, count * sizeof(T)); + size_t get(T *v, size_t count) { + /* if eof was reached, at least return how many values succeeded */ + return read_bytes(v, count * sizeof(T)) / sizeof(T); } template void get(T &v) { - read_bytes(&v, sizeof(T)); + if (read_bytes(&v, sizeof(T)) != sizeof(T)) { + throw stream_error{EIO, std::generic_category()}; + } } template diff --git a/src/io.cc b/src/io.cc index 8917d51..2b9e250 100644 --- a/src/io.cc +++ b/src/io.cc @@ -84,10 +84,15 @@ void file_stream::flush() { } } -void file_stream::read_bytes(void *buf, size_t count) { - if (std::fread(buf, 1, count, p_f) != count) { +size_t file_stream::read_bytes(void *buf, size_t count) { + size_t readn = std::fread(buf, 1, count, p_f); + if (readn != count) { + if (std::feof(p_f) != 0) { + return readn; + } throw stream_error{EIO, std::generic_category()}; } + return readn; } void file_stream::write_bytes(void const *buf, size_t count) {