Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/common/binary_reader_writer.cpp
4212 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#include "binary_reader_writer.h"
5
#include "assert.h"
6
#include "error.h"
7
#include "small_string.h"
8
9
#include "common/file_system.h"
10
11
BinarySpanReader::BinarySpanReader() = default;
12
13
BinarySpanReader::BinarySpanReader(std::span<const u8> buf) : m_buf(buf)
14
{
15
}
16
17
BinarySpanReader::BinarySpanReader(BinarySpanReader&& move) : m_buf(std::move(move.m_buf)), m_pos(move.m_pos)
18
{
19
move.m_pos = 0;
20
}
21
22
BinarySpanReader& BinarySpanReader::operator=(BinarySpanReader&& move)
23
{
24
m_buf = std::move(move.m_buf);
25
m_pos = move.m_pos;
26
move.m_pos = 0;
27
return *this;
28
}
29
30
bool BinarySpanReader::PeekCString(std::string_view* dst)
31
{
32
size_t pos = m_pos;
33
size_t size = 0;
34
while (pos < m_buf.size())
35
{
36
if (m_buf[pos] == 0)
37
break;
38
39
pos++;
40
size++;
41
}
42
43
if (pos == m_buf.size())
44
return false;
45
46
*dst = std::string_view(reinterpret_cast<const char*>(&m_buf[m_pos]), size);
47
return true;
48
}
49
50
bool BinarySpanReader::PeekSizePrefixedString(std::string_view* dst)
51
{
52
u32 length;
53
if (!PeekU32(&length) || (m_pos + sizeof(length) + length) > m_buf.size()) [[unlikely]]
54
return false;
55
56
*dst = std::string_view(reinterpret_cast<const char*>(&m_buf[m_pos + sizeof(length)]), length);
57
return true;
58
}
59
60
std::span<const u8> BinarySpanReader::GetRemainingSpan(size_t size) const
61
{
62
DebugAssert(size <= GetBufferRemaining());
63
return m_buf.subspan(m_pos, size);
64
}
65
66
std::span<const u8> BinarySpanReader::GetRemainingSpan() const
67
{
68
return m_buf.subspan(m_pos, m_buf.size() - m_pos);
69
}
70
71
void BinarySpanReader::IncrementPosition(size_t size)
72
{
73
DebugAssert(size < GetBufferRemaining());
74
m_pos += size;
75
}
76
77
bool BinarySpanReader::ReadCString(std::string* dst)
78
{
79
std::string_view sv;
80
if (!PeekCString(&sv))
81
return false;
82
83
dst->assign(sv);
84
m_pos += sv.size() + 1;
85
return true;
86
}
87
88
bool BinarySpanReader::ReadCString(std::string_view* dst)
89
{
90
if (!PeekCString(dst))
91
return false;
92
93
m_pos += dst->size() + 1;
94
return true;
95
}
96
97
bool BinarySpanReader::ReadCString(SmallStringBase* dst)
98
{
99
std::string_view sv;
100
if (!PeekCString(&sv))
101
return false;
102
103
dst->assign(sv);
104
m_pos += sv.size() + 1;
105
return true;
106
}
107
108
bool BinarySpanReader::ReadSizePrefixedString(std::string* dst)
109
{
110
std::string_view sv;
111
if (!PeekSizePrefixedString(&sv))
112
return false;
113
114
dst->assign(sv);
115
m_pos += sizeof(u32) + sv.size();
116
return true;
117
}
118
119
bool BinarySpanReader::ReadSizePrefixedString(std::string_view* dst)
120
{
121
if (!PeekSizePrefixedString(dst))
122
return false;
123
124
m_pos += sizeof(u32) + dst->size();
125
return true;
126
}
127
128
bool BinarySpanReader::ReadSizePrefixedString(SmallStringBase* dst)
129
{
130
std::string_view sv;
131
if (!PeekSizePrefixedString(&sv))
132
return false;
133
134
dst->assign(sv);
135
m_pos += sizeof(u32) + sv.size();
136
return true;
137
}
138
139
std::string_view BinarySpanReader::ReadCString()
140
{
141
std::string_view ret;
142
if (PeekCString(&ret))
143
m_pos += ret.size() + 1;
144
return ret;
145
}
146
147
std::string_view BinarySpanReader::ReadSizePrefixedString()
148
{
149
std::string_view ret;
150
if (PeekSizePrefixedString(&ret))
151
m_pos += sizeof(u32) + ret.size();
152
return ret;
153
}
154
155
bool BinarySpanReader::PeekCString(std::string* dst)
156
{
157
std::string_view sv;
158
if (!PeekCString(&sv))
159
return false;
160
161
dst->assign(sv);
162
return true;
163
}
164
165
bool BinarySpanReader::PeekCString(SmallStringBase* dst)
166
{
167
std::string_view sv;
168
if (!PeekCString(&sv))
169
return false;
170
171
dst->assign(sv);
172
return true;
173
}
174
175
bool BinarySpanReader::PeekSizePrefixedString(std::string* dst)
176
{
177
std::string_view sv;
178
if (!PeekSizePrefixedString(&sv))
179
return false;
180
181
dst->assign(sv);
182
return true;
183
}
184
185
bool BinarySpanReader::PeekSizePrefixedString(SmallStringBase* dst)
186
{
187
std::string_view sv;
188
if (!PeekSizePrefixedString(&sv))
189
return false;
190
191
dst->assign(sv);
192
return true;
193
}
194
195
BinarySpanWriter::BinarySpanWriter() = default;
196
197
BinarySpanWriter::BinarySpanWriter(std::span<u8> buf) : m_buf(buf)
198
{
199
}
200
201
BinarySpanWriter::BinarySpanWriter(BinarySpanWriter&& move) : m_buf(std::move(move.m_buf)), m_pos(move.m_pos)
202
{
203
move.m_pos = 0;
204
}
205
206
BinarySpanWriter& BinarySpanWriter::operator=(BinarySpanWriter&& move)
207
{
208
m_buf = std::move(move.m_buf);
209
m_pos = move.m_pos;
210
move.m_pos = 0;
211
return *this;
212
}
213
214
std::span<u8> BinarySpanWriter::GetRemainingSpan(size_t size) const
215
{
216
DebugAssert(size <= GetBufferRemaining());
217
return m_buf.subspan(m_pos, size);
218
}
219
220
std::span<u8> BinarySpanWriter::GetRemainingSpan() const
221
{
222
return m_buf.subspan(m_pos, m_buf.size() - m_pos);
223
}
224
225
void BinarySpanWriter::IncrementPosition(size_t size)
226
{
227
DebugAssert(size < GetBufferRemaining());
228
m_pos += size;
229
}
230
231
bool BinarySpanWriter::WriteCString(std::string_view val)
232
{
233
if ((m_pos + val.size() + 1) > m_buf.size()) [[unlikely]]
234
return false;
235
236
if (!val.empty())
237
std::memcpy(&m_buf[m_pos], val.data(), val.size());
238
239
m_buf[m_pos + val.size()] = 0;
240
m_pos += val.size() + 1;
241
return true;
242
}
243
244
bool BinarySpanWriter::WriteSizePrefixedString(std::string_view val)
245
{
246
if (val.size() > std::numeric_limits<u32>::max() || (m_pos + sizeof(u32) + val.size()) > m_buf.size()) [[unlikely]]
247
return false;
248
249
const u32 usize = static_cast<u32>(val.size());
250
std::memcpy(&m_buf[m_pos], &usize, sizeof(usize));
251
m_pos += sizeof(usize);
252
if (val.size() > 0)
253
{
254
std::memcpy(&m_buf[m_pos], val.data(), val.size());
255
m_pos += val.size();
256
}
257
258
return true;
259
}
260
261
BinaryFileReader::BinaryFileReader() : m_fp(nullptr), m_size(0), m_good(false)
262
{
263
}
264
265
BinaryFileReader::BinaryFileReader(std::FILE* fp)
266
: m_fp(fp), m_size(fp ? FileSystem::FSize64(fp) : 0), m_good(fp != nullptr)
267
{
268
}
269
270
BinaryFileReader::BinaryFileReader(BinaryFileReader&& move) : m_fp(move.m_fp), m_size(move.m_size), m_good(move.m_good)
271
{
272
move.m_fp = nullptr;
273
move.m_size = 0;
274
move.m_good = false;
275
}
276
277
BinaryFileReader& BinaryFileReader::operator=(BinaryFileReader&& move)
278
{
279
m_fp = move.m_fp;
280
m_size = move.m_size;
281
m_good = move.m_good;
282
283
move.m_fp = nullptr;
284
move.m_size = 0;
285
move.m_good = false;
286
287
return *this;
288
}
289
290
bool BinaryFileReader::IsAtEnd()
291
{
292
return (!m_fp || FileSystem::FTell64(m_fp) == m_size);
293
}
294
295
bool BinaryFileReader::ReadCString(std::string* dst)
296
{
297
dst->clear();
298
299
while (m_good)
300
{
301
u8 val;
302
if ((m_good = std::fread(&val, sizeof(val), 1, m_fp) == 1))
303
{
304
if (val == 0)
305
break;
306
else
307
dst->push_back(static_cast<char>(val));
308
}
309
}
310
311
return m_good;
312
}
313
314
bool BinaryFileReader::ReadCString(SmallStringBase* dst)
315
{
316
dst->clear();
317
318
while (m_good)
319
{
320
u8 val;
321
if ((m_good = std::fread(&val, sizeof(val), 1, m_fp) == 1))
322
{
323
if (val == 0)
324
break;
325
else
326
dst->push_back(static_cast<char>(val));
327
}
328
}
329
330
return m_good;
331
}
332
333
bool BinaryFileReader::ReadSizePrefixedString(std::string* dst)
334
{
335
u32 length;
336
if (!ReadU32(&length)) [[unlikely]]
337
return false;
338
339
dst->resize(length);
340
return (length == 0 || Read(dst->data(), dst->length()));
341
}
342
343
bool BinaryFileReader::ReadSizePrefixedString(SmallStringBase* dst)
344
{
345
u32 length;
346
if (!ReadU32(&length)) [[unlikely]]
347
return false;
348
349
dst->resize(length);
350
return (length == 0 || Read(dst->data(), dst->length()));
351
}
352
353
std::string BinaryFileReader::ReadCString()
354
{
355
std::string ret;
356
if (!ReadCString(&ret))
357
ret = {};
358
return ret;
359
}
360
361
std::string BinaryFileReader::ReadSizePrefixedString()
362
{
363
std::string ret;
364
if (!ReadSizePrefixedString(&ret))
365
ret = {};
366
return ret;
367
}
368
369
BinaryFileWriter::BinaryFileWriter() : m_fp(nullptr), m_good(false)
370
{
371
}
372
373
BinaryFileWriter::BinaryFileWriter(std::FILE* fp) : m_fp(fp), m_good(fp != nullptr)
374
{
375
}
376
377
BinaryFileWriter::BinaryFileWriter(BinaryFileWriter&& move) : m_fp(move.m_fp), m_good(move.m_good)
378
{
379
move.m_fp = nullptr;
380
move.m_good = false;
381
}
382
383
BinaryFileWriter& BinaryFileWriter::operator=(BinaryFileWriter&& move)
384
{
385
m_fp = move.m_fp;
386
m_good = move.m_good;
387
388
move.m_fp = nullptr;
389
move.m_good = false;
390
391
return *this;
392
}
393
394
bool BinaryFileWriter::WriteCString(std::string_view val)
395
{
396
if (!val.empty() && (!m_good && std::fwrite(val.data(), val.length(), 1, m_fp) != 1)) [[unlikely]]
397
return false;
398
399
const u8 terminator = 0;
400
return (m_good = (m_good && std::fwrite(&terminator, 1, 1, m_fp) == 1));
401
}
402
403
bool BinaryFileWriter::WriteSizePrefixedString(std::string_view val)
404
{
405
if (val.size() > std::numeric_limits<u32>::max()) [[unlikely]]
406
return false;
407
408
const u32 usize = static_cast<u32>(val.size());
409
return (m_good = (m_good && std::fwrite(&usize, sizeof(usize), 1, m_fp) == 1 &&
410
(val.empty() || std::fwrite(val.data(), val.size(), 1, m_fp) == 1)));
411
}
412
413
bool BinaryFileWriter::Flush(Error* error)
414
{
415
if (!m_good)
416
{
417
Error::SetStringView(error, "Write error previously occurred.");
418
return false;
419
}
420
421
if (!(m_good = (m_good && std::fflush(m_fp) == 0)))
422
{
423
Error::SetErrno(error, "fflush() failed: ", errno);
424
return false;
425
}
426
427
return true;
428
}
429
430