diff --git a/SDL2pp/ExtraRWops.hh b/SDL2pp/ExtraRWops.hh index 3d682cd..a3205a4 100644 --- a/SDL2pp/ExtraRWops.hh +++ b/SDL2pp/ExtraRWops.hh @@ -88,6 +88,61 @@ public: } }; +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&) = default; + ConstContainerRWops(ConstContainerRWops&&) = default; + ConstContainerRWops& operator=(ConstContainerRWops&&) = default; + + 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 Exception("Unexpected whence value for WritableMemRWops::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; + } + + virtual int Close() override { + return 0; + } +}; + } #endif diff --git a/tests/test_rwops.cc b/tests/test_rwops.cc index 67e7036..578b459 100644 --- a/tests/test_rwops.cc +++ b/tests/test_rwops.cc @@ -114,6 +114,33 @@ BEGIN_TEST() } } + // Short test for ContainerRWops + { + const std::vector buffer = { 'a', 'b', 'c', 'd' }; + + RWops rw((ConstContainerRWops>(buffer))); + + { + // Read via C++ + EXPECT_TRUE(rw.Seek(0, SEEK_SET) == 0); + + char buf[4] = {0}; + EXPECT_TRUE(rw.Read(buf, 1, 4) == 4); + EXPECT_TRUE(buf[0] == 'a' && buf[3] == 'd'); + + // Position after read + EXPECT_TRUE(rw.Tell() == 4); + } + + { + // Write + char buf[4] = {0}; + + EXPECT_TRUE(rw.Write(buf, 1, 4) == 0); + EXPECT_TRUE(rw.Write(buf, 4, 1) == 0); + } + } + // SDL file read test { RWops rw = RWops::FromFile(TESTDATA_DIR "/test.txt");