#ifndef XNA_CSHARP_STREAM_HPP #define XNA_CSHARP_STREAM_HPP #include "../types.hpp" #include "../enums.hpp" #include "../xnaerror.hpp" #include <fstream> #include <filesystem> namespace xna { class Stream { public: virtual ~Stream(){} virtual Int Length() = 0; virtual Long Position() = 0; virtual void Close() = 0; virtual bool IsClosed() = 0; virtual Long Seek(Long offset, SeekOrigin const& origin, xna_error_nullarg) = 0; virtual Int Read(Byte* buffer, Int bufferLength, Int offset, Int count, xna_error_nullarg) = 0; virtual Int Read(std::vector<Byte>& buffer, Int offset, Int count, xna_error_nullarg) = 0; virtual Int ReadByte(xna_error_nullarg) = 0; virtual void Write(Byte const* buffer, Int bufferLength, Int offset, Int count, xna_error_nullarg) = 0; virtual void Write(std::vector<Byte> const& buffer, Int offset, Int count, xna_error_nullarg) = 0; virtual void WriteByte(Byte value, xna_error_nullarg) = 0; }; class MemoryStream : public Stream { public: constexpr MemoryStream(Int capacity) : _buffer(static_cast<size_t>(capacity)), _length(capacity > 0 ? capacity : 0){} virtual constexpr Int Length() override { if (_closed) return 0; return _length; } virtual constexpr Long Position() override { if (_closed) return 0; return _position; } virtual constexpr void Close() override { _closed = true; _buffer = std::vector<Byte>(); } virtual constexpr bool IsClosed() override { return _closed; } virtual Long Seek(Long offset, SeekOrigin const& origin, xna_error_nullarg) override; virtual Int Read(Byte* buffer, Int bufferLength, Int offset, Int count, xna_error_nullarg) override; virtual Int Read(std::vector<Byte>& buffer, Int offset, Int count, xna_error_nullarg) override; virtual Int ReadByte(xna_error_nullarg) override; virtual void Write(Byte const* buffer, Int bufferLength, Int offset, Int count, xna_error_nullarg) override; virtual void Write(std::vector<Byte> const& buffer, Int offset, Int count, xna_error_nullarg) override; virtual void WriteByte(Byte value, xna_error_nullarg) override; public: Int _position{ 0 }; Int _origin{ 0 }; Int _length{ 0 }; std::vector<Byte> _buffer; bool _closed{ false }; }; class FileStream : public Stream { public: FileStream(String const& path, FileMode fileMode) { int flags = std::fstream::in | std::fstream::out | std::fstream::binary; const auto exists = std::filesystem::exists(path); switch (fileMode) { //Especifica se deve abrir um arquivo existente. case FileMode::Open: if (!exists) { _closed = true; return; } 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 return; 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. //Tentativa de ler um arquivo truncado retornar� 0; case FileMode::Truncate: flags |= std::fstream::trunc; _truncated = true; break; default: break; } _fstream.open(path.c_str(), flags); if (!_fstream.good()) _closed = true; } FileStream(String const& path){ int flags = std::fstream::in | std::fstream::out | std::fstream::binary; //| std::fstream::ate; const auto exists = std::filesystem::exists(path); if (!exists) flags |= std::fstream::trunc; _fstream.open(path.c_str(), flags); if (!_fstream.good()) _closed = true; } ~FileStream() { Close(); } virtual Int Length() override { if (_closed) return 0; const auto end = endOfFile(); return end; } virtual Long Position() override { if (_closed) return 0; return static_cast<Long>(_fstream.tellg()); } virtual void Close() override { _closed = true; if(_fstream.is_open()) _fstream.close(); } virtual constexpr bool IsClosed() override { return _closed; } virtual Long Seek(Long offset, SeekOrigin const& origin, xna_error_nullarg) override; virtual Int Read(Byte* buffer, Int bufferLength, Int offset, Int count, xna_error_nullarg) override; virtual Int Read(std::vector<Byte>& buffer, Int offset, Int count, xna_error_nullarg) override; virtual Int ReadByte(xna_error_nullarg) override; virtual void Write(Byte const* buffer, Int bufferLength, Int offset, Int count, xna_error_nullarg) override; virtual void Write(std::vector<Byte> const& buffer, Int offset, Int count, xna_error_nullarg) override; virtual void WriteByte(Byte value, xna_error_nullarg) override; public: std::fstream _fstream; private: std::streampos _filesize{ 0 }; bool _closed{ false }; bool _truncated{ false }; Int endOfFile() { if (_closed) return 0; const auto pos = _fstream.tellg(); _fstream.seekg(0, std::ios_base::end); const auto end = _fstream.tellg(); _fstream.seekg(pos); return static_cast<Int>(end); } }; } #endif