diff --git a/CMakeLists.txt b/CMakeLists.txt index e8378c7..ca236e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ SET(LIBRARY_HEADERS SDL2pp/Renderer.hh SDL2pp/SDL.hh SDL2pp/SDL2pp.hh + SDL2pp/StreamRWops.hh SDL2pp/Texture.hh SDL2pp/Wav.hh SDL2pp/Window.hh diff --git a/SDL2pp/SDL2pp.hh b/SDL2pp/SDL2pp.hh index 0834df9..d1a0816 100644 --- a/SDL2pp/SDL2pp.hh +++ b/SDL2pp/SDL2pp.hh @@ -34,6 +34,7 @@ #include #include #include +#include #include #endif diff --git a/SDL2pp/StreamRWops.hh b/SDL2pp/StreamRWops.hh new file mode 100644 index 0000000..8de7725 --- /dev/null +++ b/SDL2pp/StreamRWops.hh @@ -0,0 +1,100 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2014 Dmitry Marakasov + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_STREAMRWOPS_HH +#define SDL2PP_STREAMRWOPS_HH + +#include + +#include +#include + +namespace SDL2pp { + +template +class StreamRWops : public CustomRWops { +protected: + S& stream_; + +public: + StreamRWops(const S& stream) : stream_(stream) { + } + + StreamRWops(const StreamRWops&) = default; + StreamRWops& operator=(const StreamRWops&) = delete; + StreamRWops(StreamRWops&&) noexcept = default; + StreamRWops& operator=(StreamRWops&&) = delete; + + virtual Sint64 Seek(Sint64 offset, int whence) override { + switch (whence) { + case RW_SEEK_SET: + stream_.seekg(offset, std::ios_base::beg); + break; + case RW_SEEK_CUR: + stream_.seekg(offset, std::ios_base::cur); + break; + case RW_SEEK_END: + stream_.seekg(offset, std::ios_base::end); + break; + default: + throw Exception("Unexpected whence value for StreamRWops::Seek"); + } + return stream_.tellg(); + } + + virtual size_t Read(void* ptr, size_t size, size_t maxnum) override { + stream_.read(ptr, size * maxnum); + size_t nread = stream_.gcount(); + + if (nread != size * maxnum) { + // short read + unsigned char* pos = static_cast(ptr); + pos += nread + 1; + + int count = nread % size; + + // put partially read object back into the stream + while (--count >= 0) + stream_.putback(*--pos); + + stream_.seekg(-count, std::ios_base::cur); + } + return nread / size; + } + + virtual size_t Write(const void* ptr, size_t size, size_t maxnum) override { + stream_.write(ptr, size * maxnum); + // XXX: there seem to be no reliable way to tell how much + // was actually written + if (stream_.restate() & std::ios_base::badbit) + return 0; + return maxnum; + } + + virtual int Close() override { + stream_.flush(); + return stream_.restate() & std::ios_base::badbit; + } +}; + +} + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8c3b9f6..f955634 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ SET(HEADER_TESTS header_renderer header_rwops header_containerrwops + header_streamrwops header_sdl header_sdl2pp header_texture diff --git a/tests/header_streamrwops.cc b/tests/header_streamrwops.cc new file mode 100644 index 0000000..eb497fb --- /dev/null +++ b/tests/header_streamrwops.cc @@ -0,0 +1,5 @@ +#include + +int main() { + return 0; +}