mirror of
https://github.com/borgesdan/xn65
synced 2024-12-29 21:54:47 +01:00
Adiciona Csharp/MemoryStream
This commit is contained in:
parent
54c08bf436
commit
a3f7969d1a
57
includes/csharp/io/exception.hpp
Normal file
57
includes/csharp/io/exception.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef CSHARP_IO_EXCEPTION_HPP
|
||||
#define CSHARP_IO_EXCEPTION_HPP
|
||||
|
||||
#include "../exception.hpp"
|
||||
#include <source_location>
|
||||
|
||||
namespace csharp {
|
||||
class IOException : public SystemException {
|
||||
public:
|
||||
IOException(std::source_location const& source = std::source_location::current())
|
||||
: SystemException(SR::Arg_IOException, source)
|
||||
{
|
||||
HRresult = HResults::HR_COR_E_IO;
|
||||
}
|
||||
|
||||
IOException(std::string const& message, std::source_location const& source = std::source_location::current())
|
||||
: SystemException(!message.empty() ? message : SR::Arg_IOException, source)
|
||||
{
|
||||
HRresult = HResults::HR_COR_E_IO;
|
||||
}
|
||||
|
||||
IOException(std::string const& message, size_t hresult, std::source_location const& source = std::source_location::current())
|
||||
: SystemException(!message.empty() ? message : SR::Arg_IOException, source)
|
||||
{
|
||||
HRresult = hresult;
|
||||
}
|
||||
|
||||
IOException(std::string const& message, std::shared_ptr<Exception>& innerException, std::source_location const& source = std::source_location::current())
|
||||
: SystemException(!message.empty() ? message : SR::Arg_IOException, innerException, source)
|
||||
{
|
||||
HRresult = HResults::HR_COR_E_IO;
|
||||
}
|
||||
};
|
||||
|
||||
class EndOfStreamException : public IOException {
|
||||
public:
|
||||
EndOfStreamException(std::source_location const& source = std::source_location::current())
|
||||
: IOException(SR::Arg_IOException, source)
|
||||
{
|
||||
HRresult = HResults::HR_COR_E_ENDOFSTREAM;
|
||||
}
|
||||
|
||||
EndOfStreamException(std::string const& message, std::source_location const& source = std::source_location::current())
|
||||
: IOException(!message.empty() ? message : SR::Arg_IOException, source)
|
||||
{
|
||||
HRresult = HResults::HR_COR_E_ENDOFSTREAM;
|
||||
}
|
||||
|
||||
EndOfStreamException(std::string const& message, std::shared_ptr<Exception>& innerException, std::source_location const& source = std::source_location::current())
|
||||
: IOException(!message.empty() ? message : SR::Arg_IOException, innerException, source)
|
||||
{
|
||||
HRresult = HResults::HR_COR_E_ENDOFSTREAM;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
337
includes/csharp/io/stream.hpp
Normal file
337
includes/csharp/io/stream.hpp
Normal file
@ -0,0 +1,337 @@
|
||||
#ifndef CSHARP_IO_STREAM_HPP
|
||||
#define CSHARP_IO_STREAM_HPP
|
||||
|
||||
#include "../exception.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace csharp {
|
||||
// Provides seek reference points. To seek to the end of a stream,
|
||||
// call stream.Seek(0, SeekOrigin.End).
|
||||
enum class SeekOrigin
|
||||
{
|
||||
// These constants match Win32's FILE_BEGIN, FILE_CURRENT, and FILE_END
|
||||
Begin = 0,
|
||||
Current = 1,
|
||||
End = 2,
|
||||
};
|
||||
|
||||
class Stream {
|
||||
public:
|
||||
virtual bool CanRead() const = 0;
|
||||
virtual bool CanWrite() const = 0;
|
||||
virtual bool CanSeek() const = 0;
|
||||
virtual bool CanTimeout() const { return false; }
|
||||
virtual int64_t Length() const = 0;
|
||||
virtual int64_t Position() const = 0;
|
||||
virtual void Position(int64_t value) = 0;
|
||||
|
||||
virtual int32_t ReadTimeout() {
|
||||
throw InvalidOperationException(SR::InvalidOperation_TimeoutsNotSupported);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void ReadTimeout(int32_t value) {
|
||||
throw InvalidOperationException(SR::InvalidOperation_TimeoutsNotSupported);
|
||||
}
|
||||
|
||||
virtual int32_t WriteTimeout() {
|
||||
throw InvalidOperationException(SR::InvalidOperation_TimeoutsNotSupported);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void WriteTimeout(int32_t value) {
|
||||
throw InvalidOperationException(SR::InvalidOperation_TimeoutsNotSupported);
|
||||
}
|
||||
|
||||
void CopyTo(Stream& destination) {
|
||||
CopyTo(destination, GetCopybufferLength());
|
||||
}
|
||||
|
||||
virtual void CopyTo(Stream& destination, int32_t bufferLength);
|
||||
virtual void Close() {}
|
||||
virtual void Flush() = 0;
|
||||
virtual int64_t Seek(int64_t offset, SeekOrigin origin) = 0;
|
||||
virtual void SetLength(int64_t value) = 0;
|
||||
virtual int32_t Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) = 0;
|
||||
virtual int32_t Read(uint8_t* buffer, int32_t bufferLength);
|
||||
virtual int32_t ReadByte();
|
||||
|
||||
virtual int32_t ReadExactly(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) {
|
||||
return ReadAtLeastCore(buffer, bufferLength, bufferLength, true);
|
||||
}
|
||||
|
||||
virtual void Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) = 0;
|
||||
virtual void Write(uint8_t const* buffer, int32_t bufferLength);
|
||||
virtual void WriteByte(uint8_t value);
|
||||
|
||||
protected:
|
||||
void ValidateBuffer(uint8_t const* buffer, int32_t bufferLength);
|
||||
|
||||
private:
|
||||
int32_t ReadAtLeastCore(uint8_t* buffer, int32_t bufferLength, int32_t minimumBytes, bool throwOnEndOfStream);
|
||||
|
||||
private:
|
||||
int32_t GetCopybufferLength() const;
|
||||
};
|
||||
|
||||
class MemoryStream : public Stream {
|
||||
public:
|
||||
MemoryStream() : MemoryStream(0) {}
|
||||
|
||||
MemoryStream(int32_t capacity)
|
||||
{
|
||||
_buffer.resize(static_cast<size_t>(capacity));
|
||||
_capacity = capacity;
|
||||
_expandable = true;
|
||||
_writable = true;
|
||||
_exposable = true;
|
||||
_isOpen = true;
|
||||
}
|
||||
|
||||
MemoryStream(std::vector<uint8_t> const buffer)
|
||||
: MemoryStream(buffer, true) {}
|
||||
|
||||
MemoryStream(std::vector<uint8_t> const buffer, bool writable) {
|
||||
_buffer = buffer;
|
||||
_length = _capacity = static_cast<int32_t>(buffer.size());
|
||||
_writable = writable;
|
||||
_isOpen = true;
|
||||
}
|
||||
|
||||
MemoryStream(std::vector<uint8_t> const buffer, int32_t index, int32_t count)
|
||||
: MemoryStream(buffer, index, count, true, false) {}
|
||||
|
||||
MemoryStream(std::vector<uint8_t> const buffer, int32_t index, int32_t count, bool writable)
|
||||
: MemoryStream(buffer, index, count, writable, false) {}
|
||||
|
||||
MemoryStream(std::vector<uint8_t> const buffer, int32_t index, int32_t count, bool writable, bool publiclyVisible)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
|
||||
if (buffer.size() - static_cast<size_t>(index < count))
|
||||
throw ArgumentException(SR::Argument_InvalidOffLen);
|
||||
|
||||
_buffer = buffer;
|
||||
_origin = _position = index;
|
||||
_length = _capacity = index + count;
|
||||
_writable = writable;
|
||||
_exposable = publiclyVisible;
|
||||
_isOpen = true;
|
||||
}
|
||||
|
||||
bool CanRead() const override { return _isOpen; }
|
||||
bool CanSeek() const override { return _isOpen; }
|
||||
bool CanWrite() const override { return _writable; }
|
||||
void Flush() override {}
|
||||
virtual std::vector<uint8_t>& GetBuffer();
|
||||
virtual bool TryGetBuffer(std::vector<uint8_t>& buffer);
|
||||
virtual int32_t Capacity() const;
|
||||
virtual void Capacity(int32_t value);
|
||||
int64_t Length() const override;
|
||||
int64_t Position() const override;
|
||||
void Position(int64_t value) override;
|
||||
int32_t Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) override;
|
||||
int32_t Read(uint8_t* buffer, int32_t bufferLength) override;
|
||||
int32_t ReadByte() override;
|
||||
void CopyTo(Stream& destination, int32_t bufferLength) override;
|
||||
int32_t InternalEmulateRead(int32_t count);
|
||||
int64_t Seek(int64_t offset, SeekOrigin loc) override;
|
||||
void SetLength(int64_t value) override;
|
||||
void Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) override;
|
||||
void Write(uint8_t const* buffer, int32_t bufferLength) override;
|
||||
void WriteByte(uint8_t value) override;
|
||||
virtual void WriteTo(Stream& stream);
|
||||
|
||||
constexpr void Close() override {
|
||||
if (!_isOpen)
|
||||
return;
|
||||
|
||||
_isOpen = false;
|
||||
_writable = false;
|
||||
_expandable = false;
|
||||
_buffer.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void EnsureNotClosed() const;
|
||||
void EnsureWriteable() const;
|
||||
bool EnsureCapacity(int32_t value);
|
||||
int64_t SeekCore(int64_t offset, int32_t loc);
|
||||
|
||||
public:
|
||||
std::vector<uint8_t> _buffer;
|
||||
|
||||
private:
|
||||
int32_t _origin{ 0 };
|
||||
int32_t _position{ 0 };
|
||||
int32_t _length{ 0 };
|
||||
int32_t _capacity{ 0 };
|
||||
bool _expandable{ false };
|
||||
bool _writable{ false };
|
||||
bool _exposable{ false };
|
||||
bool _isOpen{ false };
|
||||
|
||||
inline static constexpr int32_t MemStreamMaxLength = std::numeric_limits<int32_t>::max();
|
||||
};
|
||||
|
||||
// Contains constants for specifying how the OS should open a file.
|
||||
// These will control whether you overwrite a file, open an existing
|
||||
// file, or some combination thereof.
|
||||
// To append to a file, use Append (which maps to OpenOrCreate then we seek
|
||||
// to the end of the file). To truncate a file or create it if it doesn't
|
||||
// exist, use Create.
|
||||
enum class FileMode
|
||||
{
|
||||
// Creates a new file. An exception is raised if the file already exists.
|
||||
CreateNew = 1,
|
||||
// Creates a new file. If the file already exists, it is overwritten.
|
||||
Create = 2,
|
||||
// Opens an existing file. An exception is raised if the file does not exist.
|
||||
Open = 3,
|
||||
// Opens the file if it exists. Otherwise, creates a new file.
|
||||
OpenOrCreate = 4,
|
||||
// Opens an existing file. Once opened, the file is truncated so that its
|
||||
// size is zero bytes. The calling process must open the file with at least
|
||||
// WRITE access. An exception is raised if the file does not exist.
|
||||
Truncate = 5,
|
||||
// Opens the file if it exists and seeks to the end. Otherwise,
|
||||
// creates a new file.
|
||||
Append = 6,
|
||||
};
|
||||
|
||||
// Contains constants for specifying the access you want for a file.
|
||||
// You can have Read, Write or ReadWrite access.
|
||||
//
|
||||
enum class FileAccess
|
||||
{
|
||||
// Specifies read access to the file. Data can be read from the file and
|
||||
// the file pointer can be moved. Combine with WRITE for read-write access.
|
||||
Read = 1,
|
||||
|
||||
// Specifies write access to the file. Data can be written to the file and
|
||||
// the file pointer can be moved. Combine with READ for read-write access.
|
||||
Write = 2,
|
||||
|
||||
// Specifies read and write access to the file. Data can be written to the
|
||||
// file and the file pointer can be moved. Data can also be read from the
|
||||
// file.
|
||||
ReadWrite = 3,
|
||||
};
|
||||
|
||||
// Contains constants for controlling file sharing options while
|
||||
// opening files. You can specify what access other processes trying
|
||||
// to open the same file concurrently can have.
|
||||
//
|
||||
// Note these values currently match the values for FILE_SHARE_READ,
|
||||
// FILE_SHARE_WRITE, and FILE_SHARE_DELETE in winnt.h
|
||||
//
|
||||
enum class FileShare
|
||||
{
|
||||
// No sharing. Any request to open the file (by this process or another
|
||||
// process) will fail until the file is closed.
|
||||
None = 0,
|
||||
|
||||
// Allows subsequent opening of the file for reading. If this flag is not
|
||||
// specified, any request to open the file for reading (by this process or
|
||||
// another process) will fail until the file is closed.
|
||||
Read = 1,
|
||||
|
||||
// Allows subsequent opening of the file for writing. If this flag is not
|
||||
// specified, any request to open the file for writing (by this process or
|
||||
// another process) will fail until the file is closed.
|
||||
Write = 2,
|
||||
|
||||
// Allows subsequent opening of the file for writing or reading. If this flag
|
||||
// is not specified, any request to open the file for writing or reading (by
|
||||
// this process or another process) will fail until the file is closed.
|
||||
ReadWrite = 3,
|
||||
|
||||
// Open the file, but allow someone else to delete the file.
|
||||
Delete = 4,
|
||||
|
||||
// Whether the file handle should be inheritable by child processes.
|
||||
// Note this is not directly supported like this by Win32.
|
||||
Inheritable = 0x10,
|
||||
};
|
||||
|
||||
// Maps to FILE_FLAG_DELETE_ON_CLOSE and similar values from winbase.h.
|
||||
// We didn't expose a number of these values because we didn't believe
|
||||
// a number of them made sense in managed code, at least not yet.
|
||||
enum class FileOptions
|
||||
{
|
||||
// NOTE: any change to FileOptions enum needs to be
|
||||
// matched in the FileStream ctor for error validation
|
||||
None = 0,
|
||||
WriteThrough = static_cast<int32_t>(0x80000000),
|
||||
Asynchronous = static_cast<int32_t>(0x40000000), // FILE_FLAG_OVERLAPPED
|
||||
// NoBuffering = 0x20000000, // FILE_FLAG_NO_BUFFERING
|
||||
RandomAccess = 0x10000000,
|
||||
DeleteOnClose = 0x04000000,
|
||||
SequentialScan = 0x08000000,
|
||||
// AllowPosix = 0x01000000, // FILE_FLAG_POSIX_SEMANTICS
|
||||
// BackupOrRestore = 0x02000000, // FILE_FLAG_BACKUP_SEMANTICS
|
||||
// DisallowReparsePoint = 0x00200000, // FILE_FLAG_OPEN_REPARSE_POINT
|
||||
// NoRemoteRecall = 0x00100000, // FILE_FLAG_OPEN_NO_RECALL
|
||||
// FirstPipeInstance = 0x00080000, // FILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
Encrypted = 0x00004000, // FILE_ATTRIBUTE_ENCRYPTED
|
||||
};
|
||||
|
||||
class FileStream : public Stream {
|
||||
public:
|
||||
FileStream(std::string const path, FileMode mode) : FileStream(path, mode, FileShare::None, 0) {}
|
||||
FileStream(std::string const path, FileMode mode, FileAccess access) : FileStream(path, mode, FileShare::None, 0) {}
|
||||
FileStream(std::string const path, FileMode mode, FileShare shared) : FileStream(path, mode, shared, 0) {}
|
||||
FileStream(std::string const path, FileMode mode, FileShare shared, int32_t bufferLength);
|
||||
|
||||
constexpr bool CanRead() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool CanWrite() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool CanSeek() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t Length() const override;
|
||||
int64_t Position() const override;
|
||||
void Position(int64_t value) override;
|
||||
void CopyTo(Stream& destination, int32_t bufferLength) override;
|
||||
void Close() override;
|
||||
void Flush() override { stream.flush(); }
|
||||
int64_t Seek(int64_t offset, SeekOrigin origin) override;
|
||||
void SetLength(int64_t value) override;
|
||||
int32_t Read(uint8_t* buffer, int32_t bufferLength, int32_t offset, int32_t count) override;
|
||||
int32_t Read(uint8_t* buffer, int32_t bufferLength) override;
|
||||
int32_t ReadByte() override;
|
||||
void Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) override;
|
||||
void Write(uint8_t const* buffer, int32_t bufferLength) override;
|
||||
void WriteByte(uint8_t value) override;
|
||||
|
||||
virtual std::fstream& GetBuffer();
|
||||
|
||||
private:
|
||||
void SetStreamLength();
|
||||
void EnsureNotClosed() const;
|
||||
void EnsureWriteable() const;
|
||||
|
||||
public:
|
||||
std::fstream stream;
|
||||
|
||||
private:
|
||||
std::streampos _length{ 0 };
|
||||
std::streampos _position{ 0 };
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -5,7 +5,7 @@
|
||||
# Add source to this project's executable.
|
||||
add_library (CSharp++ STATIC
|
||||
"exception.cpp"
|
||||
)
|
||||
"io/stream.cpp")
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
||||
set_property(TARGET CSharp++ PROPERTY CXX_STANDARD 20)
|
||||
|
729
sources/csharp/io/stream.cpp
Normal file
729
sources/csharp/io/stream.cpp
Normal file
@ -0,0 +1,729 @@
|
||||
#include "csharp/io/stream.hpp"
|
||||
#include "csharp/io/exception.hpp"
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
using byte = uint8_t;
|
||||
|
||||
namespace csharp {
|
||||
void Stream::CopyTo(Stream& destination, int32_t bufferLength)
|
||||
{
|
||||
if (!CanRead())
|
||||
{
|
||||
if (CanWrite())
|
||||
{
|
||||
throw NotSupportedException(SR::NotSupported_UnreadableStream);
|
||||
}
|
||||
|
||||
throw InvalidOperationException(SR::ObjectDisposed_StreamClosed);
|
||||
}
|
||||
|
||||
auto buffer = std::vector<byte>(bufferLength);
|
||||
|
||||
int32_t bytesRead = 0;
|
||||
|
||||
while ((bytesRead = Read(buffer.data(), static_cast<int32_t>(buffer.size()), 0, static_cast<int32_t>(buffer.size()))) != 0)
|
||||
{
|
||||
destination.Write(buffer.data(), static_cast<int32_t>(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<int32_t>(std::min(static_cast<int64_t>(bufferLength), remaining));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bufferLength;
|
||||
}
|
||||
|
||||
int32_t Stream::Read(uint8_t* buffer, int32_t bufferLength) {
|
||||
ValidateBuffer(buffer, bufferLength);
|
||||
|
||||
auto sharedBuffer = std::vector<byte>(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<byte>(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<uint8_t>& MemoryStream::GetBuffer() {
|
||||
if (!_exposable) {
|
||||
throw UnauthorizedAccessException(SR::UnauthorizedAccess_MemStreamBuffer);
|
||||
}
|
||||
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
bool MemoryStream::TryGetBuffer(std::vector<uint8_t>& 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<byte>(value);
|
||||
|
||||
if (_length > 0)
|
||||
{
|
||||
//Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _length);
|
||||
std::memmove(newBuffer.data(), _buffer.data(), _length);
|
||||
}
|
||||
|
||||
_buffer = newBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer = std::vector<byte>();
|
||||
}
|
||||
_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<int32_t>(_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<int32_t>(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<int32_t>(_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<int32_t>(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<byte>(_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<int32_t>(_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<int64_t>(_length);
|
||||
}
|
||||
|
||||
void FileStream::EnsureNotClosed() const {
|
||||
if (!stream.is_open())
|
||||
throw InvalidOperationException(SR::ObjectDisposed_StreamClosed);
|
||||
}
|
||||
|
||||
int64_t FileStream::Position() const {
|
||||
EnsureNotClosed();
|
||||
return static_cast<int64_t>(_position);
|
||||
}
|
||||
|
||||
void FileStream::Position(int64_t value) {
|
||||
EnsureNotClosed();
|
||||
const auto _position = static_cast<std::streampos>(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<byte>(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<std::streamoff>(offset), static_cast<int>(origin));
|
||||
_position = stream.tellg();
|
||||
return static_cast<int64_t>(_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<char*>(buffer);
|
||||
stream.read(buff + offset, count);
|
||||
|
||||
if (stream.rdstate() != std::fstream::goodbit) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<int32_t>(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 result = static_cast<int32_t>(c);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FileStream::Write(uint8_t const* buffer, int32_t bufferLength, int32_t offset, int32_t count) {
|
||||
EnsureNotClosed();
|
||||
EnsureWriteable();
|
||||
|
||||
auto buff = reinterpret_cast<const char*>(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<char>(value);
|
||||
|
||||
stream.write(&c, 1);
|
||||
|
||||
if (stream.rdstate() != std::fstream::goodbit) {
|
||||
throw InvalidOperationException();
|
||||
}
|
||||
|
||||
SetStreamLength();
|
||||
}
|
||||
|
||||
std::fstream& FileStream::GetBuffer() {
|
||||
return stream;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user