From 3bc10d36d231a7419c797bafe068314071c473af Mon Sep 17 00:00:00 2001 From: Danilo Borges Santos Date: Mon, 9 Dec 2024 11:49:40 -0300 Subject: [PATCH] Implementa NullStream --- includes/csharp/io/binary.hpp | 24 + includes/csharp/io/stream.hpp | 34 + sources/csharp/io/stream.cpp | 1383 +++++++++++++++++---------------- 3 files changed, 751 insertions(+), 690 deletions(-) diff --git a/includes/csharp/io/binary.hpp b/includes/csharp/io/binary.hpp index e18c7f3..784c247 100644 --- a/includes/csharp/io/binary.hpp +++ b/includes/csharp/io/binary.hpp @@ -11,9 +11,12 @@ namespace csharp { * The BinaryReader class uses byte encodings, by default UTF8. * This was not implemented, but we tried to follow the same standard. * Also the reading of primitives was modified. + * */ //TODO: ReadString and ReadChar as it only reads ASCII characters + //https://learn.microsoft.com/pt-br/dotnet/csharp/language-reference/builtin-types/char + //char - 16 bits //The BinaryReader class uses byte encodings, by default UTF8 class BinaryReader { @@ -136,6 +139,27 @@ namespace csharp { std::vector _auxBuffer; }; + + class BinaryWriter { + public: + BinaryWriter(std::shared_ptr const& output) { + OutStream = Stream::Null; + } + + BinaryWriter(std::shared_ptr const& output, bool leaveOpen); + + protected: + BinaryWriter(); + + protected: + std::shared_ptr OutStream; + + private: + static constexpr int MaxArrayPoolRentalSize = 64 * 1024; + static std::shared_ptr Null; + bool _leaveOpen{ false }; + bool _useFastUtf8{ true }; + }; } #endif \ No newline at end of file diff --git a/includes/csharp/io/stream.hpp b/includes/csharp/io/stream.hpp index 9ab1bd6..9a6d5c5 100644 --- a/includes/csharp/io/stream.hpp +++ b/includes/csharp/io/stream.hpp @@ -76,6 +76,9 @@ namespace csharp { virtual void Write(uint8_t const* buffer, int32_t bufferLength); virtual void WriteByte(uint8_t value) = 0; + public: + static const std::shared_ptr Null; + protected: void ValidateBuffer(uint8_t const* buffer, int32_t bufferLength); @@ -86,6 +89,37 @@ namespace csharp { int32_t GetCopybufferLength() const; }; + class NullStream : Stream { + public: + NullStream(){} + + constexpr bool CanRead() const override { return true; } + constexpr bool CanWrite() const override { return true; } + constexpr bool CanSeek() const override { return true; } + constexpr int64_t Length() const override { return 0; }; + constexpr int64_t Position() const override { return 0; }; + constexpr void Position(int64_t value) override { }; + constexpr void CopyTo(Stream& destination, int32_t bufferLength) override {}; + constexpr void SetLength(int64_t value) override {}; + + constexpr void Flush() override {}; + constexpr int64_t Seek(int64_t offset, SeekOrigin origin) override { + return 0; + } + + int32_t Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) override { + return 0; + } + + constexpr int32_t ReadByte() override { return -1; } + + constexpr void Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) override + {} + + constexpr void WriteByte(uint8_t value) override + {} + }; + class MemoryStream : public Stream { public: MemoryStream() : MemoryStream(0) {} diff --git a/sources/csharp/io/stream.cpp b/sources/csharp/io/stream.cpp index 0adb879..ea74a3f 100644 --- a/sources/csharp/io/stream.cpp +++ b/sources/csharp/io/stream.cpp @@ -5,726 +5,729 @@ #include #include #include +#include "misc.hpp" using byte = uint8_t; namespace csharp { + const std::shared_ptr Stream::Null = misc::reinterpret_make_shared(); + void Stream::CopyTo(Stream& destination, int32_t bufferLength) { - if (!CanRead()) - { - if (CanWrite()) - { - throw NotSupportedException(SR::NotSupported_UnreadableStream); - } + if (!CanRead()) + { + if (CanWrite()) + { + throw NotSupportedException(SR::NotSupported_UnreadableStream); + } - throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); - } + throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); + } - auto buffer = std::vector(bufferLength); + auto buffer = std::vector(bufferLength); - int32_t bytesRead = 0; + int32_t bytesRead = 0; - while ((bytesRead = Read(buffer.data(), static_cast(buffer.size()), 0, static_cast(buffer.size()))) != 0) - { - destination.Write(buffer.data(), static_cast(buffer.size()), 0, bytesRead); - } + while ((bytesRead = Read(buffer.data(), static_cast(buffer.size()), 0, static_cast(buffer.size()))) != 0) + { + destination.Write(buffer.data(), static_cast(buffer.size()), 0, bytesRead); + } } - int32_t Stream::GetCopybufferLength() const - { - constexpr auto DefaultCopybufferLength = 81920; - auto bufferLength = DefaultCopybufferLength; - - if (CanSeek()) - { - auto length = Length(); - auto position = Position(); - - if (length <= position) - { - bufferLength = 1; - } - else - { - auto remaining = length - position; - if (remaining > 0) - { - bufferLength = static_cast(std::min(static_cast(bufferLength), remaining)); - } - } - } - - return bufferLength; - } - - int32_t Stream::Read(uint8_t* buffer, int32_t bufferLength) { - ValidateBuffer(buffer, bufferLength); - - auto sharedBuffer = std::vector(bufferLength); - auto numRead = Read(sharedBuffer.data(), bufferLength, 0, bufferLength); - - if (numRead > bufferLength) - { - throw IOException(SR::IO_StreamTooLong); - } - - for (size_t i = 0; i < numRead; ++i) - buffer[i] = sharedBuffer[i]; - - return numRead; - } - - int32_t Stream::ReadByte() { - byte oneByteArray = 0; - auto r = Read(&oneByteArray, 1, 0, 1); - - return r == 0 ? -1 : oneByteArray; - } - - int32_t Stream::ReadAtLeastCore(uint8_t* buffer, int32_t bufferLength, int32_t minimumBytes, bool throwOnEndOfStream) { - ValidateBuffer(buffer, bufferLength); - - int32_t totalRead = 0; - while (totalRead < minimumBytes) - { - auto read = Read(buffer, bufferLength); - if (read == 0) - { - if (throwOnEndOfStream) - { - throw EndOfStreamException(SR::IO_EOF_ReadBeyondEOF); - } - - return totalRead; - } - - totalRead += read; - } - - return totalRead; - } - - void Stream::Write(uint8_t const* buffer, int32_t bufferLength) { - ValidateBuffer(buffer, bufferLength); - - auto sharedBuffer = std::vector(bufferLength); - - for (size_t i = 0; i < bufferLength; ++i) - sharedBuffer[i] = buffer[i]; - - Write(sharedBuffer.data(), bufferLength, 0, bufferLength); - } - - void Stream::ValidateBuffer(uint8_t const* buffer, int32_t bufferLength) { - if (!buffer) { - throw ArgumentNullException("buffer"); - } - - if (bufferLength < 0) { - throw ArgumentException("bufferLength"); - } - } - - // - //---------------------------------------------------------------- - // MemoryStream - //---------------------------------------------------------------- - // - - void MemoryStream::EnsureNotClosed() const { - if (!_isOpen) - throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); - } - - void MemoryStream::EnsureWriteable() const { - if (!CanWrite()) - throw NotSupportedException(SR::NotSupported_UnwritableStream); - } - - bool MemoryStream::EnsureCapacity(int32_t value) { - if (value < 0) - throw IOException(SR::IO_StreamTooLong); - - if (value > _capacity) - { - auto newCapacity = std::max(value, 256); - - if (newCapacity < _capacity * 2) - { - newCapacity = _capacity * 2; - } - - - if ((_capacity * 2) > MemStreamMaxLength) - { - newCapacity = std::max(value, MemStreamMaxLength); - } - - Capacity(newCapacity); - - return true; - } - return false; - } - - std::vector& MemoryStream::GetBuffer() { - if (!_exposable) { - throw UnauthorizedAccessException(SR::UnauthorizedAccess_MemStreamBuffer); - } - - return _buffer; - } - - bool MemoryStream::TryGetBuffer(std::vector& buffer) { - if (!_exposable) - { - return false; - } - - buffer = _buffer; - return true; - } - - int32_t MemoryStream::Capacity() const { - EnsureNotClosed(); - return _capacity - _origin; - } - - void MemoryStream::Capacity(int32_t value) { - if (value < Length()) - throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_SmallCapacity); - - EnsureNotClosed(); - - if (!_expandable && (value != Capacity())) - throw NotSupportedException(SR::NotSupported_MemStreamNotExpandable); - - if (_expandable && value != _capacity) - { - if (value > 0) - { - auto newBuffer = std::vector(value); - - if (_length > 0) - { - //Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _length); - std::memmove(newBuffer.data(), _buffer.data(), _length); - } - - _buffer = newBuffer; - } - else - { - _buffer = std::vector(); - } - _capacity = value; - } - } - - int64_t MemoryStream::Length() const { - EnsureNotClosed(); - return _length - _origin; - } - - int64_t MemoryStream::Position() const { - EnsureNotClosed(); - return _position - _origin; - } - - void MemoryStream::Position(int64_t value) { - EnsureNotClosed(); - - if (value > MemStreamMaxLength - _origin) - throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_StreamLength); - - _position = static_cast(_origin + value); - } - - int32_t MemoryStream::Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) { - ValidateBuffer(buffer, bufferLength); - EnsureNotClosed(); - - auto n = _length - _position; - - if (n > count) - n = count; - if (n <= 0) - return 0; - - if (n <= 8) - { - auto byteCount = n; - while (--byteCount >= 0) - buffer[offset + byteCount] = _buffer[_position + byteCount]; - } - else { - //Buffer.BlockCopy(_buffer, _position, buffer, offset, n); - std::memmove(buffer + offset, _buffer.data() + _position, n); - } - - _position += n; - - return static_cast(n); - } - - int32_t MemoryStream::Read(uint8_t* buffer, int32_t bufferLength) { - ValidateBuffer(buffer, bufferLength); - EnsureNotClosed(); - - int n = std::min(_length - _position, bufferLength); - - if (n <= 0) - return 0; - - for (size_t i = 0; i < n; ++i) - buffer[i] = _buffer[i]; - - _position += n; - - return n; - } - - int32_t MemoryStream::ReadByte() { - EnsureNotClosed(); - - if (_position >= _length) - return -1; - - return _buffer[_position++]; - } - - void MemoryStream::CopyTo(Stream& destination, int32_t bufferLength) { - EnsureNotClosed(); - - auto originalPosition = _position; - - auto remaining = InternalEmulateRead(_length - originalPosition); - - if (remaining > 0) - { - destination.Write(_buffer.data(), static_cast(_buffer.size()), originalPosition, remaining); - } - } - - int32_t MemoryStream::InternalEmulateRead(int32_t count) { - EnsureNotClosed(); - - auto n = _length - _position; - - if (n > count) - n = count; - if (n < 0) - n = 0; - _position += n; - return n; - } - - int64_t MemoryStream::Seek(int64_t offset, SeekOrigin loc) { - EnsureNotClosed(); - - int32_t _loc = 0; - - switch (loc) - { - case csharp::SeekOrigin::Begin: - _loc = _origin; - break; - case csharp::SeekOrigin::Current: - _loc = _position; - break; - case csharp::SeekOrigin::End: - _loc = _length; - break; - default: - throw ArgumentException(SR::Argument_InvalidSeekOrigin); - break; - } - - return SeekCore(offset, _loc); - } - - int64_t MemoryStream::SeekCore(int64_t offset, int32_t loc) { - if (offset > MemStreamMaxLength - loc) - throw ArgumentOutOfRangeException("offset", SR::ArgumentOutOfRange_StreamLength); - - auto tempPosition = loc + static_cast(offset); - - if ((loc + offset) < _origin || tempPosition < _origin) - throw IOException(SR::IO_SeekBeforeBegin); - - _position = tempPosition; - - return _position - _origin; - } - - void MemoryStream::SetLength(int64_t value) { - if (value < 0 || value > MemStreamMaxLength) - throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_StreamLength); - - EnsureWriteable(); - - if (value > (MemStreamMaxLength - _origin)) - throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_StreamLength); - - int newLength = _origin + (int)value; - bool allocatedNewArray = EnsureCapacity(newLength); - - if (!allocatedNewArray && newLength > _length) - { - //Array.Clear(_buffer, _length, newLength - _length); - for (size_t i = _length; i < newLength - _length; ++i) { - _buffer[i] = 0; - } - } - - _length = newLength; - - if (_position > newLength) - _position = newLength; - } - - void MemoryStream::Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) { - ValidateBuffer(buffer, bufferLength); - EnsureNotClosed(); - EnsureWriteable(); - - auto i = _position + count; - - if (i < 0) - throw IOException(SR::IO_StreamTooLong); - - if (i > _length) - { - auto mustZero = _position > _length; - - if (i > _capacity) - { - bool allocatedNewArray = EnsureCapacity(i); - if (allocatedNewArray) - { - mustZero = false; - } - } - if (mustZero) - { - //Array.Clear(_buffer, _length, i - _length); - for (size_t j = _length; j < i - _length; ++j) { - _buffer[j] = 0; - } - } - - _length = i; - } - - if ((count <= 8) && (buffer != _buffer.data())) - { - auto byteCount = count; - while (--byteCount >= 0) - { - _buffer[_position + byteCount] = buffer[offset + byteCount]; - } - } - else - { - //Buffer.BlockCopy(buffer, offset, _buffer, _position, count); - std::memmove(_buffer.data() + _position, buffer + offset, count); - } - _position = i; - } - - void MemoryStream::Write(uint8_t const* buffer, int32_t bufferLength) { - EnsureNotClosed(); - EnsureWriteable(); - - // Check for overflow - auto i = _position + bufferLength; - - if (i < 0) - throw IOException(SR::IO_StreamTooLong); - - if (i > _length) - { - auto mustZero = _position > _length; - - if (i > _capacity) - { - auto allocatedNewArray = EnsureCapacity(i); - if (allocatedNewArray) - { - mustZero = false; - } - } - - if (mustZero) - { - //Array.Clear(_buffer, _length, i - _length); - for (size_t j = _length; j < i - _length; ++j) { - _buffer[j] = 0; - } - } - - _length = i; - } - - //TODO: Verificar se está correto e verificar os std::memmove - //buffer.CopyTo(new Span(_buffer, _position, buffer.Length)); - for (size_t x = _position; x < bufferLength; ++i) { - _buffer[x] = buffer[x]; - } - - _position = i; - } - - void MemoryStream::WriteByte(uint8_t value) { - EnsureNotClosed(); - EnsureWriteable(); - - if (_position >= _length) - { - auto newLength = _position + 1; - auto mustZero = _position > _length; - - if (newLength >= _capacity) - { - bool allocatedNewArray = EnsureCapacity(newLength); - if (allocatedNewArray) - { - mustZero = false; - } - } - if (mustZero) - { - //Array.Clear(_buffer, _length, _position - _length); - for (size_t j = _length; j < _position - _length; ++j) { - _buffer[j] = 0; - } - } - _length = newLength; - } - _buffer[_position++] = value; - } - - void MemoryStream::WriteTo(Stream& stream) { - EnsureNotClosed(); - - stream.Write(_buffer.data(), static_cast(_buffer.size()), _origin, _length - _origin); - } - - // - //---------------------------------------------------------------- - // FileStream - //---------------------------------------------------------------- - // - - FileStream::FileStream(std::string const path, FileMode mode, FileShare shared, int32_t bufferLength) { - auto flags = std::fstream::in - | std::fstream::out - | std::fstream::binary; - - const auto exists = std::filesystem::exists(path); - - switch (mode) - { - //Especifica se deve abrir um arquivo existente. - case FileMode::Open: - if (!exists) - throw InvalidOperationException("The specified file does not exist."); - break; - //Especifica que se deve abrir um arquivo, se existir; - // caso contrário, um novo arquivo deverá ser criado. - case FileMode::OpenOrCreate: - case FileMode::Create: - if (!exists) - flags |= std::fstream::trunc; - break; - //Especifica que o sistema operacional deve criar um novo arquivo. - //Se o arquivo já existir, não abre o arquivo. - case FileMode::CreateNew: - if (!exists) - flags |= std::fstream::trunc; - else - throw InvalidOperationException("The specified file already exists."); - break; - //Abre o arquivo, se existir, e busca o final do arquivo ou cria um novo arquivo. - case FileMode::Append: - if (!exists) - flags |= std::fstream::trunc; - else - flags |= std::fstream::app; - break; - //Especifica que se deve abrir um arquivo existente. - //Quando o arquivo for aberto, ele deverá ser truncado - //para que seu tamanho seja zero bytes. - case FileMode::Truncate: - if (!exists) - throw InvalidOperationException("The specified file does not exist."); - - flags |= std::fstream::trunc; - break; - default: - throw InvalidOperationException(); - break; - } - - stream.open(path.c_str(), flags); - - if (!stream.good()) - throw InvalidOperationException("Failed to open file: " + path); - - SetStreamLength(); - _position = stream.tellg(); - } - - void FileStream::SetStreamLength() { - const auto pos = stream.tellg(); - stream.seekg(0, std::ios_base::end); - - const auto end = stream.tellg(); - stream.seekg(pos); - - _length = end; - } - - int64_t FileStream::Length() const { - EnsureNotClosed(); - return static_cast(_length); - } - - void FileStream::EnsureNotClosed() const { - if (!stream.is_open()) - throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); - } - - int64_t FileStream::Position() const { - EnsureNotClosed(); - return static_cast(_position); - } - - void FileStream::Position(int64_t value) { - EnsureNotClosed(); - const auto _position = static_cast(value); - stream.seekg(_position); - } - - void FileStream::CopyTo(Stream& destination, int32_t bufferLength) { - if (!CanRead()) - { - if (CanWrite()) - { - throw NotSupportedException(SR::NotSupported_UnreadableStream); - } - - throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); - } - - auto buffer = std::vector(bufferLength); - int32_t bytesRead = 0; - - while ((bytesRead = Read(buffer.data(), bufferLength, 0, bufferLength)) != 0) - { - destination.Write(buffer.data(), bufferLength, 0, bytesRead); - } - } - - void FileStream::Close() { - if (!stream.is_open()) - return; - - stream.close(); - _position = 0; - _length = 0; - } - - int64_t FileStream::Seek(int64_t offset, SeekOrigin origin) { - EnsureNotClosed(); - stream.seekg(static_cast(offset), static_cast(origin)); - _position = stream.tellg(); - return static_cast(_position); - } - - void FileStream::SetLength(int64_t value) { - EnsureNotClosed(); - EnsureWriteable(); - - throw NotSupportedException(); - } - - void FileStream::EnsureWriteable() const { - if (!CanWrite()) - throw NotSupportedException(SR::NotSupported_UnwritableStream); - } - - int32_t FileStream::Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) { - EnsureNotClosed(); - ValidateBuffer(buffer, bufferLength); + int32_t Stream::GetCopybufferLength() const + { + constexpr auto DefaultCopybufferLength = 81920; + auto bufferLength = DefaultCopybufferLength; + + if (CanSeek()) + { + auto length = Length(); + auto position = Position(); + + if (length <= position) + { + bufferLength = 1; + } + else + { + auto remaining = length - position; + if (remaining > 0) + { + bufferLength = static_cast(std::min(static_cast(bufferLength), remaining)); + } + } + } + + return bufferLength; + } + + int32_t Stream::Read(uint8_t* buffer, int32_t bufferLength) { + ValidateBuffer(buffer, bufferLength); + + auto sharedBuffer = std::vector(bufferLength); + auto numRead = Read(sharedBuffer.data(), bufferLength, 0, bufferLength); + + if (numRead > bufferLength) + { + throw IOException(SR::IO_StreamTooLong); + } + + for (size_t i = 0; i < numRead; ++i) + buffer[i] = sharedBuffer[i]; + + return numRead; + } + + int32_t Stream::ReadByte() { + byte oneByteArray = 0; + auto r = Read(&oneByteArray, 1, 0, 1); + + return r == 0 ? -1 : oneByteArray; + } + + int32_t Stream::ReadAtLeastCore(uint8_t* buffer, int32_t bufferLength, int32_t minimumBytes, bool throwOnEndOfStream) { + ValidateBuffer(buffer, bufferLength); + + int32_t totalRead = 0; + while (totalRead < minimumBytes) + { + auto read = Read(buffer, bufferLength); + if (read == 0) + { + if (throwOnEndOfStream) + { + throw EndOfStreamException(SR::IO_EOF_ReadBeyondEOF); + } + + return totalRead; + } + + totalRead += read; + } + + return totalRead; + } + + void Stream::Write(uint8_t const* buffer, int32_t bufferLength) { + ValidateBuffer(buffer, bufferLength); + + auto sharedBuffer = std::vector(bufferLength); + + for (size_t i = 0; i < bufferLength; ++i) + sharedBuffer[i] = buffer[i]; + + Write(sharedBuffer.data(), bufferLength, 0, bufferLength); + } + + void Stream::ValidateBuffer(uint8_t const* buffer, int32_t bufferLength) { + if (!buffer) { + throw ArgumentNullException("buffer"); + } + + if (bufferLength < 0) { + throw ArgumentException("bufferLength"); + } + } + + // + //---------------------------------------------------------------- + // MemoryStream + //---------------------------------------------------------------- + // + + void MemoryStream::EnsureNotClosed() const { + if (!_isOpen) + throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); + } + + void MemoryStream::EnsureWriteable() const { + if (!CanWrite()) + throw NotSupportedException(SR::NotSupported_UnwritableStream); + } + + bool MemoryStream::EnsureCapacity(int32_t value) { + if (value < 0) + throw IOException(SR::IO_StreamTooLong); + + if (value > _capacity) + { + auto newCapacity = std::max(value, 256); + + if (newCapacity < _capacity * 2) + { + newCapacity = _capacity * 2; + } + + + if ((_capacity * 2) > MemStreamMaxLength) + { + newCapacity = std::max(value, MemStreamMaxLength); + } + + Capacity(newCapacity); + + return true; + } + return false; + } + + std::vector& MemoryStream::GetBuffer() { + if (!_exposable) { + throw UnauthorizedAccessException(SR::UnauthorizedAccess_MemStreamBuffer); + } + + return _buffer; + } + + bool MemoryStream::TryGetBuffer(std::vector& buffer) { + if (!_exposable) + { + return false; + } + + buffer = _buffer; + return true; + } + + int32_t MemoryStream::Capacity() const { + EnsureNotClosed(); + return _capacity - _origin; + } - auto buff = reinterpret_cast(buffer); - stream.read(buff + offset, count); + void MemoryStream::Capacity(int32_t value) { + if (value < Length()) + throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_SmallCapacity); - if (stream.rdstate() != std::fstream::goodbit) { - return -1; - } + EnsureNotClosed(); - return static_cast(stream.gcount()); - } + if (!_expandable && (value != Capacity())) + throw NotSupportedException(SR::NotSupported_MemStreamNotExpandable); - int32_t FileStream::Read(uint8_t* buffer, int32_t bufferLength) { - return Read(buffer, bufferLength, 0, bufferLength); - } + if (_expandable && value != _capacity) + { + if (value > 0) + { + auto newBuffer = std::vector(value); - int32_t FileStream::ReadByte() { - EnsureNotClosed(); + if (_length > 0) + { + //Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _length); + std::memmove(newBuffer.data(), _buffer.data(), _length); + } - char c = 0; + _buffer = newBuffer; + } + else + { + _buffer = std::vector(); + } + _capacity = value; + } + } + + int64_t MemoryStream::Length() const { + EnsureNotClosed(); + return _length - _origin; + } - stream.read(&c, 1); + int64_t MemoryStream::Position() const { + EnsureNotClosed(); + return _position - _origin; + } - if (stream.rdstate() != std::fstream::goodbit) { - return -1; - } - - const auto uchar = static_cast(c); - const auto result = static_cast(uchar); - - return result; - } + void MemoryStream::Position(int64_t value) { + EnsureNotClosed(); + + if (value > MemStreamMaxLength - _origin) + throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_StreamLength); + + _position = static_cast(_origin + value); + } + + int32_t MemoryStream::Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) { + ValidateBuffer(buffer, bufferLength); + EnsureNotClosed(); + + auto n = _length - _position; + + if (n > count) + n = count; + if (n <= 0) + return 0; + + if (n <= 8) + { + auto byteCount = n; + while (--byteCount >= 0) + buffer[offset + byteCount] = _buffer[_position + byteCount]; + } + else { + //Buffer.BlockCopy(_buffer, _position, buffer, offset, n); + std::memmove(buffer + offset, _buffer.data() + _position, n); + } - void FileStream::Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) { - EnsureNotClosed(); - EnsureWriteable(); + _position += n; - auto buff = reinterpret_cast(buffer); + return static_cast(n); + } - stream.write(buff + offset, count); + int32_t MemoryStream::Read(uint8_t* buffer, int32_t bufferLength) { + ValidateBuffer(buffer, bufferLength); + EnsureNotClosed(); - if (stream.rdstate() != std::fstream::goodbit) { - throw InvalidOperationException(); - } + int n = std::min(_length - _position, bufferLength); - SetStreamLength(); - } + if (n <= 0) + return 0; + + for (size_t i = 0; i < n; ++i) + buffer[i] = _buffer[i]; - void FileStream::Write(uint8_t const* buffer, int32_t bufferLength) { - Write(buffer, bufferLength, 0, bufferLength); - } + _position += n; - void FileStream::WriteByte(uint8_t value) { - EnsureNotClosed(); - EnsureWriteable(); + return n; + } - const char c = static_cast(value); + int32_t MemoryStream::ReadByte() { + EnsureNotClosed(); - stream.write(&c, 1); + if (_position >= _length) + return -1; - if (stream.rdstate() != std::fstream::goodbit) { - throw InvalidOperationException(); - } + return _buffer[_position++]; + } - SetStreamLength(); - } + void MemoryStream::CopyTo(Stream& destination, int32_t bufferLength) { + EnsureNotClosed(); - std::fstream& FileStream::GetBuffer() { - return stream; - } + auto originalPosition = _position; + + auto remaining = InternalEmulateRead(_length - originalPosition); + + if (remaining > 0) + { + destination.Write(_buffer.data(), static_cast(_buffer.size()), originalPosition, remaining); + } + } + + int32_t MemoryStream::InternalEmulateRead(int32_t count) { + EnsureNotClosed(); + + auto n = _length - _position; + + if (n > count) + n = count; + if (n < 0) + n = 0; + _position += n; + return n; + } + + int64_t MemoryStream::Seek(int64_t offset, SeekOrigin loc) { + EnsureNotClosed(); + + int32_t _loc = 0; + + switch (loc) + { + case csharp::SeekOrigin::Begin: + _loc = _origin; + break; + case csharp::SeekOrigin::Current: + _loc = _position; + break; + case csharp::SeekOrigin::End: + _loc = _length; + break; + default: + throw ArgumentException(SR::Argument_InvalidSeekOrigin); + break; + } + + return SeekCore(offset, _loc); + } + + int64_t MemoryStream::SeekCore(int64_t offset, int32_t loc) { + if (offset > MemStreamMaxLength - loc) + throw ArgumentOutOfRangeException("offset", SR::ArgumentOutOfRange_StreamLength); + + auto tempPosition = loc + static_cast(offset); + + if ((loc + offset) < _origin || tempPosition < _origin) + throw IOException(SR::IO_SeekBeforeBegin); + + _position = tempPosition; + + return _position - _origin; + } + + void MemoryStream::SetLength(int64_t value) { + if (value < 0 || value > MemStreamMaxLength) + throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_StreamLength); + + EnsureWriteable(); + + if (value > (MemStreamMaxLength - _origin)) + throw ArgumentOutOfRangeException("value", SR::ArgumentOutOfRange_StreamLength); + + int newLength = _origin + (int)value; + bool allocatedNewArray = EnsureCapacity(newLength); + + if (!allocatedNewArray && newLength > _length) + { + //Array.Clear(_buffer, _length, newLength - _length); + for (size_t i = _length; i < newLength - _length; ++i) { + _buffer[i] = 0; + } + } + + _length = newLength; + + if (_position > newLength) + _position = newLength; + } + + void MemoryStream::Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) { + ValidateBuffer(buffer, bufferLength); + EnsureNotClosed(); + EnsureWriteable(); + + auto i = _position + count; + + if (i < 0) + throw IOException(SR::IO_StreamTooLong); + + if (i > _length) + { + auto mustZero = _position > _length; + + if (i > _capacity) + { + bool allocatedNewArray = EnsureCapacity(i); + if (allocatedNewArray) + { + mustZero = false; + } + } + if (mustZero) + { + //Array.Clear(_buffer, _length, i - _length); + for (size_t j = _length; j < i - _length; ++j) { + _buffer[j] = 0; + } + } + + _length = i; + } + + if ((count <= 8) && (buffer != _buffer.data())) + { + auto byteCount = count; + while (--byteCount >= 0) + { + _buffer[_position + byteCount] = buffer[offset + byteCount]; + } + } + else + { + //Buffer.BlockCopy(buffer, offset, _buffer, _position, count); + std::memmove(_buffer.data() + _position, buffer + offset, count); + } + _position = i; + } + + void MemoryStream::Write(uint8_t const* buffer, int32_t bufferLength) { + EnsureNotClosed(); + EnsureWriteable(); + + // Check for overflow + auto i = _position + bufferLength; + + if (i < 0) + throw IOException(SR::IO_StreamTooLong); + + if (i > _length) + { + auto mustZero = _position > _length; + + if (i > _capacity) + { + auto allocatedNewArray = EnsureCapacity(i); + if (allocatedNewArray) + { + mustZero = false; + } + } + + if (mustZero) + { + //Array.Clear(_buffer, _length, i - _length); + for (size_t j = _length; j < i - _length; ++j) { + _buffer[j] = 0; + } + } + + _length = i; + } + + //TODO: Verificar se está correto e verificar os std::memmove + //buffer.CopyTo(new Span(_buffer, _position, buffer.Length)); + for (size_t x = _position; x < bufferLength; ++i) { + _buffer[x] = buffer[x]; + } + + _position = i; + } + + void MemoryStream::WriteByte(uint8_t value) { + EnsureNotClosed(); + EnsureWriteable(); + + if (_position >= _length) + { + auto newLength = _position + 1; + auto mustZero = _position > _length; + + if (newLength >= _capacity) + { + bool allocatedNewArray = EnsureCapacity(newLength); + if (allocatedNewArray) + { + mustZero = false; + } + } + if (mustZero) + { + //Array.Clear(_buffer, _length, _position - _length); + for (size_t j = _length; j < _position - _length; ++j) { + _buffer[j] = 0; + } + } + _length = newLength; + } + _buffer[_position++] = value; + } + + void MemoryStream::WriteTo(Stream& stream) { + EnsureNotClosed(); + + stream.Write(_buffer.data(), static_cast(_buffer.size()), _origin, _length - _origin); + } + + // + //---------------------------------------------------------------- + // FileStream + //---------------------------------------------------------------- + // + + FileStream::FileStream(std::string const path, FileMode mode, FileShare shared, int32_t bufferLength) { + auto flags = std::fstream::in + | std::fstream::out + | std::fstream::binary; + + const auto exists = std::filesystem::exists(path); + + switch (mode) + { + //Especifica se deve abrir um arquivo existente. + case FileMode::Open: + if (!exists) + throw InvalidOperationException("The specified file does not exist."); + break; + //Especifica que se deve abrir um arquivo, se existir; + // caso contrário, um novo arquivo deverá ser criado. + case FileMode::OpenOrCreate: + case FileMode::Create: + if (!exists) + flags |= std::fstream::trunc; + break; + //Especifica que o sistema operacional deve criar um novo arquivo. + //Se o arquivo já existir, não abre o arquivo. + case FileMode::CreateNew: + if (!exists) + flags |= std::fstream::trunc; + else + throw InvalidOperationException("The specified file already exists."); + break; + //Abre o arquivo, se existir, e busca o final do arquivo ou cria um novo arquivo. + case FileMode::Append: + if (!exists) + flags |= std::fstream::trunc; + else + flags |= std::fstream::app; + break; + //Especifica que se deve abrir um arquivo existente. + //Quando o arquivo for aberto, ele deverá ser truncado + //para que seu tamanho seja zero bytes. + case FileMode::Truncate: + if (!exists) + throw InvalidOperationException("The specified file does not exist."); + + flags |= std::fstream::trunc; + break; + default: + throw InvalidOperationException(); + break; + } + + stream.open(path.c_str(), flags); + + if (!stream.good()) + throw InvalidOperationException("Failed to open file: " + path); + + SetStreamLength(); + _position = stream.tellg(); + } + + void FileStream::SetStreamLength() { + const auto pos = stream.tellg(); + stream.seekg(0, std::ios_base::end); + + const auto end = stream.tellg(); + stream.seekg(pos); + + _length = end; + } + + int64_t FileStream::Length() const { + EnsureNotClosed(); + return static_cast(_length); + } + + void FileStream::EnsureNotClosed() const { + if (!stream.is_open()) + throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); + } + + int64_t FileStream::Position() const { + EnsureNotClosed(); + return static_cast(_position); + } + + void FileStream::Position(int64_t value) { + EnsureNotClosed(); + const auto _position = static_cast(value); + stream.seekg(_position); + } + + void FileStream::CopyTo(Stream& destination, int32_t bufferLength) { + if (!CanRead()) + { + if (CanWrite()) + { + throw NotSupportedException(SR::NotSupported_UnreadableStream); + } + + throw InvalidOperationException(SR::ObjectDisposed_StreamClosed); + } + + auto buffer = std::vector(bufferLength); + int32_t bytesRead = 0; + + while ((bytesRead = Read(buffer.data(), bufferLength, 0, bufferLength)) != 0) + { + destination.Write(buffer.data(), bufferLength, 0, bytesRead); + } + } + + void FileStream::Close() { + if (!stream.is_open()) + return; + + stream.close(); + _position = 0; + _length = 0; + } + + int64_t FileStream::Seek(int64_t offset, SeekOrigin origin) { + EnsureNotClosed(); + stream.seekg(static_cast(offset), static_cast(origin)); + _position = stream.tellg(); + return static_cast(_position); + } + + void FileStream::SetLength(int64_t value) { + EnsureNotClosed(); + EnsureWriteable(); + + throw NotSupportedException(); + } + + void FileStream::EnsureWriteable() const { + if (!CanWrite()) + throw NotSupportedException(SR::NotSupported_UnwritableStream); + } + + int32_t FileStream::Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) { + EnsureNotClosed(); + ValidateBuffer(buffer, bufferLength); + + auto buff = reinterpret_cast(buffer); + stream.read(buff + offset, count); + + if (stream.rdstate() != std::fstream::goodbit) { + return -1; + } + + return static_cast(stream.gcount()); + } + + int32_t FileStream::Read(uint8_t* buffer, int32_t bufferLength) { + return Read(buffer, bufferLength, 0, bufferLength); + } + + int32_t FileStream::ReadByte() { + EnsureNotClosed(); + + char c = 0; + + stream.read(&c, 1); + + if (stream.rdstate() != std::fstream::goodbit) { + return -1; + } + + const auto uchar = static_cast(c); + const auto result = static_cast(uchar); + + return result; + } + + void FileStream::Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) { + EnsureNotClosed(); + EnsureWriteable(); + + auto buff = reinterpret_cast(buffer); + + stream.write(buff + offset, count); + + if (stream.rdstate() != std::fstream::goodbit) { + throw InvalidOperationException(); + } + + SetStreamLength(); + } + + void FileStream::Write(uint8_t const* buffer, int32_t bufferLength) { + Write(buffer, bufferLength, 0, bufferLength); + } + + void FileStream::WriteByte(uint8_t value) { + EnsureNotClosed(); + EnsureWriteable(); + + const char c = static_cast(value); + + stream.write(&c, 1); + + if (stream.rdstate() != std::fstream::goodbit) { + throw InvalidOperationException(); + } + + SetStreamLength(); + } + + std::fstream& FileStream::GetBuffer() { + return stream; + } } \ No newline at end of file