mirror of https://github.com/stenzek/duckstation
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
3.7 KiB
C++
155 lines
3.7 KiB
C++
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
|
|
|
#include "state_wrapper.h"
|
|
#include "common/log.h"
|
|
#include "common/small_string.h"
|
|
#include <cinttypes>
|
|
#include <cstring>
|
|
LOG_CHANNEL(StateWrapper);
|
|
|
|
static constexpr size_t MAX_MARKER_LEN = 128;
|
|
|
|
StateWrapper::StateWrapper(std::span<u8> data, Mode mode, u32 version)
|
|
: m_data(data.data()), m_size(data.size()), m_mode(mode), m_version(version)
|
|
{
|
|
}
|
|
|
|
StateWrapper::StateWrapper(std::span<const u8> data, Mode mode, u32 version)
|
|
: m_data(const_cast<u8*>(data.data())), m_size(data.size()), m_mode(mode), m_version(version)
|
|
{
|
|
Assert(mode == Mode::Read);
|
|
}
|
|
|
|
StateWrapper::~StateWrapper() = default;
|
|
|
|
void StateWrapper::DoBytes(void* data, size_t length)
|
|
{
|
|
if (m_mode == Mode::Read)
|
|
{
|
|
if (!ReadData(data, length))
|
|
std::memset(data, 0, length);
|
|
}
|
|
else
|
|
{
|
|
WriteData(data, length);
|
|
}
|
|
}
|
|
|
|
void StateWrapper::DoBytesEx(void* data, size_t length, u32 version_introduced, const void* default_value)
|
|
{
|
|
if (m_mode == Mode::Read && m_version < version_introduced)
|
|
{
|
|
std::memcpy(data, default_value, length);
|
|
return;
|
|
}
|
|
|
|
DoBytes(data, length);
|
|
}
|
|
|
|
void StateWrapper::Do(bool* value_ptr)
|
|
{
|
|
if (m_mode == Mode::Read)
|
|
{
|
|
u8 value = 0;
|
|
if (!(m_error = m_error || m_pos >= m_size)) [[likely]]
|
|
value = m_data[m_pos++];
|
|
*value_ptr = (value != 0);
|
|
}
|
|
else
|
|
{
|
|
if (!(m_error = m_error || m_pos >= m_size)) [[likely]]
|
|
m_data[m_pos++] = static_cast<u8>(*value_ptr);
|
|
}
|
|
}
|
|
|
|
void StateWrapper::Do(std::string* value_ptr, size_t max_length)
|
|
{
|
|
u32 length = static_cast<u32>(value_ptr->length());
|
|
Do(&length);
|
|
if (m_mode == Mode::Read)
|
|
{
|
|
if ((m_error = (m_error || length > max_length || ((m_size - m_pos) < length)))) [[unlikely]]
|
|
return;
|
|
value_ptr->resize(length);
|
|
}
|
|
DoBytes(&(*value_ptr)[0], length);
|
|
value_ptr->resize(std::strlen(&(*value_ptr)[0]));
|
|
}
|
|
|
|
void StateWrapper::Do(SmallStringBase* value_ptr, size_t max_length)
|
|
{
|
|
u32 length = static_cast<u32>(value_ptr->length());
|
|
Do(&length);
|
|
if (m_mode == Mode::Read)
|
|
{
|
|
if ((m_error = (m_error || length > max_length || ((m_size - m_pos) < length)))) [[unlikely]]
|
|
return;
|
|
value_ptr->resize(length);
|
|
}
|
|
DoBytes(value_ptr->data(), length);
|
|
value_ptr->update_size();
|
|
}
|
|
|
|
void StateWrapper::Do(std::string_view* value_ptr)
|
|
{
|
|
if (m_mode != Mode::Write)
|
|
Panic("Trying to write to std::string_view");
|
|
|
|
u32 length = static_cast<u32>(value_ptr->length());
|
|
Do(&length);
|
|
DoBytes(const_cast<char*>(value_ptr->data()), length);
|
|
}
|
|
|
|
bool StateWrapper::DoMarker(const char* marker)
|
|
{
|
|
SmallString file_value(marker);
|
|
Do(&file_value, MAX_MARKER_LEN);
|
|
if (m_error)
|
|
return false;
|
|
|
|
if (m_mode == Mode::Write || file_value.equals(marker))
|
|
return true;
|
|
|
|
ERROR_LOG("Marker mismatch at offset {}: found '{}' expected '{}'", m_pos, file_value, marker);
|
|
return false;
|
|
}
|
|
|
|
bool StateWrapper::DoMarkerEx(const char* marker, u32 version_introduced)
|
|
{
|
|
if (m_version < version_introduced)
|
|
return !HasError();
|
|
|
|
return DoMarker(marker);
|
|
}
|
|
|
|
std::span<u8> StateWrapper::GetDeferredBytes(size_t size)
|
|
{
|
|
if ((m_error = (m_error || ((m_size - m_pos) < size)))) [[unlikely]]
|
|
return {};
|
|
|
|
const std::span<u8> ret(&m_data[m_pos], size);
|
|
m_pos += size;
|
|
return ret;
|
|
}
|
|
|
|
bool StateWrapper::ReadData(void* buf, size_t size)
|
|
{
|
|
if ((m_error = (m_error || ((m_size - m_pos) < size)))) [[unlikely]]
|
|
return false;
|
|
|
|
std::memcpy(buf, &m_data[m_pos], size);
|
|
m_pos += size;
|
|
return true;
|
|
}
|
|
|
|
bool StateWrapper::WriteData(const void* buf, size_t size)
|
|
{
|
|
if ((m_error = (m_error || ((m_size - m_pos) < size)))) [[unlikely]]
|
|
return false;
|
|
|
|
std::memcpy(&m_data[m_pos], buf, size);
|
|
m_pos += size;
|
|
return true;
|
|
}
|