duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 }