1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-19 21:40:45 +00:00

Merge branch 'esm_name' into 'master'

Use ESM::NAME instead of const char* and std::string as argument type

See merge request OpenMW/openmw!1659
This commit is contained in:
psi29a 2022-02-15 08:11:12 +00:00
commit 776b286286
13 changed files with 137 additions and 100 deletions

View File

@ -484,9 +484,9 @@ int clone(Arguments& info)
if (i <= 0)
break;
const ESM::NAME& typeName = record->getType();
const ESM::NAME typeName = record->getType();
esm.startRecord(typeName.toString(), record->getFlags());
esm.startRecord(typeName, record->getFlags());
record->save(esm);
if (typeName.toInt() == ESM::REC_CELL) {
@ -498,7 +498,7 @@ int clone(Arguments& info)
}
}
esm.endRecord(typeName.toString());
esm.endRecord(typeName);
saved++;
int perc = recordCount == 0 ? 100 : (int)((saved / (float)recordCount)*100);

View File

@ -1,12 +1,12 @@
#include <gtest/gtest.h>
#include "components/esm/esmcommon.hpp"
#include "components/esm/defs.hpp"
TEST(EsmFixedString, operator__eq_ne)
{
{
SCOPED_TRACE("asdc == asdc");
ESM::NAME name;
name.assign("asdc");
constexpr ESM::NAME name("asdc");
char s[4] = {'a', 's', 'd', 'c'};
std::string ss(s, 4);
@ -16,8 +16,7 @@ TEST(EsmFixedString, operator__eq_ne)
}
{
SCOPED_TRACE("asdc == asdcx");
ESM::NAME name;
name.assign("asdc");
constexpr ESM::NAME name("asdc");
char s[5] = {'a', 's', 'd', 'c', 'x'};
std::string ss(s, 5);
@ -27,8 +26,7 @@ TEST(EsmFixedString, operator__eq_ne)
}
{
SCOPED_TRACE("asdc == asdc[NULL]");
ESM::NAME name;
name.assign("asdc");
const ESM::NAME name("asdc");
char s[5] = {'a', 's', 'd', 'c', '\0'};
std::string ss(s, 5);
@ -41,8 +39,7 @@ TEST(EsmFixedString, operator__eq_ne_const)
{
{
SCOPED_TRACE("asdc == asdc (const)");
ESM::NAME name;
name.assign("asdc");
constexpr ESM::NAME name("asdc");
const char s[4] = { 'a', 's', 'd', 'c' };
std::string ss(s, 4);
@ -52,8 +49,7 @@ TEST(EsmFixedString, operator__eq_ne_const)
}
{
SCOPED_TRACE("asdc == asdcx (const)");
ESM::NAME name;
name.assign("asdc");
constexpr ESM::NAME name("asdc");
const char s[5] = { 'a', 's', 'd', 'c', 'x' };
std::string ss(s, 5);
@ -63,8 +59,7 @@ TEST(EsmFixedString, operator__eq_ne_const)
}
{
SCOPED_TRACE("asdc == asdc[NULL] (const)");
ESM::NAME name;
name.assign("asdc");
constexpr ESM::NAME name("asdc");
const char s[5] = { 'a', 's', 'd', 'c', '\0' };
std::string ss(s, 5);
@ -148,3 +143,15 @@ TEST(EsmFixedString, assignment_operator_is_supported_for_uint32)
value = static_cast<uint32_t>(0xFEDCBA98u);
EXPECT_EQ(value, static_cast<uint32_t>(0xFEDCBA98u)) << value.toInt();
}
TEST(EsmFixedString, construction_from_uint32_is_supported)
{
constexpr ESM::NAME value(0xFEDCBA98u);
EXPECT_EQ(value, static_cast<std::uint32_t>(0xFEDCBA98u)) << value.toInt();
}
TEST(EsmFixedString, construction_from_RecNameInts_is_supported)
{
constexpr ESM::NAME value(ESM::RecNameInts::REC_ACTI);
EXPECT_EQ(value, static_cast<std::uint32_t>(ESM::RecNameInts::REC_ACTI)) << value.toInt();
}

View File

@ -6,6 +6,8 @@
#include <vector>
#include <string_view>
#include <cstdint>
#include <cassert>
#include <limits>
namespace ESM
{
@ -30,6 +32,41 @@ struct FixedString
char mData[capacity];
FixedString() = default;
template <std::size_t size>
constexpr FixedString(const char (&value)[size]) noexcept
: mData()
{
if constexpr (capacity == sizeof(std::uint32_t))
{
static_assert(capacity == size || capacity + 1 == size);
if constexpr (capacity + 1 == size)
assert(value[capacity] == '\0');
for (std::size_t i = 0; i < capacity; ++i)
mData[i] = value[i];
}
else
{
const std::size_t length = std::min(capacity, size);
for (std::size_t i = 0; i < length; ++i)
mData[i] = value[i];
mData[std::min(capacity - 1, length)] = '\0';
}
}
constexpr explicit FixedString(std::uint32_t value) noexcept
: mData()
{
static_assert(capacity == sizeof(std::uint32_t));
for (std::size_t i = 0; i < capacity; ++i)
mData[i] = static_cast<char>((value >> (i * std::numeric_limits<std::uint8_t>::digits)) & std::numeric_limits<std::uint8_t>::max());
}
template <class T>
constexpr explicit FixedString(T value) noexcept
: FixedString(static_cast<std::uint32_t>(value)) {}
std::string_view toStringView() const noexcept
{
return std::string_view(mData, strnlen(mData, capacity));
@ -116,6 +153,11 @@ inline bool operator==(const FixedString<4>& lhs, std::uint32_t rhs) noexcept
return lhs.toInt() == rhs;
}
inline bool operator==(const FixedString<4>& lhs, const FixedString<4>& rhs) noexcept
{
return lhs.toInt() == rhs.toInt();
}
template <std::size_t capacity, class Rhs>
inline bool operator!=(const FixedString<capacity>& lhs, const Rhs& rhs) noexcept
{

View File

@ -5,7 +5,7 @@
namespace
{
void save(ESM::ESMWriter& esm, const std::vector<ESM::ActiveSpells::ActiveSpellParams>& spells, const std::string& tag)
void save(ESM::ESMWriter& esm, const std::vector<ESM::ActiveSpells::ActiveSpellParams>& spells, ESM::NAME tag)
{
for (const auto& params : spells)
{
@ -38,7 +38,7 @@ namespace
}
}
void load(ESM::ESMReader& esm, std::vector<ESM::ActiveSpells::ActiveSpellParams>& spells, const char* tag)
void load(ESM::ESMReader& esm, std::vector<ESM::ActiveSpells::ActiveSpellParams>& spells, ESM::NAME tag)
{
int format = esm.getFormat();

View File

@ -65,7 +65,7 @@ namespace ESM
case AI_Escort:
case AI_Follow: {
const char *name = (it->mType == AI_Escort) ? "AI_E" : "AI_F";
const ESM::NAME name = (it->mType == AI_Escort) ? ESM::NAME("AI_E") : ESM::NAME("AI_F");
esm.writeHNT(name, it->mTarget, sizeof(it->mTarget));
esm.writeHNOCString("CNDT", it->mCellName);
break;

View File

@ -5,15 +5,15 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
void ESM::RefNum::load (ESMReader& esm, bool wide, const std::string& tag)
void ESM::RefNum::load(ESMReader& esm, bool wide, ESM::NAME tag)
{
if (wide)
esm.getHNT (*this, tag.c_str(), 8);
esm.getHNT(*this, tag, 8);
else
esm.getHNT (mIndex, tag.c_str());
esm.getHNT(mIndex, tag);
}
void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
void ESM::RefNum::save(ESMWriter &esm, bool wide, ESM::NAME tag) const
{
if (wide)
esm.writeHNT (tag, *this, 8);

View File

@ -5,6 +5,7 @@
#include <string>
#include "components/esm/defs.hpp"
#include "components/esm/esmcommon.hpp"
namespace ESM
{
@ -18,9 +19,9 @@ namespace ESM
unsigned int mIndex;
int mContentFile;
void load (ESMReader& esm, bool wide = false, const std::string& tag = "FRMR");
void load(ESMReader& esm, bool wide = false, ESM::NAME tag = "FRMR");
void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const;
void save(ESMWriter &esm, bool wide = false, ESM::NAME tag = "FRMR") const;
inline bool hasContentFile() const { return mContentFile >= 0; }

View File

@ -113,14 +113,14 @@ void ESMReader::open(const std::string &file)
open (Files::openConstrainedFileStream (file.c_str ()), file);
}
std::string ESMReader::getHNOString(const char* name)
std::string ESMReader::getHNOString(NAME name)
{
if (isNextSub(name))
return getHString();
return "";
}
std::string ESMReader::getHNString(const char* name)
std::string ESMReader::getHNString(NAME name)
{
getSubNameIs(name);
return getHString();
@ -156,21 +156,21 @@ void ESMReader::getHExact(void*p, int size)
}
// Read the given number of bytes from a named subrecord
void ESMReader::getHNExact(void*p, int size, const char* name)
void ESMReader::getHNExact(void*p, int size, NAME name)
{
getSubNameIs(name);
getHExact(p, size);
}
// Get the next subrecord name and check if it matches the parameter
void ESMReader::getSubNameIs(const char* name)
void ESMReader::getSubNameIs(NAME name)
{
getSubName();
if (mCtx.subName != name)
fail("Expected subrecord " + std::string(name) + " but got " + mCtx.subName.toString());
fail("Expected subrecord " + name.toString() + " but got " + mCtx.subName.toString());
}
bool ESMReader::isNextSub(const char* name)
bool ESMReader::isNextSub(NAME name)
{
if (!hasMoreSubs())
return false;
@ -185,7 +185,7 @@ bool ESMReader::isNextSub(const char* name)
return !mCtx.subCached;
}
bool ESMReader::peekNextSub(const char *name)
bool ESMReader::peekNextSub(NAME name)
{
if (!hasMoreSubs())
return false;
@ -226,7 +226,7 @@ void ESMReader::skipHSubSize(int size)
reportSubSizeMismatch(mCtx.leftSub, size);
}
void ESMReader::skipHSubUntil(const char *name)
void ESMReader::skipHSubUntil(NAME name)
{
while (hasMoreSubs() && !isNextSub(name))
{

View File

@ -98,7 +98,7 @@ public:
// Read data of a given type, stored in a subrecord of a given name
template <typename X>
void getHNT(X &x, const char* name)
void getHNT(X &x, NAME name)
{
getSubNameIs(name);
getHT(x);
@ -106,7 +106,7 @@ public:
// Optional version of getHNT
template <typename X>
void getHNOT(X &x, const char* name)
void getHNOT(X &x, NAME name)
{
if(isNextSub(name))
getHT(x);
@ -115,7 +115,7 @@ public:
// Version with extra size checking, to make sure the compiler
// doesn't mess up our struct padding.
template <typename X>
void getHNT(X &x, const char* name, int size)
void getHNT(X &x, NAME name, int size)
{
assert(sizeof(X) == size);
getSubNameIs(name);
@ -123,7 +123,7 @@ public:
}
template <typename X>
void getHNOT(X &x, const char* name, int size)
void getHNOT(X &x, NAME name, int size)
{
assert(sizeof(X) == size);
if(isNextSub(name))
@ -150,10 +150,10 @@ public:
}
// Read a string by the given name if it is the next record.
std::string getHNOString(const char* name);
std::string getHNOString(NAME name);
// Read a string with the given sub-record name
std::string getHNString(const char* name);
std::string getHNString(NAME name);
// Read a string, including the sub-record header (but not the name)
std::string getHString();
@ -162,7 +162,7 @@ public:
void getHExact(void*p, int size);
// Read the given number of bytes from a named subrecord
void getHNExact(void*p, int size, const char* name);
void getHNExact(void*p, int size, NAME name);
/*************************************************************************
*
@ -171,16 +171,16 @@ public:
*************************************************************************/
// Get the next subrecord name and check if it matches the parameter
void getSubNameIs(const char* name);
void getSubNameIs(NAME name);
/** Checks if the next sub record name matches the parameter. If it
does, it is read into 'subName' just as if getSubName() was
called. If not, the read name will still be available for future
calls to getSubName(), isNextSub() and getSubNameIs().
*/
bool isNextSub(const char* name);
bool isNextSub(NAME name);
bool peekNextSub(const char* name);
bool peekNextSub(NAME name);
// Store the current subrecord name for the next call of getSubName()
void cacheSubName() {mCtx.subCached = true; };
@ -197,7 +197,7 @@ public:
void skipHSubSize(int size);
// Skip all subrecords until the given subrecord or no more subrecords remaining
void skipHSubUntil(const char* name);
void skipHSubUntil(NAME name);
/* Sub-record header. This updates leftRec beyond the current
sub-record as well. leftSub contains size of current sub-record.

View File

@ -86,7 +86,7 @@ namespace ESM
throw std::runtime_error ("Unclosed record remaining");
}
void ESMWriter::startRecord(const std::string& name, uint32_t flags)
void ESMWriter::startRecord(ESM::NAME name, uint32_t flags)
{
mRecordCount++;
@ -105,15 +105,10 @@ namespace ESM
void ESMWriter::startRecord (uint32_t name, uint32_t flags)
{
std::string type;
for (int i=0; i<4; ++i)
/// \todo make endianess agnostic
type += reinterpret_cast<const char *> (&name)[i];
startRecord (type, flags);
startRecord(ESM::NAME(name), flags);
}
void ESMWriter::startSubRecord(const std::string& name)
void ESMWriter::startSubRecord(ESM::NAME name)
{
// Sub-record hierarchies are not properly supported in ESMReader. This should be fixed later.
assert (mRecords.size() <= 1);
@ -129,7 +124,7 @@ namespace ESM
assert(mRecords.back().size == 0);
}
void ESMWriter::endRecord(const std::string& name)
void ESMWriter::endRecord(ESM::NAME name)
{
RecordData rec = mRecords.back();
assert(rec.name == name);
@ -147,22 +142,17 @@ namespace ESM
void ESMWriter::endRecord (uint32_t name)
{
std::string type;
for (int i=0; i<4; ++i)
/// \todo make endianess agnostic
type += reinterpret_cast<const char *> (&name)[i];
endRecord (type);
endRecord(ESM::NAME(name));
}
void ESMWriter::writeHNString(const std::string& name, const std::string& data)
void ESMWriter::writeHNString(ESM::NAME name, const std::string& data)
{
startSubRecord(name);
writeHString(data);
endRecord(name);
}
void ESMWriter::writeHNString(const std::string& name, const std::string& data, size_t size)
void ESMWriter::writeHNString(ESM::NAME name, const std::string& data, size_t size)
{
assert(data.size() <= size);
startSubRecord(name);
@ -177,7 +167,7 @@ namespace ESM
endRecord(name);
}
void ESMWriter::writeFixedSizeString(const std::string &data, int size)
void ESMWriter::writeFixedSizeString(const std::string& data, int size)
{
std::string string;
if (!data.empty())
@ -206,10 +196,9 @@ namespace ESM
write("\0", 1);
}
void ESMWriter::writeName(const std::string& name)
void ESMWriter::writeName(ESM::NAME name)
{
assert((name.size() == 4 && name[3] != '\0'));
write(name.c_str(), name.size());
write(name.mData, ESM::NAME::sCapacity);
}
void ESMWriter::write(const char* data, size_t size)

View File

@ -19,7 +19,7 @@ class ESMWriter
{
struct RecordData
{
std::string name;
ESM::NAME name;
std::streampos position;
uint32_t size;
};
@ -56,27 +56,27 @@ class ESMWriter
void close();
///< \note Does not close the stream.
void writeHNString(const std::string& name, const std::string& data);
void writeHNString(const std::string& name, const std::string& data, size_t size);
void writeHNCString(const std::string& name, const std::string& data)
void writeHNString(ESM::NAME name, const std::string& data);
void writeHNString(ESM::NAME name, const std::string& data, size_t size);
void writeHNCString(ESM::NAME name, const std::string& data)
{
startSubRecord(name);
writeHCString(data);
endRecord(name);
}
void writeHNOString(const std::string& name, const std::string& data)
void writeHNOString(ESM::NAME name, const std::string& data)
{
if (!data.empty())
writeHNString(name, data);
}
void writeHNOCString(const std::string& name, const std::string& data)
void writeHNOCString(ESM::NAME name, const std::string& data)
{
if (!data.empty())
writeHNCString(name, data);
}
template<typename T>
void writeHNT(const std::string& name, const T& data)
void writeHNT(ESM::NAME name, const T& data)
{
startSubRecord(name);
writeT(data);
@ -84,7 +84,7 @@ class ESMWriter
}
template<typename T, std::size_t size>
void writeHNT(const std::string& name, const T (&data)[size])
void writeHNT(ESM::NAME name, const T (&data)[size])
{
startSubRecord(name);
writeT(data);
@ -94,15 +94,15 @@ class ESMWriter
// Prevent using writeHNT with strings. This already happened by accident and results in
// state being discarded without any error on writing or reading it. :(
// writeHNString and friends must be used instead.
void writeHNT(const std::string& name, const std::string& data) = delete;
void writeHNT(ESM::NAME name, const std::string& data) = delete;
void writeT(const std::string& data) = delete;
void writeT(ESM::NAME data) = delete;
template<typename T, std::size_t size>
void writeHNT(const std::string& name, const T (&data)[size], int) = delete;
void writeHNT(ESM::NAME name, const T (&data)[size], int) = delete;
template<typename T>
void writeHNT(const std::string& name, const T& data, int size)
void writeHNT(ESM::NAME name, const T& data, int size)
{
startSubRecord(name);
writeT(data, size);
@ -129,16 +129,16 @@ class ESMWriter
write((char*)&data, size);
}
void startRecord(const std::string& name, uint32_t flags = 0);
void startRecord(ESM::NAME name, uint32_t flags = 0);
void startRecord(uint32_t name, uint32_t flags = 0);
/// @note Sub-record hierarchies are not properly supported in ESMReader. This should be fixed later.
void startSubRecord(const std::string& name);
void endRecord(const std::string& name);
void startSubRecord(ESM::NAME name);
void endRecord(ESM::NAME name);
void endRecord(uint32_t name);
void writeFixedSizeString(const std::string& data, int size);
void writeHString(const std::string& data);
void writeHCString(const std::string& data);
void writeName(const std::string& data);
void writeName(ESM::NAME data);
void write(const char* data, size_t size);
private:

View File

@ -4,6 +4,8 @@
#include <string>
#include <vector>
#include <components/esm/esmcommon.hpp>
namespace ESM
{
@ -27,7 +29,7 @@ struct LevelledListBase
// Record name used to read references. Must be set before load() is
// called.
const char *mRecName;
ESM::NAME mRecName;
struct LevelItem
{
@ -37,6 +39,8 @@ struct LevelledListBase
std::vector<LevelItem> mList;
explicit LevelledListBase(ESM::NAME recName) : mRecName(recName) {}
void load(ESMReader &esm, bool &isDeleted);
void save(ESMWriter &esm, bool isDeleted = false) const;
@ -58,10 +62,7 @@ struct CreatureLevList: LevelledListBase
// player.
};
CreatureLevList()
{
mRecName = "CNAM";
}
CreatureLevList() : LevelledListBase("CNAM") {}
};
struct ItemLevList: LevelledListBase
@ -84,10 +85,7 @@ struct ItemLevList: LevelledListBase
// player.
};
ItemLevList()
{
mRecName = "INAM";
}
ItemLevList() : LevelledListBase("INAM") {}
};
}

View File

@ -5,17 +5,17 @@
namespace
{
const char* currentRegionRecord = "CREG";
const char* timePassedRecord = "TMPS";
const char* fastForwardRecord = "FAST";
const char* weatherUpdateTimeRecord = "WUPD";
const char* transitionFactorRecord = "TRFC";
const char* currentWeatherRecord = "CWTH";
const char* nextWeatherRecord = "NWTH";
const char* queuedWeatherRecord = "QWTH";
const char* regionNameRecord = "RGNN";
const char* regionWeatherRecord = "RGNW";
const char* regionChanceRecord = "RGNC";
constexpr ESM::NAME currentRegionRecord = "CREG";
constexpr ESM::NAME timePassedRecord = "TMPS";
constexpr ESM::NAME fastForwardRecord = "FAST";
constexpr ESM::NAME weatherUpdateTimeRecord = "WUPD";
constexpr ESM::NAME transitionFactorRecord = "TRFC";
constexpr ESM::NAME currentWeatherRecord = "CWTH";
constexpr ESM::NAME nextWeatherRecord = "NWTH";
constexpr ESM::NAME queuedWeatherRecord = "QWTH";
constexpr ESM::NAME regionNameRecord = "RGNN";
constexpr ESM::NAME regionWeatherRecord = "RGNW";
constexpr ESM::NAME regionChanceRecord = "RGNC";
}
namespace ESM