1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24
25 #include "bstone_memory_stream.h"
26 #include <cstddef>
27 #include <algorithm>
28
29
30 namespace bstone {
31
32
MemoryStream(int initial_capacity,StreamOpenMode open_mode)33 MemoryStream::MemoryStream(
34 int initial_capacity,
35 StreamOpenMode open_mode) :
36 is_open_(),
37 can_read_(),
38 can_write_(),
39 position_(),
40 size_(),
41 ext_size_(),
42 buffer_(),
43 ext_buffer_()
44 {
45 open(initial_capacity, open_mode);
46 }
47
MemoryStream(int buffer_size,int buffer_offset,const uint8_t * buffer,StreamOpenMode open_mode)48 MemoryStream::MemoryStream(
49 int buffer_size,
50 int buffer_offset,
51 const uint8_t* buffer,
52 StreamOpenMode open_mode) :
53 is_open_(),
54 can_read_(),
55 can_write_(),
56 position_(),
57 size_(),
58 ext_size_(),
59 buffer_(),
60 ext_buffer_()
61 {
62 open(buffer_size, buffer_offset, buffer, open_mode);
63 }
64
65 // (virtual)
~MemoryStream()66 MemoryStream::~MemoryStream()
67 {
68 close();
69 }
70
open(int initial_capacity,StreamOpenMode open_mode)71 bool MemoryStream::open(
72 int initial_capacity,
73 StreamOpenMode open_mode)
74 {
75 close();
76
77
78 bool is_readable = false;
79 bool is_writable = false;
80
81 switch (open_mode) {
82 case StreamOpenMode::read:
83 is_readable = true;
84 break;
85
86 case StreamOpenMode::write:
87 is_writable = true;
88 break;
89
90 case StreamOpenMode::read_write:
91 is_readable = true;
92 is_writable = true;
93 break;
94
95 default:
96 return false;
97 }
98
99
100 if (initial_capacity < 0) {
101 initial_capacity = 0;
102 }
103
104 int_buffer_.reserve(initial_capacity);
105
106 is_open_ = true;
107 can_read_ = is_readable;
108 can_write_ = is_writable;
109
110 return true;
111 }
112
open(int buffer_size,int buffer_offset,const uint8_t * buffer,StreamOpenMode open_mode)113 bool MemoryStream::open(
114 int buffer_size,
115 int buffer_offset,
116 const uint8_t* buffer,
117 StreamOpenMode open_mode)
118 {
119 close();
120
121 if (buffer_size < 0) {
122 return false;
123 }
124
125 if (!buffer) {
126 return false;
127 }
128
129
130 bool is_readable = false;
131 bool is_writable = false;
132
133 switch (open_mode) {
134 case StreamOpenMode::read:
135 is_readable = true;
136 break;
137
138 case StreamOpenMode::write:
139 is_writable = true;
140 break;
141
142 case StreamOpenMode::read_write:
143 is_readable = true;
144 is_writable = true;
145 break;
146
147 default:
148 return false;
149 }
150
151
152 is_open_ = true;
153 can_read_ = is_readable;
154 can_write_ = is_writable;
155 size_ = buffer_size;
156 ext_size_ = buffer_size;
157 buffer_ = const_cast<uint8_t*>(&buffer[buffer_offset]);
158 ext_buffer_ = buffer_;
159
160 return true;
161 }
162
163 // (virtual)
close()164 void MemoryStream::close()
165 {
166 can_read_ = false;
167 can_write_ = false;
168 position_ = 0;
169 size_ = 0;
170 ext_size_ = 0;
171 buffer_ = nullptr;
172 ext_buffer_ = nullptr;
173 Buffer().swap(int_buffer_);
174 }
175
176 // (virtual)
is_open() const177 bool MemoryStream::is_open() const
178 {
179 return is_open_;
180 }
181
182 // (virtual)
get_size()183 int64_t MemoryStream::get_size()
184 {
185 return size_;
186 }
187
188 // (virtual)
set_size(int64_t size)189 bool MemoryStream::set_size(
190 int64_t size)
191 {
192 if (!is_open()) {
193 return false;
194 }
195
196 if (!can_write()) {
197 return false;
198 }
199
200 if (size < 0) {
201 return false;
202 }
203
204 if (ext_buffer_) {
205 return false;
206 }
207
208 int_buffer_.resize(static_cast<size_t>(size));
209
210 size_ = size;
211
212 if (size_ > 0) {
213 buffer_ = reinterpret_cast<uint8_t*>(&int_buffer_[0]);
214 } else {
215 buffer_ = nullptr;
216 }
217
218 return true;
219 }
220
221 // (virtual)
flush()222 bool MemoryStream::flush()
223 {
224 return is_open();
225 }
226
227 // (virtual)
seek(int64_t offset,StreamSeekOrigin origin)228 int64_t MemoryStream::seek(
229 int64_t offset,
230 StreamSeekOrigin origin)
231 {
232 if (!is_open()) {
233 return -1;
234 }
235
236 if (!can_seek()) {
237 return -1;
238 }
239
240 switch (origin) {
241 case StreamSeekOrigin::begin:
242 position_ = offset;
243 break;
244
245 case StreamSeekOrigin::current:
246 position_ += offset;
247 break;
248
249 case StreamSeekOrigin::end:
250 position_ = size_ + offset;
251 break;
252
253 default:
254 return -1;
255 }
256
257 if (position_ < 0) {
258 position_ = 0;
259 }
260
261 return position_;
262 }
263
264 // (virtual)
get_position()265 int64_t MemoryStream::get_position()
266 {
267 return position_;
268 }
269
270 // (virtual)
read(void * buffer,int count)271 int MemoryStream::read(
272 void* buffer,
273 int count)
274 {
275 if (!is_open()) {
276 return 0;
277 }
278
279 if (!can_read()) {
280 return 0;
281 }
282
283 if (!buffer) {
284 return 0;
285 }
286
287 if (count <= 0) {
288 return 0;
289 }
290
291 auto remain = size_ - position_;
292
293 if (remain <= 0) {
294 return 0;
295 }
296
297 auto read_count = static_cast<int>(std::min(
298 static_cast<int64_t>(count),
299 remain));
300
301 std::uninitialized_copy_n(
302 &buffer_[position_],
303 read_count,
304 static_cast<uint8_t*>(buffer));
305
306 position_ += read_count;
307
308 return read_count;
309 }
310
311 // (virtual)
write(const void * buffer,int count)312 bool MemoryStream::write(
313 const void* buffer,
314 int count)
315 {
316 if (!is_open()) {
317 return false;
318 }
319
320 if (!can_write()) {
321 return false;
322 }
323
324 if (count < 0) {
325 return false;
326 }
327
328 if (count == 0) {
329 return true;
330 }
331
332 if (!buffer) {
333 return false;
334 }
335
336 if (!ext_buffer_) {
337 auto new_size = position_ + count;
338
339 if (new_size > size_) {
340 int_buffer_.resize(static_cast<size_t>(new_size));
341
342 size_ = new_size;
343 buffer_ = reinterpret_cast<uint8_t*>(&int_buffer_[0]);
344 }
345 } else {
346 if ((position_ + count) > ext_size_) {
347 return false;
348 }
349 }
350
351 std::uninitialized_copy_n(
352 static_cast<const uint8_t*>(buffer),
353 count,
354 &buffer_[position_]);
355
356 position_ += count;
357
358 return true;
359 }
360
361 // (virtual)
can_read() const362 bool MemoryStream::can_read() const
363 {
364 return is_open() && can_read_;
365 }
366
367 // (virtual)
can_seek() const368 bool MemoryStream::can_seek() const
369 {
370 return is_open();
371 }
372
373 // (virtual)
can_write() const374 bool MemoryStream::can_write() const
375 {
376 return is_open() && can_write_;
377 }
378
get_data()379 uint8_t* MemoryStream::get_data()
380 {
381 return buffer_;
382 }
383
get_data() const384 const uint8_t* MemoryStream::get_data() const
385 {
386 return buffer_;
387 }
388
remove_block(int64_t offset,int count)389 bool MemoryStream::remove_block(
390 int64_t offset,
391 int count)
392 {
393 if (!is_open()) {
394 return false;
395 }
396
397 if (offset < 0) {
398 return false;
399 }
400
401 if (count < 0) {
402 return false;
403 }
404
405 if (count == 0) {
406 return true;
407 }
408
409 if ((offset + count) > size_) {
410 return false;
411 }
412
413 int_buffer_.erase(
414 int_buffer_.begin() + static_cast<ptrdiff_t>(offset),
415 int_buffer_.begin() + static_cast<ptrdiff_t>(offset) + count);
416
417 size_ -= count;
418
419 return true;
420 }
421
422
423 } // bstone
424