Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/psx/mednadisc/MemoryStream.cpp
2 views
1
/* Mednafen - Multi-system Emulator
2
*
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation; either version 2 of the License, or
6
* (at your option) any later version.
7
*
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
12
*
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
*/
17
18
#include <stdlib.h>
19
#include "MemoryStream.h"
20
#include "math_ops.h"
21
#include "error.h"
22
23
//work around gettext
24
#define _(X) X
25
26
/*
27
TODO: Copy and assignment constructor fixes.
28
29
Proper negative position behavior?
30
*/
31
32
MemoryStream::MemoryStream() : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
33
{
34
data_buffer_size = 0;
35
data_buffer_alloced = 64;
36
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
37
throw MDFN_Error(ErrnoHolder(errno));
38
}
39
40
MemoryStream::MemoryStream(uint64 alloc_hint, int alloc_hint_is_size) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
41
{
42
if(alloc_hint_is_size != 0)
43
{
44
data_buffer_size = alloc_hint;
45
data_buffer_alloced = alloc_hint;
46
47
if(alloc_hint > SIZE_MAX)
48
throw MDFN_Error(ErrnoHolder(ENOMEM));
49
}
50
else
51
{
52
data_buffer_size = 0;
53
data_buffer_alloced = (alloc_hint > SIZE_MAX) ? SIZE_MAX : alloc_hint;
54
}
55
56
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
57
throw MDFN_Error(ErrnoHolder(errno));
58
59
if(alloc_hint_is_size > 0)
60
memset(data_buffer, 0, data_buffer_size);
61
}
62
63
MemoryStream::MemoryStream(Stream *stream, uint64 size_limit) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
64
{
65
try
66
{
67
if((position = stream->tell()) != 0)
68
stream->seek(0, SEEK_SET);
69
70
void* tp;
71
data_buffer_size = data_buffer_alloced = stream->alloc_and_read(&tp, size_limit);
72
data_buffer = (uint8*)tp;
73
stream->close();
74
}
75
catch(...)
76
{
77
if(data_buffer)
78
{
79
free(data_buffer);
80
data_buffer = NULL;
81
}
82
83
delete stream;
84
throw;
85
}
86
delete stream;
87
}
88
89
MemoryStream::MemoryStream(const MemoryStream &zs)
90
{
91
data_buffer_size = zs.data_buffer_size;
92
data_buffer_alloced = zs.data_buffer_alloced;
93
if(!(data_buffer = (uint8*)malloc(data_buffer_alloced)))
94
throw MDFN_Error(ErrnoHolder(errno));
95
96
memcpy(data_buffer, zs.data_buffer, data_buffer_size);
97
98
position = zs.position;
99
}
100
101
#if 0
102
MemoryStream & MemoryStream::operator=(const MemoryStream &zs)
103
{
104
if(this != &zs)
105
{
106
if(data_buffer)
107
{
108
free(data_buffer);
109
data_buffer = NULL;
110
}
111
112
data_buffer_size = zs.data_buffer_size;
113
data_buffer_alloced = zs.data_buffer_alloced;
114
115
if(!(data_buffer = (uint8*)malloc(data_buffer_alloced)))
116
throw MDFN_Error(ErrnoHolder(errno));
117
118
memcpy(data_buffer, zs.data_buffer, data_buffer_size);
119
120
position = zs.position;
121
}
122
return(*this);
123
}
124
#endif
125
126
MemoryStream::~MemoryStream()
127
{
128
if(data_buffer)
129
{
130
free(data_buffer);
131
data_buffer = NULL;
132
}
133
}
134
135
uint64 MemoryStream::attributes(void)
136
{
137
return (ATTRIBUTE_READABLE | ATTRIBUTE_WRITEABLE | ATTRIBUTE_SEEKABLE);
138
}
139
140
141
uint8 *MemoryStream::map(void) noexcept
142
{
143
return data_buffer;
144
}
145
146
uint64 MemoryStream::map_size(void) noexcept
147
{
148
return data_buffer_size;
149
}
150
151
void MemoryStream::unmap(void) noexcept
152
{
153
154
}
155
156
157
INLINE void MemoryStream::grow_if_necessary(uint64 new_required_size, uint64 hole_end)
158
{
159
if(new_required_size > data_buffer_size)
160
{
161
const uint64 old_data_buffer_size = data_buffer_size;
162
163
if(new_required_size > data_buffer_alloced)
164
{
165
uint64 new_required_alloced = round_up_pow2(new_required_size);
166
uint8 *new_data_buffer;
167
168
// first condition will happen at new_required_size > (1ULL << 63) due to round_up_pow2() "wrapping".
169
// second condition can occur when running on a 32-bit system.
170
if(new_required_alloced < new_required_size || new_required_alloced > SIZE_MAX)
171
new_required_alloced = SIZE_MAX;
172
173
// If constrained alloc size isn't enough, throw an out-of-memory/address-space type error.
174
if(new_required_alloced < new_required_size)
175
throw MDFN_Error(ErrnoHolder(ENOMEM));
176
177
if(!(new_data_buffer = (uint8*)realloc(data_buffer, new_required_alloced)))
178
throw MDFN_Error(ErrnoHolder(errno));
179
180
//
181
// Assign all in one go after the realloc() so we don't leave our object in an inconsistent state if the realloc() fails.
182
//
183
data_buffer = new_data_buffer;
184
data_buffer_size = new_required_size;
185
data_buffer_alloced = new_required_alloced;
186
}
187
else
188
data_buffer_size = new_required_size;
189
190
if(hole_end > old_data_buffer_size)
191
memset(data_buffer + old_data_buffer_size, 0, hole_end - old_data_buffer_size);
192
}
193
}
194
195
void MemoryStream::shrink_to_fit(void) noexcept
196
{
197
if(data_buffer_alloced > data_buffer_size)
198
{
199
uint8 *new_data_buffer;
200
201
new_data_buffer = (uint8*)realloc(data_buffer, data_buffer_size);
202
203
if(new_data_buffer != NULL)
204
{
205
data_buffer = new_data_buffer;
206
data_buffer_alloced = data_buffer_size;
207
}
208
}
209
}
210
211
uint64 MemoryStream::read(void *data, uint64 count, bool error_on_eos)
212
{
213
//printf("%llu %llu %llu\n", position, count, data_buffer_size);
214
215
if(count > data_buffer_size)
216
{
217
if(error_on_eos)
218
throw MDFN_Error(0, _("Unexpected EOF"));
219
220
count = data_buffer_size;
221
}
222
223
if(position > (data_buffer_size - count))
224
{
225
if(error_on_eos)
226
throw MDFN_Error(0, _("Unexpected EOF"));
227
228
if(data_buffer_size > position)
229
count = data_buffer_size - position;
230
else
231
count = 0;
232
}
233
234
memmove(data, &data_buffer[position], count);
235
position += count;
236
237
return count;
238
}
239
240
void MemoryStream::write(const void *data, uint64 count)
241
{
242
uint64 nrs = position + count;
243
244
if(nrs < position)
245
throw MDFN_Error(ErrnoHolder(EFBIG));
246
247
grow_if_necessary(nrs, position);
248
249
memmove(&data_buffer[position], data, count);
250
position += count;
251
}
252
253
//
254
// Don't add code to reduce the amount of memory allocated(when possible) without providing a
255
// per-stream setting to disable that behavior.
256
//
257
void MemoryStream::truncate(uint64 length)
258
{
259
grow_if_necessary(length, length);
260
261
data_buffer_size = length;
262
}
263
264
void MemoryStream::seek(int64 offset, int whence)
265
{
266
uint64 new_position;
267
268
switch(whence)
269
{
270
default:
271
throw MDFN_Error(ErrnoHolder(EINVAL));
272
break;
273
274
case SEEK_SET:
275
new_position = offset;
276
break;
277
278
case SEEK_CUR:
279
new_position = position + offset;
280
break;
281
282
case SEEK_END:
283
new_position = data_buffer_size + offset;
284
break;
285
}
286
287
if(new_position < 0)
288
throw MDFN_Error(ErrnoHolder(EINVAL));
289
290
position = new_position;
291
}
292
293
uint64 MemoryStream::tell(void)
294
{
295
return position;
296
}
297
298
uint64 MemoryStream::size(void)
299
{
300
return data_buffer_size;
301
}
302
303
void MemoryStream::flush(void)
304
{
305
306
}
307
308
void MemoryStream::close(void)
309
{
310
311
}
312
313
314
int MemoryStream::get_line(std::string &str)
315
{
316
str.clear(); // or str.resize(0)??
317
318
while((uint64)position < data_buffer_size)
319
{
320
uint8 c = data_buffer[position++];
321
322
if(c == '\r' || c == '\n' || c == 0)
323
return(c);
324
325
str.push_back(c); // Should be faster than str.append(1, c)
326
}
327
328
return(str.length() ? 256 : -1);
329
}
330
331
332