Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
7.3 kB · 247 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248#include "refid.hpp"
#include "serializerefid.hpp"
#include "components/misc/strings/lower.hpp"
#include <sstream>#include <stdexcept>#include <variant>
namespace ESM{ namespace { const std::string emptyString;
struct GetRefString { const std::string& operator()(EmptyRefId /*v*/) const { return emptyString; }
const std::string& operator()(StringRefId v) const { return v.getValue(); }
template <class T> const std::string& operator()(const T& v) const { std::ostringstream stream; stream << "RefId is not a string: " << v; throw std::runtime_error(stream.str()); } };
struct IsEqualToString { const std::string_view mRhs;
bool operator()(StringRefId v) const noexcept { return v == mRhs; }
template <class T> bool operator()(const T& /*v*/) const noexcept { return false; } };
struct IsLessThanString { const std::string_view mRhs;
bool operator()(StringRefId v) const noexcept { return v < mRhs; }
template <class T> bool operator()(const T& /*v*/) const noexcept { return false; } };
struct IsGreaterThanString { const std::string_view mLhs;
bool operator()(StringRefId v) const noexcept { return mLhs < v; }
template <class T> bool operator()(const T& /*v*/) const noexcept { return true; } };
struct StartsWith { const std::string_view mPrefix;
bool operator()(StringRefId v) const { return v.startsWith(mPrefix); }
template <class T> bool operator()(const T& /*v*/) const { return false; } };
struct EndsWith { const std::string_view mSuffix;
bool operator()(StringRefId v) const { return v.endsWith(mSuffix); }
template <class T> bool operator()(const T& /*v*/) const { return false; } };
struct Contains { const std::string_view mSubString;
bool operator()(StringRefId v) const { return v.contains(mSubString); }
template <class T> bool operator()(const T& /*v*/) const { return false; } };
struct SerializeText { std::string operator()(ESM::EmptyRefId /*v*/) const { return std::string(); }
std::string operator()(ESM::StringRefId v) const { return Misc::StringUtils::lowerCase(v.getValue()); }
std::string operator()(ESM::FormId v) const { return v.toString(formIdRefIdPrefix); }
template <class T> std::string operator()(const T& v) const { return v.toDebugString(); } }; }
bool RefId::operator==(std::string_view rhs) const { return std::visit(IsEqualToString{ rhs }, mValue); }
bool operator<(RefId lhs, std::string_view rhs) { return std::visit(IsLessThanString{ rhs }, lhs.mValue); }
bool operator<(std::string_view lhs, RefId rhs) { return std::visit(IsGreaterThanString{ lhs }, rhs.mValue); }
RefId RefId::stringRefId(std::string_view value) { if (value.empty()) return RefId(); return RefId(StringRefId(value)); }
const std::string& RefId::getRefIdString() const { return std::visit(GetRefString{}, mValue); }
std::string RefId::toString() const { return std::visit([](auto v) { return v.toString(); }, mValue); }
std::string RefId::toDebugString() const { return std::visit( [](auto v) { if constexpr (std::is_same_v<decltype(v), FormId>) return v.toString(formIdRefIdPrefix); else return v.toDebugString(); }, mValue); }
bool RefId::startsWith(std::string_view prefix) const { return std::visit(StartsWith{ prefix }, mValue); }
bool RefId::endsWith(std::string_view suffix) const { return std::visit(EndsWith{ suffix }, mValue); }
bool RefId::contains(std::string_view subString) const { return std::visit(Contains{ subString }, mValue); }
std::string RefId::serialize() const { std::string result(sizeof(mValue), '\0'); std::memcpy(result.data(), &mValue, sizeof(mValue)); return result; }
ESM::RefId RefId::deserialize(std::string_view value) { if (value.size() != sizeof(ESM::RefId::mValue)) throw std::runtime_error("Invalid value size to deserialize: " + std::to_string(value.size())); ESM::RefId result; std::memcpy(&result.mValue, value.data(), sizeof(result.mValue)); return result; }
std::string RefId::serializeText() const { return std::visit(SerializeText{}, mValue); }
ESM::RefId RefId::deserializeText(std::string_view value) { if (value.empty()) return ESM::RefId();
if (value.starts_with(formIdRefIdPrefix)) { uint64_t v = deserializeHexIntegral<uint64_t>(formIdRefIdPrefix.size(), value); uint32_t index = static_cast<uint32_t>(v) & 0xffffff; int contentFile = static_cast<int>(v >> 24); return ESM::FormId{ index, contentFile }; }
if (value.starts_with(generatedRefIdPrefix)) return ESM::RefId::generated(deserializeHexIntegral<std::uint64_t>(generatedRefIdPrefix.size(), value));
if (value.starts_with(indexRefIdPrefix)) { ESM::RecNameInts recordType{}; std::memcpy(&recordType, value.data() + indexRefIdPrefix.size(), sizeof(recordType)); return ESM::RefId::index(recordType, deserializeHexIntegral<std::uint32_t>(indexRefIdPrefix.size() + sizeof(recordType) + 1, value)); }
if (value.starts_with(esm3ExteriorCellRefIdPrefix)) { if (value.size() < esm3ExteriorCellRefIdPrefix.size() + 3) throw std::runtime_error("Invalid ESM3ExteriorCellRefId format: not enough size"); const std::size_t separator = value.find(':', esm3ExteriorCellRefIdPrefix.size() + 1); if (separator == std::string_view::npos) throw std::runtime_error("Invalid ESM3ExteriorCellRefId format: coordinates separator is not found"); const std::int32_t x = deserializeDecIntegral<std::int32_t>(esm3ExteriorCellRefIdPrefix.size(), separator, value); const std::int32_t y = deserializeDecIntegral<std::int32_t>(separator + 1, value.size(), value); return ESM::ESM3ExteriorCellRefId(x, y); }
if (auto id = ESM::StringRefId::deserializeExisting(value)) return *id; return {}; }}