1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "Prerequisites/BsPrerequisitesUtil.h"
6#include <istream>
7
8namespace bs
9{
10 /** @addtogroup Filesystem
11 * @{
12 */
13
14 /** Supported encoding types for strings. */
15 enum class StringEncoding
16 {
17 UTF8 = 1,
18 UTF16 = 2
19 };
20
21 /**
22 * General purpose class used for encapsulating the reading and writing of data from and to various sources using a
23 * common interface.
24 */
25 class BS_UTILITY_EXPORT DataStream
26 {
27 public:
28 enum AccessMode
29 {
30 READ = 1,
31 WRITE = 2
32 };
33
34 public:
35 /** Creates an unnamed stream. */
36 DataStream(UINT16 accessMode = READ)
37 : mAccess(accessMode)
38 { }
39
40 /** Creates a named stream. */
41 DataStream(const String& name, UINT16 accessMode = READ)
42 :mName(name), mAccess(accessMode) {}
43
44 virtual ~DataStream() = default;
45
46 const String& getName() const { return mName; }
47 UINT16 getAccessMode() const { return mAccess; }
48
49 virtual bool isReadable() const { return (mAccess & READ) != 0; }
50 virtual bool isWriteable() const { return (mAccess & WRITE) != 0; }
51 virtual bool isFile() const = 0;
52
53 /** Reads data from the buffer and copies it to the specified value. */
54 template<typename T> DataStream& operator>>(T& val);
55
56 /**
57 * Read the requisite number of bytes from the stream, stopping at the end of the file. Advances
58 * the read pointer.
59 *
60 * @param[in] buf Pre-allocated buffer to read the data into.
61 * @param[in] count Number of bytes to read.
62 * @return Number of bytes actually read.
63 *
64 * @note Stream must be created with READ access mode.
65 */
66 virtual size_t read(void* buf, size_t count) = 0;
67
68 /**
69 * Write the requisite number of bytes to the stream and advance the write pointer.
70 *
71 * @param[in] buf Buffer containing bytes to write.
72 * @param[in] count Number of bytes to write.
73 * @return Number of bytes actually written.
74 *
75 * @note Stream must be created with WRITE access mode.
76 */
77 virtual size_t write(const void* buf, size_t count) { return 0; }
78
79 /**
80 * Writes the provided narrow string to the steam. String is convered to the required encoding before being written.
81 *
82 * @param[in] string String containing narrow characters to write, encoded as UTF8.
83 * @param[in] encoding Encoding to convert the string to before writing.
84 */
85 virtual void writeString(const String& string, StringEncoding encoding = StringEncoding::UTF8);
86
87 /**
88 * Writes the provided wide string to the steam. String is convered to the required encoding before being written.
89 *
90 * @param[in] string String containing wide characters to write, encoded as specified by platform for
91 * wide characters.
92 * @param[in] encoding Encoding to convert the string to before writing.
93 */
94 virtual void writeString(const WString& string, StringEncoding encoding = StringEncoding::UTF8);
95
96 /**
97 * Returns a string containing the entire stream.
98 *
99 * @return String data encoded as UTF-8.
100 *
101 * @note This is a convenience method for text streams only, allowing you to retrieve a String object containing
102 * all the data in the stream.
103 */
104 virtual String getAsString();
105
106 /**
107 * Returns a wide string containing the entire stream.
108 *
109 * @return Wide string encoded as specified by current platform.
110 *
111 * @note This is a convenience method for text streams only, allowing you to retrieve a WString object
112 * containing all the data in the stream.
113 */
114 virtual WString getAsWString();
115
116 /**
117 * Skip a defined number of bytes. This can also be a negative value, in which case the file pointer rewinds a
118 * defined number of bytes.
119 */
120 virtual void skip(size_t count) = 0;
121
122 /** Repositions the read point to a specified byte. */
123 virtual void seek(size_t pos) = 0;
124
125 /** Returns the current byte offset from beginning. */
126 virtual size_t tell() const = 0;
127
128 /** Returns true if the stream has reached the end. */
129 virtual bool eof() const = 0;
130
131 /** Returns the total size of the data to be read from the stream, or 0 if this is indeterminate for this stream. */
132 size_t size() const { return mSize; }
133
134 /**
135 * Creates a copy of this stream.
136 *
137 * @param[in] copyData If true the internal stream data will be copied as well, otherwise it will just
138 * reference the data from the original stream (in which case the caller must ensure the
139 * original stream outlives the clone). This is not relevant for file streams.
140 */
141 virtual SPtr<DataStream> clone(bool copyData = true) const = 0;
142
143 /** Close the stream. This makes further operations invalid. */
144 virtual void close() = 0;
145
146 protected:
147 static const UINT32 StreamTempSize;
148
149 String mName;
150 size_t mSize = 0;
151 UINT16 mAccess;
152 };
153
154 /** Data stream for handling data from memory. */
155 class BS_UTILITY_EXPORT MemoryDataStream : public DataStream
156 {
157 public:
158 /**
159 * Allocates a new chunk of memory and wraps it in a stream.
160 *
161 * @param[in] size Size of the memory chunk in bytes.
162 */
163 MemoryDataStream(size_t size);
164
165 /**
166 * Wrap an existing memory chunk in a stream.
167 *
168 * @param[in] memory Memory to wrap the data stream around.
169 * @param[in] size Size of the memory chunk in bytes.
170 * @param[in] freeOnClose Should the memory buffer be freed when the data stream goes out of scope.
171 */
172 MemoryDataStream(void* memory, size_t size, bool freeOnClose = true);
173
174 /**
175 * Create a stream which pre-buffers the contents of another stream. Data from the other buffer will be entirely
176 * read and stored in an internal buffer.
177 *
178 * @param[in] sourceStream Stream to read data from.
179 */
180 MemoryDataStream(DataStream& sourceStream);
181
182 /**
183 * Create a stream which pre-buffers the contents of another stream. Data from the other buffer will be entirely
184 * read and stored in an internal buffer.
185 *
186 * @param[in] sourceStream Stream to read data from.
187 */
188 MemoryDataStream(const SPtr<DataStream>& sourceStream);
189
190 ~MemoryDataStream();
191
192 bool isFile() const override { return false; }
193
194 /** Get a pointer to the start of the memory block this stream holds. */
195 UINT8* getPtr() const { return mData; }
196
197 /** Get a pointer to the current position in the memory block this stream holds. */
198 UINT8* getCurrentPtr() const { return mPos; }
199
200 /** @copydoc DataStream::read */
201 size_t read(void* buf, size_t count) override;
202
203 /** @copydoc DataStream::write */
204 size_t write(const void* buf, size_t count) override;
205
206 /** @copydoc DataStream::skip */
207 void skip(size_t count) override;
208
209 /** @copydoc DataStream::seek */
210 void seek(size_t pos) override;
211
212 /** @copydoc DataStream::tell */
213 size_t tell() const override;
214
215 /** @copydoc DataStream::eof */
216 bool eof() const override;
217
218 /** @copydoc DataStream::clone */
219 SPtr<DataStream> clone(bool copyData = true) const override;
220
221 /** @copydoc DataStream::close */
222 void close() override;
223
224 protected:
225 UINT8* mData;
226 UINT8* mPos;
227 UINT8* mEnd;
228
229 bool mFreeOnClose;
230 };
231
232 /** Data stream for handling data from standard streams. */
233 class BS_UTILITY_EXPORT FileDataStream : public DataStream
234 {
235 public:
236 /**
237 * Construct a file stream.
238 *
239 * @param[in] filePath Path of the file to open.
240 * @param[in] accessMode Determines should the file be opened in read, write or read/write mode.
241 * @param[in] freeOnClose Determines should the internal stream be freed once the data stream is closed or goes
242 * out of scope.
243 */
244 FileDataStream(const Path& filePath, AccessMode accessMode = READ, bool freeOnClose = true);
245
246 ~FileDataStream();
247
248 bool isFile() const override { return true; }
249
250 /** @copydoc DataStream::read */
251 size_t read(void* buf, size_t count) override;
252
253 /** @copydoc DataStream::write */
254 size_t write(const void* buf, size_t count) override;
255
256 /** @copydoc DataStream::skip */
257 void skip(size_t count) override;
258
259 /** @copydoc DataStream::seek */
260 void seek(size_t pos) override;
261
262 /** @copydoc DataStream::tell */
263 size_t tell() const override;
264
265 /** @copydoc DataStream::eof */
266 bool eof() const override;
267
268 /** @copydoc DataStream::clone */
269 SPtr<DataStream> clone(bool copyData = true) const override;
270
271 /** @copydoc DataStream::close */
272 void close() override;
273
274 /** Returns the path of the file opened by the stream. */
275 const Path& getPath() const { return mPath; }
276
277 protected:
278 Path mPath;
279 SPtr<std::istream> mInStream;
280 SPtr<std::ifstream> mFStreamRO;
281 SPtr<std::fstream> mFStream;
282 bool mFreeOnClose;
283 };
284
285 /** @} */
286}
287
288