From c9a135799404fc0f440e732e8357f9fb133a08c5 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 12:04:12 +0100 Subject: [PATCH] add new MemoryStream class --- openrct2.vcxproj | 3 +- src/core/FileStream.hpp | 5 - src/core/IDisposable.hpp | 27 ------ src/core/IStream.hpp | 6 +- src/core/MemoryStream.cpp | 186 ++++++++++++++++++++++++++++++++++++++ src/core/MemoryStream.h | 68 ++++++++++++++ 6 files changed, 258 insertions(+), 37 deletions(-) delete mode 100644 src/core/IDisposable.hpp create mode 100644 src/core/MemoryStream.cpp create mode 100644 src/core/MemoryStream.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 9fec386430..641b84d74f 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -45,6 +45,7 @@ + @@ -345,12 +346,12 @@ - + diff --git a/src/core/FileStream.hpp b/src/core/FileStream.hpp index dce4ee866c..9a0bca777d 100644 --- a/src/core/FileStream.hpp +++ b/src/core/FileStream.hpp @@ -67,11 +67,6 @@ public: } ~FileStream() - { - Dispose(); - } - - void Dispose() override { if (!_disposed) { diff --git a/src/core/IDisposable.hpp b/src/core/IDisposable.hpp deleted file mode 100644 index 7a0492f877..0000000000 --- a/src/core/IDisposable.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers -/***************************************************************************** - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * OpenRCT2 is the work of many authors, a full list can be found in contributors.md - * For more information, visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * A full copy of the GNU General Public License can be found in licence.txt - *****************************************************************************/ -#pragma endregion - -#pragma once - -#include "../common.h" - -/** - * Represents an object that can be disposed. So things can explicitly close resources before the destructor kicks in. - */ -interface IDisposable -{ - virtual void Dispose() abstract; -}; diff --git a/src/core/IStream.hpp b/src/core/IStream.hpp index 9f85e1b229..577f1d29e8 100644 --- a/src/core/IStream.hpp +++ b/src/core/IStream.hpp @@ -17,9 +17,7 @@ #pragma once #include "../common.h" - #include "Exception.hpp" -#include "IDisposable.hpp" enum { STREAM_SEEK_BEGIN, @@ -30,12 +28,12 @@ enum { /** * Represents a stream that can be read or written to. Implemented by types such as FileStream, NetworkStream or MemoryStream. */ -interface IStream : public IDisposable +interface IStream { /////////////////////////////////////////////////////////////////////////// // Interface methods /////////////////////////////////////////////////////////////////////////// - // virtual ~IStream() abstract; + virtual ~IStream() { } virtual bool CanRead() const abstract; virtual bool CanWrite() const abstract; diff --git a/src/core/MemoryStream.cpp b/src/core/MemoryStream.cpp new file mode 100644 index 0000000000..2e6d46f525 --- /dev/null +++ b/src/core/MemoryStream.cpp @@ -0,0 +1,186 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "Math.hpp" +#include "Memory.hpp" +#include "MemoryStream.h" + +MemoryStream::MemoryStream() +{ + _access = MEMORY_ACCESS_READ | + MEMORY_ACCESS_WRITE | + MEMORY_ACCESS_OWNER; + _dataCapacity = 0; + _dataSize = 0; + _data = nullptr; + _position = nullptr; +} + +MemoryStream::MemoryStream(const MemoryStream ©) +{ + _access = copy._access; + _dataCapacity = copy._dataCapacity; + _dataSize = copy._dataSize; + + if (_access == MEMORY_ACCESS_OWNER) + { + _data = Memory::Duplicate(copy._data, _dataCapacity); + _position = (void*)((uintptr_t)_data + copy.GetPosition()); + } +} + +MemoryStream::MemoryStream(size_t capacity) +{ + _access = MEMORY_ACCESS_READ | + MEMORY_ACCESS_WRITE | + MEMORY_ACCESS_OWNER; + _dataCapacity = capacity; + _dataSize = 0; + _data = Memory::Allocate(capacity); + _position = _data; +} + +MemoryStream::MemoryStream(void * data, size_t dataSize, MEMORY_ACCESS access) +{ + _access = access; + _dataCapacity = dataSize; + _dataSize = dataSize; + _data = data; + _position = _data; +} + +MemoryStream::MemoryStream(const void * data, size_t dataSize) + : MemoryStream((void *)data, dataSize, MEMORY_ACCESS_READ) +{ +} + +MemoryStream::~MemoryStream() +{ + if (MEMORY_ACCESS_OWNER) + { + Memory::Free(_data); + } + _dataCapacity = 0; + _dataSize = 0; + _data = nullptr; +} + +void * MemoryStream::GetData() const +{ + return Memory::Duplicate(_data, _dataSize); +} + +void * MemoryStream::TakeData() +{ + _access &= ~MEMORY_ACCESS_OWNER; + return _data; +} + +bool MemoryStream::CanRead() const +{ + return (_access & MEMORY_ACCESS_READ) != 0; +} + +bool MemoryStream::CanWrite() const +{ + return (_access & MEMORY_ACCESS_WRITE) != 0; +} + +uint64 MemoryStream::GetLength() const +{ + return _dataSize; +} + +uint64 MemoryStream::GetPosition() const +{ + return (uint64)((uintptr_t)_position - (uintptr_t)_data); +} + +void MemoryStream::SetPosition(uint64 position) +{ + Seek(position, STREAM_SEEK_BEGIN); +} + +void MemoryStream::Seek(sint64 offset, int origin) +{ + uint64 newPosition; + switch (origin) { + default: + case STREAM_SEEK_BEGIN: + newPosition = offset; + break; + case STREAM_SEEK_CURRENT: + newPosition = GetPosition() + offset; + break; + case STREAM_SEEK_END: + newPosition = _dataSize + offset; + break; + } + + if (newPosition > _dataSize) + { + throw IOException("New position out of bounds."); + } + _position = (void*)((uintptr_t)_data + (uintptr_t)newPosition); +} + +void MemoryStream::Read(void * buffer, uint64 length) +{ + uint64 position = GetPosition(); + if (position + length > _dataSize) + { + throw IOException("Attempted to read past end of stream."); + } + + Memory::Copy(buffer, _position, (size_t)length); + _position = (void*)((uintptr_t)_position + length); +} + +void MemoryStream::Write(const void * buffer, uint64 length) +{ + uint64 position = GetPosition(); + uint64 nextPosition = position + length; + if (nextPosition > _dataCapacity) + { + if (_access & MEMORY_ACCESS_OWNER) + { + EnsureCapacity((size_t)nextPosition); + } + else + { + throw IOException("Attempted to write past end of stream."); + } + } + + Memory::Copy(_position, buffer, (size_t)length); + _position = (void*)((uintptr_t)_position + length); + _dataSize = Math::Max(_dataSize, (size_t)nextPosition); +} + +void MemoryStream::EnsureCapacity(size_t capacity) +{ + if (_dataCapacity < capacity) + { + size_t newCapacity = Math::Max(8, _dataCapacity); + while (newCapacity < capacity) + { + newCapacity *= 2; + } + + _dataCapacity = newCapacity; + Memory::Reallocate(_data, _dataCapacity); + } +} diff --git a/src/core/MemoryStream.h b/src/core/MemoryStream.h new file mode 100644 index 0000000000..c7a2a0763b --- /dev/null +++ b/src/core/MemoryStream.h @@ -0,0 +1,68 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" +#include "IStream.hpp" + +enum MEMORY_ACCESS +{ + MEMORY_ACCESS_READ = 1 << 0, + MEMORY_ACCESS_WRITE = 1 << 1, + MEMORY_ACCESS_OWNER = 1 << 2, +}; + +/** + * A stream for reading and writing to files. Wraps an SDL_RWops, SDL2's cross platform file stream. + */ +class MemoryStream : public IStream +{ +private: + uint16 _access; + size_t _dataCapacity; + size_t _dataSize; + void * _data; + void * _position; + +public: + MemoryStream(); + MemoryStream(const MemoryStream ©); + explicit MemoryStream(size_t capacity); + MemoryStream(void * data, size_t dataSize, MEMORY_ACCESS access = MEMORY_ACCESS_READ); + MemoryStream(const void * data, size_t dataSize); + virtual ~MemoryStream(); + + void * GetData() const; + void * TakeData(); + + /////////////////////////////////////////////////////////////////////////// + // ISteam methods + /////////////////////////////////////////////////////////////////////////// + bool CanRead() const override; + bool CanWrite() const override; + + uint64 GetLength() const override; + uint64 GetPosition() const override; + void SetPosition(uint64 position) override; + void Seek(sint64 offset, int origin) override; + + void Read(void * buffer, uint64 length) override; + void Write(const void * buffer, uint64 length) override; + +private: + void EnsureCapacity(size_t capacity); +};