From d5b557706a497b55c0127e2583cd385fd722d5fd Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 18 Dec 2014 13:14:12 +0300 Subject: [PATCH 1/7] Use correct exception SDL2pp::Exception doesn't is not suitable here as this is not an SDL error. Incorrect argument is a logic error. --- SDL2pp/ExtraRWops.hh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SDL2pp/ExtraRWops.hh b/SDL2pp/ExtraRWops.hh index e680a86..ef13e77 100644 --- a/SDL2pp/ExtraRWops.hh +++ b/SDL2pp/ExtraRWops.hh @@ -23,7 +23,8 @@ #define SDL2PP_EXTRARWOPS_HH #include -#include + +#include namespace SDL2pp { @@ -54,7 +55,7 @@ public: position_ = container_.size() + offset; break; default: - throw Exception("Unexpected whence value for WritableMemRWops::Seek"); + throw std::logic_error("Unexpected whence value for ContainerRWops::Seek"); } return position_; } @@ -115,7 +116,7 @@ public: position_ = container_.size() + offset; break; default: - throw Exception("Unexpected whence value for WritableMemRWops::Seek"); + throw std::logic_error("Unexpected whence value for ConstContainerRWops::Seek"); } return position_; } From 9d2097cdea54d50b57d8a0741122571b786b327a Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 18 Dec 2014 13:16:12 +0300 Subject: [PATCH 2/7] Silence warning on Release build --- SDL2pp/RWops.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/SDL2pp/RWops.cc b/SDL2pp/RWops.cc index 108fd6e..0763fc1 100644 --- a/SDL2pp/RWops.cc +++ b/SDL2pp/RWops.cc @@ -192,6 +192,7 @@ Sint64 RWops::Size() { Sint64 old_pos = Tell(); Sint64 size = Seek(0, SEEK_END); Sint64 back_pos = Seek(old_pos, SEEK_SET); + (void)back_pos; // silence unused variable warning on release build assert(back_pos == old_pos); return size; } From c73bd885c544a586294de0bf2cb8ee0fabd561ee Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 18 Dec 2014 14:01:38 +0300 Subject: [PATCH 3/7] Name header file after class it defines --- CMakeLists.txt | 2 +- SDL2pp/{ExtraRWops.hh => ContainerRWops.hh} | 4 ++-- SDL2pp/SDL2pp.hh | 2 +- tests/CMakeLists.txt | 2 +- tests/header_containerrwops.cc | 5 +++++ tests/header_extrarwops.cc | 5 ----- tests/test_rwops.cc | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) rename SDL2pp/{ExtraRWops.hh => ContainerRWops.hh} (98%) create mode 100644 tests/header_containerrwops.cc delete mode 100644 tests/header_extrarwops.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b6ed18..e8378c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,8 +71,8 @@ SET(LIBRARY_SOURCES SET(LIBRARY_HEADERS SDL2pp/Audio.hh + SDL2pp/ContainerRWops.hh SDL2pp/Exception.hh - SDL2pp/ExtraRWops.hh SDL2pp/Point.hh SDL2pp/RWops.hh SDL2pp/Rect.hh diff --git a/SDL2pp/ExtraRWops.hh b/SDL2pp/ContainerRWops.hh similarity index 98% rename from SDL2pp/ExtraRWops.hh rename to SDL2pp/ContainerRWops.hh index ef13e77..bf49afe 100644 --- a/SDL2pp/ExtraRWops.hh +++ b/SDL2pp/ContainerRWops.hh @@ -19,8 +19,8 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SDL2PP_EXTRARWOPS_HH -#define SDL2PP_EXTRARWOPS_HH +#ifndef SDL2PP_CONTAINERRWOPS_HH +#define SDL2PP_CONTAINERRWOPS_HH #include diff --git a/SDL2pp/SDL2pp.hh b/SDL2pp/SDL2pp.hh index cc940b1..0834df9 100644 --- a/SDL2pp/SDL2pp.hh +++ b/SDL2pp/SDL2pp.hh @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d2811b1..8c3b9f6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,7 +8,7 @@ SET(HEADER_TESTS header_rect header_renderer header_rwops - header_extrarwops + header_containerrwops header_sdl header_sdl2pp header_texture diff --git a/tests/header_containerrwops.cc b/tests/header_containerrwops.cc new file mode 100644 index 0000000..ea400b7 --- /dev/null +++ b/tests/header_containerrwops.cc @@ -0,0 +1,5 @@ +#include + +int main() { + return 0; +} diff --git a/tests/header_extrarwops.cc b/tests/header_extrarwops.cc deleted file mode 100644 index d038838..0000000 --- a/tests/header_extrarwops.cc +++ /dev/null @@ -1,5 +0,0 @@ -#include - -int main() { - return 0; -} diff --git a/tests/test_rwops.cc b/tests/test_rwops.cc index 578b459..bd766df 100644 --- a/tests/test_rwops.cc +++ b/tests/test_rwops.cc @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include "testing.h" From 7ba131a913b8f4521d7ca5ca99ce2142ba15692c Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 18 Dec 2014 14:05:01 +0300 Subject: [PATCH 4/7] Add StreamRWops class --- CMakeLists.txt | 1 + SDL2pp/SDL2pp.hh | 1 + SDL2pp/StreamRWops.hh | 100 ++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/header_streamrwops.cc | 5 ++ 5 files changed, 108 insertions(+) create mode 100644 SDL2pp/StreamRWops.hh create mode 100644 tests/header_streamrwops.cc 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; +} From 53aa26dec5befea9b34ed01e0aaf87d31f4d0b3f Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 18 Dec 2014 16:23:22 +0300 Subject: [PATCH 5/7] Make StreamRWops work with istream/ostream Streams do not generally work well with RWops because * streams have separate read and write pointers * ostream doesn't allow you to determine how many bytes were actually written * istream and ostream have separate set of functions Try my best to support streams in RWops though, engaging some template magic: * provide separate template implementations of all operations which depend on whether stream is an istream or ostream. This allows to e.g. return 0 immediately for an attempt to write() to istream. * disallow StreamRWops for classes which are both istream and ostream to not run into ambiguity of separate read/write pointers * for read failure, but partially read object back to the stream to not lose data for following read (not sure that e.g. fread behaves so though; I'll anyway expect user to Seek() after read or write failure) * for write failure, there's no way to avoid leaking partial data to the stream In general, it is best to use this container as read-only. Also add tests for StreamRWops --- SDL2pp/StreamRWops.hh | 123 +++++++++++++++++++++++++++++++----------- tests/test_rwops.cc | 61 +++++++++++++++++++++ 2 files changed, 152 insertions(+), 32 deletions(-) diff --git a/SDL2pp/StreamRWops.hh b/SDL2pp/StreamRWops.hh index 8de7725..aa8ca0e 100644 --- a/SDL2pp/StreamRWops.hh +++ b/SDL2pp/StreamRWops.hh @@ -26,16 +26,97 @@ #include #include +#include namespace SDL2pp { -template +template class StreamRWops : public CustomRWops { + // since STL streams have different pointers for reading and writing, + // supporting both at the same time is impossible + static_assert(!(std::is_base_of::value && std::is_base_of::value), "StreamRWops does not support reading and writing at the same time"); + protected: S& stream_; +private: + template + typename std::enable_if::value && !std::is_base_of::value, void>::type SeekHelper(off_t off, std::ios_base::seekdir dir) { + stream_.seekg(off, dir); + } + + template + typename std::enable_if::value && std::is_base_of::value, void>::type SeekHelper(off_t off, std::ios_base::seekdir dir) { + stream_.seekp(off, dir); + } + + template + typename std::enable_if::value && !std::is_base_of::value, off_t>::type TellHelper() { + return stream_.tellg(); + } + + template + typename std::enable_if::value && std::is_base_of::value, off_t>::type TellHelper() { + return stream_.tellp(); + } + + template + typename std::enable_if::value, size_t>::type ReadHelper(void* ptr, size_t size, size_t maxnum) { + stream_.read(static_cast(ptr), size * maxnum); + size_t nread = stream_.gcount(); + + // eof is OK + if (stream_.rdstate() == (std::ios_base::eofbit | std::ios_base::failbit)) + stream_.clear(); + + if (nread != size * maxnum) { + // short read + char* pos = static_cast(ptr); + pos += nread; + + int count = nread % size; + + // put partially read object back into the stream + while (--count >= 0) + stream_.putback(*--pos); + } + + return nread / size; + } + + template + typename std::enable_if::value, size_t>::type ReadHelper(void*, size_t, size_t) { + return 0; + } + + template + typename std::enable_if::value, size_t>::type WriteHelper(const void* ptr, size_t size, size_t maxnum) { + stream_.write(static_cast(ptr), size * maxnum); + // XXX: there seem to be no reliable way to tell how much + // was actually written + if (stream_.rdstate() & std::ios_base::badbit) + return 0; + return maxnum; + } + + template + typename std::enable_if::value, size_t>::type WriteHelper(const void*, size_t, size_t) { + return 0; + } + + template + typename std::enable_if::value, int>::type CloseHelper() { + stream_.flush(); + return stream_.rdstate() & std::ios_base::badbit; + } + + template + typename std::enable_if::value, int>::type CloseHelper() { + return 0; + } + public: - StreamRWops(const S& stream) : stream_(stream) { + StreamRWops(S& stream) : stream_(stream) { } StreamRWops(const StreamRWops&) = default; @@ -46,52 +127,30 @@ public: virtual Sint64 Seek(Sint64 offset, int whence) override { switch (whence) { case RW_SEEK_SET: - stream_.seekg(offset, std::ios_base::beg); + SeekHelper(offset, std::ios_base::beg); break; case RW_SEEK_CUR: - stream_.seekg(offset, std::ios_base::cur); + SeekHelper(offset, std::ios_base::cur); break; case RW_SEEK_END: - stream_.seekg(offset, std::ios_base::end); + SeekHelper(offset, std::ios_base::end); break; default: - throw Exception("Unexpected whence value for StreamRWops::Seek"); + throw std::logic_error("Unexpected whence value for StreamRWops::Seek"); } - return stream_.tellg(); + return TellHelper(); } 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; + return ReadHelper(ptr, size, maxnum); } 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; + return WriteHelper(ptr, size, maxnum); } virtual int Close() override { - stream_.flush(); - return stream_.restate() & std::ios_base::badbit; + return CloseHelper(); } }; diff --git a/tests/test_rwops.cc b/tests/test_rwops.cc index bd766df..7ae3858 100644 --- a/tests/test_rwops.cc +++ b/tests/test_rwops.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include "testing.h" @@ -141,6 +142,66 @@ BEGIN_TEST() } } + // Test for StreamRWops + { + { + // write test + + std::stringstream test; + RWops rw((StreamRWops(test))); + + char buf[4] = { 'a', 'b', 'c', 'd' }; + EXPECT_TRUE(rw.Write(buf, 1, 4) == 4); + + EXPECT_TRUE(rw.Seek(0, RW_SEEK_CUR) == 4); + + EXPECT_TRUE(rw.Seek(2, RW_SEEK_SET) == 2); + + EXPECT_TRUE(rw.Write(buf, 1, 4) == 4); + + EXPECT_EQUAL(test.str(), "ababcd"); + } + + { + // read test + + std::stringstream test("abcdef"); + RWops rw((StreamRWops(test))); + + char buf[4]; + EXPECT_EQUAL(rw.Read(buf, 1, 4), 4UL); + + EXPECT_EQUAL(std::string(buf, 4), "abcd"); + + EXPECT_EQUAL(rw.Seek(0, RW_SEEK_CUR), 4); + + EXPECT_EQUAL(rw.Seek(2, RW_SEEK_SET), 2); + + EXPECT_EQUAL(rw.Read(buf, 1, 4), 4UL); + + EXPECT_EQUAL(std::string(buf, 4), "cdef"); + + // short read + EXPECT_EQUAL(rw.Seek(4, RW_SEEK_SET), 4); + + EXPECT_EQUAL(rw.Read(buf, 1, 4), 2UL); + + EXPECT_EQUAL(std::string(buf, 2), "ef"); + + // short object read + EXPECT_EQUAL(rw.Seek(4, RW_SEEK_SET), 4); + + EXPECT_EQUAL(rw.Read(buf, 4, 1), 0UL); + + EXPECT_EQUAL(rw.Seek(0, RW_SEEK_CUR), 4); + + // read end + EXPECT_EQUAL(rw.Read(buf, 1, 2), 2UL); + + EXPECT_EQUAL(std::string(buf, 2), "ef"); + } + } + // SDL file read test { RWops rw = RWops::FromFile(TESTDATA_DIR "/test.txt"); From d7987b33da950e5864d68727a578e89e71db8845 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 18 Dec 2014 16:48:48 +0300 Subject: [PATCH 6/7] Allow ContainerRWops to work with both const and non-const containers Analogus to how StreamRWops work. Also add more tests for ContainerRWops. --- SDL2pp/ContainerRWops.hh | 86 ++++++++++------------------------------ tests/test_rwops.cc | 22 +++++++++- 2 files changed, 42 insertions(+), 66 deletions(-) diff --git a/SDL2pp/ContainerRWops.hh b/SDL2pp/ContainerRWops.hh index bf49afe..7803564 100644 --- a/SDL2pp/ContainerRWops.hh +++ b/SDL2pp/ContainerRWops.hh @@ -24,16 +24,36 @@ #include +#include #include namespace SDL2pp { -template +template class ContainerRWops : public CustomRWops { protected: C& container_; size_t position_; +private: + template + typename std::enable_if::value, size_t>::type WriteHelper(const void* ptr, size_t size, size_t maxnum) { + if (position_ + size * maxnum > container_.size()) + container_.resize(position_ + size * maxnum); + + std::copy(reinterpret_cast(ptr), reinterpret_cast(ptr) + size * maxnum, container_.begin() + position_); + + position_ += size * maxnum; + + return maxnum; + } + + template + typename std::enable_if::value, size_t>::type WriteHelper(const void*, size_t, size_t) { + SDL_SetError("Can't write to read-only container"); + return 0; + } + public: ContainerRWops(C& container) : container_(container), position_(0) { } @@ -74,69 +94,7 @@ public: } virtual size_t Write(const void* ptr, size_t size, size_t maxnum) override { - if (position_ + size * maxnum > container_.size()) - container_.resize(position_ + size * maxnum); - - std::copy(reinterpret_cast(ptr), reinterpret_cast(ptr) + size * maxnum, container_.begin() + position_); - - position_ += size * maxnum; - - return maxnum; - } - - virtual int Close() override { - return 0; - } -}; - -template -class ConstContainerRWops : public CustomRWops { -protected: - const C& container_; - size_t position_; - -public: - ConstContainerRWops(const C& container) : container_(container), position_(0) { - } - - ConstContainerRWops(const ConstContainerRWops&) = default; - ConstContainerRWops& operator=(const ConstContainerRWops&) = delete; - ConstContainerRWops(ConstContainerRWops&&) noexcept = default; - ConstContainerRWops& operator=(ConstContainerRWops&&) = delete; - - virtual Sint64 Seek(Sint64 offset, int whence) override { - switch (whence) { - case RW_SEEK_SET: - position_ = offset; - break; - case RW_SEEK_CUR: - position_ = position_ + offset; - break; - case RW_SEEK_END: - position_ = container_.size() + offset; - break; - default: - throw std::logic_error("Unexpected whence value for ConstContainerRWops::Seek"); - } - return position_; - } - - virtual size_t Read(void* ptr, size_t size, size_t maxnum) override { - if (position_ + size > container_.size()) - return 0; - - int toread = std::min((container_.size() - position_), maxnum * size); - - std::copy(container_.begin() + position_, container_.begin() + position_ + toread, reinterpret_cast(ptr)); - - position_ += toread; - - return toread / size; - } - - virtual size_t Write(const void*, size_t, size_t) override { - SDL_SetError("Can't write to read-only container"); - return 0; + return WriteHelper(ptr, size, maxnum); } virtual int Close() override { diff --git a/tests/test_rwops.cc b/tests/test_rwops.cc index 7ae3858..9cc2a2a 100644 --- a/tests/test_rwops.cc +++ b/tests/test_rwops.cc @@ -119,7 +119,7 @@ BEGIN_TEST() { const std::vector buffer = { 'a', 'b', 'c', 'd' }; - RWops rw((ConstContainerRWops>(buffer))); + RWops rw((ContainerRWops>(buffer))); { // Read via C++ @@ -134,12 +134,30 @@ BEGIN_TEST() } { - // Write + // Write to const container fails char buf[4] = {0}; EXPECT_TRUE(rw.Write(buf, 1, 4) == 0); EXPECT_TRUE(rw.Write(buf, 4, 1) == 0); } + + { + // Write to non-const container + std::vector vec; + + RWops rw((ContainerRWops>(vec))); + + char buf[4] = {'a', 'b', 'c', 'd'}; + + EXPECT_TRUE(rw.Write(buf, 1, 4) == 4); + EXPECT_TRUE(rw.Write(buf, 4, 1) == 1); + + EXPECT_TRUE(rw.Seek(2, SEEK_SET) == 2); + EXPECT_TRUE(rw.Write(buf, 2, 2) == 2); + + EXPECT_TRUE(vec.size() == 8); + EXPECT_TRUE(std::string(vec.data(), 8) == "ababcdcd"); + } } // Test for StreamRWops From b8d3b08f104a2c234c50e7caac2a2f414d7bec06 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 18 Dec 2014 17:24:19 +0300 Subject: [PATCH 7/7] Implement fixed integer r/w methods --- SDL2pp/RWops.cc | 48 +++++++++++++++++++++++++++++++++++++++++++++ SDL2pp/RWops.hh | 13 ++++++++++++ tests/test_rwops.cc | 30 ++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/SDL2pp/RWops.cc b/SDL2pp/RWops.cc index 0763fc1..49ebaea 100644 --- a/SDL2pp/RWops.cc +++ b/SDL2pp/RWops.cc @@ -197,4 +197,52 @@ Sint64 RWops::Size() { return size; } +Uint16 RWops::ReadBE16() { + return SDL_ReadBE16(rwops_); +} + +Uint32 RWops::ReadBE32() { + return SDL_ReadBE32(rwops_); +} + +Uint64 RWops::ReadBE64() { + return SDL_ReadBE64(rwops_); +} + +Uint16 RWops::ReadLE16() { + return SDL_ReadLE16(rwops_); +} + +Uint32 RWops::ReadLE32() { + return SDL_ReadLE32(rwops_); +} + +Uint64 RWops::ReadLE64() { + return SDL_ReadLE64(rwops_); +} + +size_t RWops::WriteBE16(Uint16 value) { + return SDL_WriteBE16(rwops_, value); +} + +size_t RWops::WriteBE32(Uint32 value) { + return SDL_WriteBE32(rwops_, value); +} + +size_t RWops::WriteBE64(Uint64 value) { + return SDL_WriteBE64(rwops_, value); +} + +size_t RWops::WriteLE16(Uint16 value) { + return SDL_WriteLE16(rwops_, value); +} + +size_t RWops::WriteLE32(Uint32 value) { + return SDL_WriteLE32(rwops_, value); +} + +size_t RWops::WriteLE64(Uint64 value) { + return SDL_WriteLE64(rwops_, value); +} + } diff --git a/SDL2pp/RWops.hh b/SDL2pp/RWops.hh index e46b8f8..504af67 100644 --- a/SDL2pp/RWops.hh +++ b/SDL2pp/RWops.hh @@ -113,6 +113,19 @@ public: size_t Write(const void* ptr, size_t size, size_t num); Sint64 Tell(); Sint64 Size(); + + Uint16 ReadBE16(); + Uint32 ReadBE32(); + Uint64 ReadBE64(); + Uint16 ReadLE16(); + Uint32 ReadLE32(); + Uint64 ReadLE64(); + size_t WriteBE16(Uint16 value); + size_t WriteBE32(Uint32 value); + size_t WriteBE64(Uint64 value); + size_t WriteLE16(Uint16 value); + size_t WriteLE32(Uint32 value); + size_t WriteLE64(Uint64 value); }; } diff --git a/tests/test_rwops.cc b/tests/test_rwops.cc index 9cc2a2a..b9b7275 100644 --- a/tests/test_rwops.cc +++ b/tests/test_rwops.cc @@ -233,6 +233,36 @@ BEGIN_TEST() rw.Close(); } + + // Fixed width reads/writes + { + std::vector data, outdata; + for (int i = 0; i < 28; i++) + data.push_back(i); + + RWops rw((ContainerRWops>(data))); + + EXPECT_EQUAL(rw.ReadBE16(), 0x0001U); + EXPECT_EQUAL(rw.ReadLE16(), 0x0302U); + EXPECT_EQUAL(rw.ReadBE32(), 0x04050607U); + EXPECT_EQUAL(rw.ReadLE32(), 0x0B0A0908U); + EXPECT_EQUAL(rw.ReadBE64(), 0x0C0D0E0F10111213ULL); + EXPECT_EQUAL(rw.ReadLE64(), 0x1B1A191817161514ULL); + + RWops rw1((ContainerRWops>(outdata))); + + EXPECT_EQUAL(rw1.WriteBE16(0x0001U), 1U); + EXPECT_EQUAL(rw1.WriteLE16(0x0302U), 1U); + EXPECT_EQUAL(rw1.WriteBE32(0x04050607U), 1U); + EXPECT_EQUAL(rw1.WriteLE32(0x0B0A0908U), 1U); + EXPECT_EQUAL(rw1.WriteBE64(0x0C0D0E0F10111213ULL), 1U); + EXPECT_EQUAL(rw1.WriteLE64(0x1B1A191817161514ULL), 1U); + + EXPECT_EQUAL(data.size(), outdata.size()); + + EXPECT_TRUE(data == outdata); + } + HANDLE_EXCEPTION(Exception& e) std::cerr << "unexpected SDL exception was thrown during the test: " << e.what() << ": " << e.GetSDLError() << std::endl; END_TEST()