state_wrapper.cpp (3225B)
1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "state_wrapper.h" 5 #include "common/log.h" 6 #include "common/small_string.h" 7 #include <cinttypes> 8 #include <cstring> 9 Log_SetChannel(StateWrapper); 10 11 StateWrapper::StateWrapper(std::span<u8> data, Mode mode, u32 version) 12 : m_data(data.data()), m_size(data.size()), m_mode(mode), m_version(version) 13 { 14 } 15 16 StateWrapper::StateWrapper(std::span<const u8> data, Mode mode, u32 version) 17 : m_data(const_cast<u8*>(data.data())), m_size(data.size()), m_mode(mode), m_version(version) 18 { 19 Assert(mode == Mode::Read); 20 } 21 22 StateWrapper::~StateWrapper() = default; 23 24 void StateWrapper::DoBytes(void* data, size_t length) 25 { 26 if (m_mode == Mode::Read) 27 { 28 if (!ReadData(data, length)) 29 std::memset(data, 0, length); 30 } 31 else 32 { 33 WriteData(data, length); 34 } 35 } 36 37 void StateWrapper::DoBytesEx(void* data, size_t length, u32 version_introduced, const void* default_value) 38 { 39 if (m_mode == Mode::Read && m_version < version_introduced) 40 { 41 std::memcpy(data, default_value, length); 42 return; 43 } 44 45 DoBytes(data, length); 46 } 47 48 void StateWrapper::Do(bool* value_ptr) 49 { 50 if (m_mode == Mode::Read) 51 { 52 u8 value = 0; 53 if (!(m_error = m_error || (m_pos + 1) > m_size)) [[likely]] 54 value = m_data[m_pos++]; 55 *value_ptr = (value != 0); 56 } 57 else 58 { 59 if (!(m_error = m_error || (m_pos + 1) > m_size)) [[likely]] 60 m_data[m_pos++] = static_cast<u8>(*value_ptr); 61 } 62 } 63 64 void StateWrapper::Do(std::string* value_ptr) 65 { 66 u32 length = static_cast<u32>(value_ptr->length()); 67 Do(&length); 68 if (m_mode == Mode::Read) 69 { 70 if ((m_error = (m_error || ((m_pos + length) > m_size)))) [[unlikely]] 71 return; 72 value_ptr->resize(length); 73 } 74 DoBytes(&(*value_ptr)[0], length); 75 value_ptr->resize(std::strlen(&(*value_ptr)[0])); 76 } 77 78 void StateWrapper::Do(SmallStringBase* value_ptr) 79 { 80 u32 length = static_cast<u32>(value_ptr->length()); 81 Do(&length); 82 if (m_mode == Mode::Read) 83 { 84 if ((m_error = (m_error || ((m_pos + length) > m_size)))) [[unlikely]] 85 return; 86 value_ptr->resize(length); 87 } 88 DoBytes(value_ptr->data(), length); 89 value_ptr->update_size(); 90 } 91 92 void StateWrapper::Do(std::string_view* value_ptr) 93 { 94 Assert(m_mode == Mode::Write); 95 u32 length = static_cast<u32>(value_ptr->length()); 96 Do(&length); 97 DoBytes(const_cast<char*>(value_ptr->data()), length); 98 } 99 100 bool StateWrapper::DoMarker(const char* marker) 101 { 102 SmallString file_value(marker); 103 Do(&file_value); 104 if (m_error) 105 return false; 106 107 if (m_mode == Mode::Write || file_value.equals(marker)) 108 return true; 109 110 ERROR_LOG("Marker mismatch at offset {}: found '{}' expected '{}'", m_pos, file_value, marker); 111 return false; 112 } 113 114 bool StateWrapper::ReadData(void* buf, size_t size) 115 { 116 if ((m_error = (m_error || (m_pos + size) > m_size))) [[unlikely]] 117 return false; 118 119 std::memcpy(buf, &m_data[m_pos], size); 120 m_pos += size; 121 return true; 122 } 123 124 bool StateWrapper::WriteData(const void* buf, size_t size) 125 { 126 if ((m_error = (m_error || (m_pos + size) > m_size))) [[unlikely]] 127 return false; 128 129 std::memcpy(&m_data[m_pos], buf, size); 130 m_pos += size; 131 return true; 132 }