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