DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
FileStream.cpp
Go to the documentation of this file.
1#include "pch.h"
6#include <filesystem>
7#include <fstream>
8
9#if defined(_WIN32)
10#include "Win32Internal.h"
11#endif
12
13namespace fs = std::filesystem;
14
15namespace {
17 fs::path ToFsPath(const DotNetDupe::System::String& sPath) {
18#if defined(_WIN32)
20#else
21 return fs::path(sPath.GetRawString());
22#endif
23 }
24}
25
26namespace DotNetDupe {
27 namespace System {
28 namespace IO {
29 struct FileStream::Impl {
30 std::fstream fs;
31 };
32
34 static std::ios_base::openmode DetermineOpenMode(int iMode, const String& sPath, bool& bCanRead, bool& bCanWrite, bool& bCanSeek) {
36 if (iMode < 0 || iMode > 5) throw ArgumentException("Invalid FileMode");
37 if (iMode == 0 && fs::exists(ToFsPath(sPath))) throw IOException("File already exists.");
38
40 if (iMode == 5) {
41 bCanRead = false; bCanWrite = true; bCanSeek = false;
42 return std::ios_base::binary | std::ios_base::out | std::ios_base::app;
43 }
44
46 bCanRead = true; bCanWrite = true; bCanSeek = true;
47 std::ios_base::openmode m = std::ios_base::binary | std::ios_base::in | std::ios_base::out;
48 if (iMode == 0 || iMode == 1 || iMode == 4) m |= std::ios_base::trunc;
49 return m;
50 }
51
52 FileStream::FileStream(const String& sPath, int iMode) : m_pImpl(new Impl()), m_sPath(sPath), m_iMode(iMode) {
54 std::ios_base::openmode openMode = DetermineOpenMode(iMode, sPath, m_bCanRead, m_bCanWrite, m_bCanSeek);
55
57 m_pImpl->fs.open(ToFsPath(sPath), openMode);
58 if (!m_pImpl->fs.is_open()) throw IOException("Could not open file.");
59 }
60
63 Dispose();
64 if (m_pImpl) {
65 delete m_pImpl;
66 m_pImpl = nullptr;
67 }
68 }
69
70 bool FileStream::CanRead() const {
71 return m_bCanRead;
72 }
73
74 bool FileStream::CanSeek() const {
75 return m_bCanSeek;
76 }
77
78 bool FileStream::CanWrite() const {
79 return m_bCanWrite;
80 }
81
82 long FileStream::GetLength() const {
84 if (!CanSeek() || !m_pImpl) {
85 throw IOException("Stream does not support seeking.");
86 }
87
89 auto& mutableStream = m_pImpl->fs;
90 long iCurrentPos = static_cast<long>(mutableStream.tellg());
91 mutableStream.seekg(0, std::ios_base::end);
92 long iLength = static_cast<long>(mutableStream.tellg());
93 mutableStream.seekg(iCurrentPos);
94 return iLength;
95 }
96
99 if (!CanSeek() || !m_pImpl) {
100 throw IOException("Stream does not support seeking.");
101 }
102
104 return static_cast<long>(m_pImpl->fs.tellg());
105 }
106
107 void FileStream::SetPosition(long llValue) {
109 if (!CanSeek() || !m_pImpl) {
110 throw IOException("Stream does not support seeking.");
111 }
112
114 m_pImpl->fs.seekg(llValue);
115 }
116
119 if (!m_pImpl) return;
120
122 m_pImpl->fs.flush();
123 if (m_pImpl->fs.bad()) {
124 throw IOException("Flush failed.");
125 }
126 }
127
128 int FileStream::Read(char* pBuffer, int iOffset, int nCount) {
130 if (!CanRead() || !m_pImpl) {
131 throw IOException("Stream does not support reading.");
132 }
133
135 m_pImpl->fs.read(pBuffer + iOffset, nCount);
136 if (m_pImpl->fs.bad()) {
137 throw IOException("A read error occurred.");
138 }
139
141 if (m_pImpl->fs.eof()) {
142 m_pImpl->fs.clear();
143 }
144
145 return static_cast<int>(m_pImpl->fs.gcount());
146 }
147
148 long FileStream::Seek(long llOffset, int iOrigin) {
150 if (!CanSeek() || !m_pImpl) {
151 throw IOException("Stream does not support seeking.");
152 }
153
155 std::ios_base::seekdir dir;
156 if (iOrigin == 0) {
157 dir = std::ios_base::beg;
158 } else if (iOrigin == 1) {
159 dir = std::ios_base::cur;
160 } else if (iOrigin == 2) {
161 dir = std::ios_base::end;
162 } else {
163 throw ArgumentException("Invalid SeekOrigin");
164 }
165
167 m_pImpl->fs.seekg(llOffset, dir);
168 return static_cast<long>(m_pImpl->fs.tellg());
169 }
170
171 void FileStream::SetLength(long llValue) {
172 throw IOException("SetLength is not supported.");
173 }
174
175 void FileStream::Write(const char* pBuffer, int iOffset, int nCount) {
177 if (!CanWrite() || !m_pImpl) {
178 throw IOException("Stream does not support writing.");
179 }
180
182 m_pImpl->fs.write(pBuffer + iOffset, nCount);
183 if (m_pImpl->fs.bad() || m_pImpl->fs.fail()) {
184 throw IOException("A write error occurred.");
185 }
186 }
187
190 if (m_pImpl && m_pImpl->fs.is_open()) {
191 m_pImpl->fs.close();
192 }
193
195 m_bCanRead = false;
196 m_bCanWrite = false;
197 m_bCanSeek = false;
198 }
199 }
200 }
201}
Defines the exception thrown when an invalid argument is provided to a method.
Defines the exception thrown when an argument value is outside the acceptable range of values.
The exception that is thrown when an I/O error occurs.
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
int Read(char *pBuffer, int iOffset, int nCount) override
Reads a block of bytes from the stream and writes the data in a given buffer.
bool CanSeek() const override
Gets a value indicating whether the current stream supports seeking.
void Write(const char *pBuffer, int iOffset, int nCount) override
Writes a block of bytes to the file stream.
long Seek(long llOffset, int iOrigin) override
Sets the current position of this stream to the given value.
bool CanRead() const override
Gets a value indicating whether the current stream supports reading.
void SetPosition(long llValue) override
Sets the current position within the stream.
~FileStream() override
Destructor releasing encapsulated native stream resources.
long GetLength() const override
Gets the length in bytes of the stream.
void Flush() override
Clears buffers for this stream and causes any unwritten data to be written to the file.
long GetPosition() const override
Gets the current position within the stream.
void SetLength(long llValue) override
Sets the length of this stream to the given value.
void Dispose() override
Releases all unmanaged resources used by the FileStream.
bool CanWrite() const override
Gets a value indicating whether the current stream supports writing.
FileStream(const String &sPath, int iMode)
Initializes a new instance of the FileStream class with the specified path and creation mode.
IOException()
Initializes a new instance of the IOException class with a default message.
Definition Exception.cpp:56
static std::wstring Utf8ToWChar(const char *pUtf8Str)
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
Definition String.h:74
const char * GetRawString() const
Definition String.cpp:230
static std::ios_base::openmode DetermineOpenMode(int iMode, const String &sPath, bool &bCanRead, bool &bCanWrite, bool &bCanSeek)
Determine stream openmode and capability flags from FileMode.