binary_reader_writer.cpp (8979B)
1 // SPDX-FileCopyrightText: 2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR 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 (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 }