1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 14:59:54 +00:00

Disallow implicitly sized reads of ESM structs

This commit is contained in:
Evil Eye 2023-06-02 16:54:27 +02:00
parent ec9b4c4563
commit 45ba05c0ed
26 changed files with 79 additions and 67 deletions

View file

@ -97,7 +97,7 @@ namespace ESSImport
void ConvertFMAP::read(ESM::ESMReader& esm)
{
MAPH maph;
esm.getHNT(maph, "MAPH");
esm.getHNTSized<8>(maph, "MAPH");
std::vector<char> data;
esm.getSubNameIs("MAPD");
esm.getSubHeader();

View file

@ -48,14 +48,14 @@ namespace ESSImport
if (esm.isNextSub("ACDT"))
{
mActorData.mHasACDT = true;
esm.getHT(mActorData.mACDT);
esm.getHTSized<264>(mActorData.mACDT);
}
mActorData.mHasACSC = false;
if (esm.isNextSub("ACSC"))
{
mActorData.mHasACSC = true;
esm.getHT(mActorData.mACSC);
esm.getHTSized<112>(mActorData.mACSC);
}
if (esm.isNextSub("ACSL"))
@ -137,7 +137,7 @@ namespace ESSImport
if (esm.isNextSub("ANIS"))
{
mActorData.mHasANIS = true;
esm.getHT(mActorData.mANIS);
esm.getHTSized<8>(mActorData.mANIS);
}
if (esm.isNextSub("LVCR"))

View file

@ -16,7 +16,7 @@ namespace ESSImport
}
else if (esm.getSubSize() == 96)
{
esm.getT(mGMDT);
esm.getTSized<96>(mGMDT);
}
else
esm.fail("unexpected subrecord size for GAME.GMDT");

View file

@ -12,7 +12,7 @@ namespace ESSImport
while (esm.isNextSub("NPCO"))
{
ContItem contItem;
esm.getHT(contItem);
esm.getHTSized<36>(contItem);
InventoryItem item;
item.mId = contItem.mItem.toString();

View file

@ -7,7 +7,7 @@ namespace ESSImport
void NPCC::load(ESM::ESMReader& esm)
{
esm.getHNT(mNPDT, "NPDT");
esm.getHNTSized<8>(mNPDT, "NPDT");
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|| esm.isNextSub("AI_A"))

View file

@ -19,7 +19,7 @@ namespace ESSImport
mMNAM = esm.getHString();
}
esm.getHNT(mPNAM, "PNAM");
esm.getHNTSized<212>(mPNAM, "PNAM");
if (esm.isNextSub("SNAM"))
esm.skipHSub();
@ -54,7 +54,7 @@ namespace ESSImport
if (esm.isNextSub("ENAM"))
{
mHasENAM = true;
esm.getHT(mENAM);
esm.getHTSized<8>(mENAM);
}
if (esm.isNextSub("LNAM"))
@ -63,7 +63,7 @@ namespace ESSImport
while (esm.isNextSub("FNAM"))
{
FNAM fnam;
esm.getHT(fnam);
esm.getHTSized<44>(fnam);
mFactions.push_back(fnam);
}
@ -71,7 +71,7 @@ namespace ESSImport
if (esm.isNextSub("AADT")) // Attack animation data?
{
mHasAADT = true;
esm.getHT(mAADT);
esm.getHTSized<44>(mAADT);
}
if (esm.isNextSub("KNAM"))

View file

@ -10,7 +10,7 @@ namespace ESSImport
while (esm.isNextSub("PNAM"))
{
PNAM pnam;
esm.getHT(pnam);
esm.getHTSized<184>(pnam);
mProjectiles.push_back(pnam);
}
}

View file

@ -7,7 +7,7 @@ namespace ESSImport
void SCPT::load(ESM::ESMReader& esm)
{
esm.getHNT(mSCHD, "SCHD");
esm.getHNTSized<52>(mSCHD, "SCHD");
mSCRI.load(esm);

View file

@ -11,13 +11,13 @@ namespace ESSImport
{
ActiveSpell spell;
esm.getHT(spell.mIndex);
esm.getHNT(spell.mSPDT, "SPDT");
esm.getHNTSized<160>(spell.mSPDT, "SPDT");
spell.mTarget = esm.getHNOString("TNAM");
while (esm.isNextSub("NPDT"))
{
ActiveEffect effect;
esm.getHT(effect.mNPDT);
esm.getHTSized<56>(effect.mNPDT);
// Effect-specific subrecords can follow:
// - INAM for disintegration and bound effects

View file

@ -61,7 +61,7 @@ namespace ESM
if (esm.isNextSub("WORS"))
{
esm.getHT(params.mWorsenings);
esm.getHNT(params.mNextWorsening, "TIME");
esm.getHNTSized<8>(params.mNextWorsening, "TIME");
}
else
params.mWorsenings = -1;

View file

@ -13,13 +13,13 @@ namespace ESM
void AiWander::load(ESMReader& esm)
{
esm.getHNT(mData, "DATA");
esm.getHNT(mDurationData, "STAR"); // was mStartTime
esm.getHNTSized<14>(mData, "DATA");
esm.getHNTSized<8>(mDurationData, "STAR"); // was mStartTime
mStoredInitialActorPosition = false;
if (esm.isNextSub("POS_"))
{
mStoredInitialActorPosition = true;
esm.getHT(mInitialActorPosition);
esm.getHTSized<12>(mInitialActorPosition);
}
}
@ -33,7 +33,7 @@ namespace ESM
void AiTravel::load(ESMReader& esm)
{
esm.getHNT(mData, "DATA");
esm.getHNTSized<12>(mData, "DATA");
esm.getHNOT(mHidden, "HIDD");
mRepeat = false;
esm.getHNOT(mRepeat, "REPT");
@ -49,7 +49,7 @@ namespace ESM
void AiEscort::load(ESMReader& esm)
{
esm.getHNT(mData, "DATA");
esm.getHNTSized<14>(mData, "DATA");
mTargetId = esm.getHNRefId("TARG");
mTargetActorId = -1;
esm.getHNOT(mTargetActorId, "TAID");
@ -81,7 +81,7 @@ namespace ESM
void AiFollow::load(ESMReader& esm)
{
esm.getHNT(mData, "DATA");
esm.getHNTSized<14>(mData, "DATA");
mTargetId = esm.getHNRefId("TARG");
mTargetActorId = -1;
esm.getHNOT(mTargetActorId, "TAID");

View file

@ -110,9 +110,13 @@ namespace ESM
getHTOrSkip(cellRef.mGoldValue);
break;
case fourCC("DODT"):
getHTOrSkip(cellRef.mDoorDest);
if constexpr (load)
{
esm.getHTSized<24>(cellRef.mDoorDest);
cellRef.mTeleport = true;
}
else
esm.skipHTSized<24, ESM::Position>();
break;
case fourCC("DNAM"):
getHStringOrSkip(cellRef.mDestCell);

View file

@ -16,7 +16,7 @@ namespace ESM
mLastRespawn.mDay = 0;
mLastRespawn.mHour = 0;
esm.getHNOT(mLastRespawn, "RESP");
esm.getHNOTSized<8>(mLastRespawn, "RESP");
}
void CellState::save(ESMWriter& esm) const

View file

@ -21,7 +21,7 @@ namespace ESM
mTradeTime.mDay = 0;
mTradeTime.mHour = 0;
esm.getHNOT(mTradeTime, "TIME");
esm.getHNOTSized<8>(mTradeTime, "TIME");
int flags = 0;
mDead = false;
@ -108,7 +108,7 @@ namespace ESM
mTimeOfDeath.mDay = 0;
mTimeOfDeath.mHour = 0;
esm.getHNOT(mTimeOfDeath, "DTIM");
esm.getHNOTSized<8>(mTimeOfDeath, "DTIM");
mSpells.load(esm);
mActiveSpells.load(esm);
@ -164,7 +164,7 @@ namespace ESM
CorprusStats stats;
esm.getHNT(stats.mWorsenings, "WORS");
esm.getHNT(stats.mNextWorsening, "TIME");
esm.getHNTSized<8>(stats.mNextWorsening, "TIME");
mCorprusSpells[id] = stats;
}

View file

@ -484,7 +484,7 @@ namespace ESM
case RefIdType::FormId:
{
FormId formId{};
getT(formId);
getTSized<8>(formId);
return RefId::formIdRefId(formId);
}
case RefIdType::Generated:

View file

@ -5,6 +5,7 @@
#include <filesystem>
#include <istream>
#include <memory>
#include <type_traits>
#include <vector>
#include <components/to_utf8/to_utf8.hpp>
@ -15,6 +16,9 @@
namespace ESM
{
template <class T>
constexpr bool IsReadable
= std::is_arithmetic_v<T> || std::is_enum_v<T> || (std::is_array_v<T> && IsReadable<std::remove_extent_t<T>>);
class ReadersCache;
@ -100,19 +104,17 @@ namespace ESM
ESM::RefId getCellId();
// Read data of a given type, stored in a subrecord of a given name
template <typename X>
template <typename X, typename = std::enable_if_t<IsReadable<X>>>
void getHNT(X& x, NAME name)
{
getSubNameIs(name);
getHT(x);
getHNTSized<sizeof(X)>(x, name);
}
// Optional version of getHNT
template <typename X>
template <typename X, typename = std::enable_if_t<IsReadable<X>>>
void getHNOT(X& x, NAME name)
{
if (isNextSub(name))
getHT(x);
getHNOTSized<sizeof(X)>(x, name);
}
// Version with extra size checking, to make sure the compiler
@ -120,34 +122,28 @@ namespace ESM
template <std::size_t size, typename X>
void getHNTSized(X& x, NAME name)
{
static_assert(sizeof(X) == size);
getHNT(x, name);
getSubNameIs(name);
getHTSized<size>(x);
}
template <std::size_t size, typename X>
void getHNOTSized(X& x, NAME name)
{
static_assert(sizeof(X) == size);
getHNOT(x, name);
if (isNextSub(name))
getHTSized<size>(x);
}
// Get data of a given type/size, including subrecord header
template <typename X>
template <typename X, typename = std::enable_if_t<IsReadable<X>>>
void getHT(X& x)
{
getSubHeader();
if (mCtx.leftSub != sizeof(X))
reportSubSizeMismatch(sizeof(X), mCtx.leftSub);
getT(x);
getHTSized<sizeof(X)>(x);
}
template <typename T>
template <typename T, typename = std::enable_if_t<IsReadable<T>>>
void skipHT()
{
getSubHeader();
if (mCtx.leftSub != sizeof(T))
reportSubSizeMismatch(sizeof(T), mCtx.leftSub);
skipT<T>();
skipHTSized<sizeof(T), T>();
}
// Version with extra size checking, to make sure the compiler
@ -155,15 +151,27 @@ namespace ESM
template <std::size_t size, typename X>
void getHTSized(X& x)
{
static_assert(sizeof(X) == size);
getHT(x);
getSubHeader();
if (mCtx.leftSub != size)
reportSubSizeMismatch(size, mCtx.leftSub);
getTSized<size>(x);
}
template <std::size_t size, typename T>
void skipHTSized()
{
static_assert(sizeof(T) == size);
skipHT<T>();
getSubHeader();
if (mCtx.leftSub != size)
reportSubSizeMismatch(size, mCtx.leftSub);
skip(size);
}
template <std::size_t size, typename X>
void getTSized(X& x)
{
static_assert(sizeof(X) == size);
getExact(&x, size);
}
// Read a string by the given name if it is the next record.
@ -266,13 +274,13 @@ namespace ESM
*
*************************************************************************/
template <typename X>
template <typename X, typename = std::enable_if_t<IsReadable<X>>>
void getT(X& x)
{
getExact(&x, sizeof(X));
}
template <typename T>
template <typename T, typename = std::enable_if_t<IsReadable<T>>>
void skipT()
{
skip(sizeof(T));
@ -283,7 +291,7 @@ namespace ESM
mEsm->read(static_cast<char*>(x), static_cast<std::streamsize>(size));
}
void getName(NAME& name) { getT(name); }
void getName(NAME& name) { getTSized<4>(name); }
void getUint(uint32_t& u) { getT(u); }
std::string getMaybeFixedStringSize(std::size_t size);

View file

@ -58,7 +58,7 @@ namespace ESM
void FogState::load(ESMReader& esm)
{
esm.getHNOT(mBounds, "BOUN");
esm.getHNOTSized<16>(mBounds, "BOUN");
esm.getHNOT(mNorthMarkerAngle, "ANGL");
const FormatVersion dataFormat = esm.getFormatVersion();
while (esm.isNextSub("FTEX"))

View file

@ -8,7 +8,7 @@ namespace ESM
void GlobalMap::load(ESMReader& esm)
{
esm.getHNT(mBounds, "BNDS");
esm.getHNTSized<16>(mBounds, "BNDS");
esm.getSubNameIs("DATA");
esm.getSubHeader();

View file

@ -28,7 +28,7 @@ namespace ESM
mName = esm.getHString();
break;
case fourCC("AADT"):
esm.getHT(mData);
esm.getHTSized<16>(mData);
hasData = true;
break;
case fourCC("SCRI"):

View file

@ -144,7 +144,7 @@ namespace ESM
mWater = waterLevel;
break;
case fourCC("AMBI"):
esm.getHT(mAmbi);
esm.getHTSized<16>(mAmbi);
mHasAmbi = true;
break;
case fourCC("RGNN"):

View file

@ -29,7 +29,7 @@ namespace ESM
// Cold weather not included before 1.3
if (esm.getSubSize() == sizeof(mData))
{
esm.getT(mData);
esm.getTSized<10>(mData);
}
else if (esm.getSubSize() == sizeof(mData) - 2)
{

View file

@ -99,7 +99,7 @@ namespace ESM
{
esm.getSubHeader();
mId = esm.getMaybeFixedRefIdSize(32);
esm.getT(mData);
esm.getTSized<20>(mData);
hasHeader = true;
break;

View file

@ -45,7 +45,7 @@ namespace ESM
if (esm.isNextSub("GMDT"))
{
esm.getHT(mGameData);
esm.getHTSized<124>(mGameData);
}
if (esm.isNextSub("SCRD"))
{

View file

@ -35,7 +35,7 @@ namespace ESM
if (esm.isNextSub("POS_"))
{
std::array<float, 6> pos;
esm.getHT(pos);
esm.getHTSized<24>(pos);
memcpy(mPosition.pos, pos.data(), sizeof(float) * 3);
memcpy(mPosition.rot, pos.data() + 3, sizeof(float) * 3);
}

View file

@ -17,8 +17,8 @@ namespace ESM
void BaseProjectileState::load(ESMReader& esm)
{
mId = esm.getHNRefId("ID__");
esm.getHNT(mPosition, "VEC3");
esm.getHNT(mOrientation, "QUAT");
esm.getHNTSized<12>(mPosition, "VEC3");
esm.getHNTSized<16>(mOrientation, "QUAT");
esm.getHNT(mActorId, "ACTO");
}
@ -64,7 +64,7 @@ namespace ESM
BaseProjectileState::load(esm);
mBowId = esm.getHNRefId("BOW_");
esm.getHNT(mVelocity, "VEL_");
esm.getHNTSized<12>(mVelocity, "VEL_");
mAttackStrength = 1.f;
esm.getHNOT(mAttackStrength, "STR_");

View file

@ -79,7 +79,7 @@ namespace ESM
CorprusStats stats;
esm.getHNT(stats.mWorsenings, "WORS");
esm.getHNT(stats.mNextWorsening, "TIME");
esm.getHNTSized<8>(stats.mNextWorsening, "TIME");
mCorprusSpells[id] = stats;
}
@ -88,7 +88,7 @@ namespace ESM
{
ESM::RefId id = esm.getRefId();
TimeStamp time;
esm.getHNT(time, "TIME");
esm.getHNTSized<8>(time, "TIME");
mUsedPowers[id] = time;
}