Implemented property name validation system

This commit is contained in:
Aruki
2018-02-11 16:11:49 -07:00
parent f980bc7536
commit 11917d03e8
44 changed files with 864 additions and 241 deletions

View File

@@ -28,6 +28,7 @@ enum EPropertyType
// functions defined in IPropertyTemplate.cpp
EPropertyType PropStringToPropEnum(TString Prop);
TString PropEnumToPropString(EPropertyType Prop);
const char* HashablePropTypeName(EPropertyType Prop);
#endif // EPROPERTYTYPE

View File

@@ -1,5 +1,6 @@
#include "IPropertyTemplate.h"
#include "CMasterTemplate.h"
#include <Common/Hash/CCRC32.h>
#include <iostream>
// ************ IPropertyTemplate ************
@@ -69,6 +70,36 @@ bool IPropertyTemplate::IsFromStructTemplate() const
return false;
}
bool IPropertyTemplate::IsNameCorrect() const
{
// Check whether the property name is correct... i.e., if we hash it, does it match the property ID?
// Only valid for Prime 2 and up, since Prime 1 doesn't have real property IDs, so we can't validate names
if (Game() >= eEchoesDemo)
{
// Don't hash for single-property structs
if ( (!Parent() || !Parent()->IsSingleProperty()) &&
// Don't hash for the three properties in EditorProperties that have fourCC property IDs
mID != FOURCC('INAM') &&
mID != FOURCC('XFRM') &&
mID != FOURCC('ACTV') )
{
// Only re-hash if we need to. Save the result (output won't change if function is called multiple times)
if (!mHasCachedNameCheck)
{
// The property ID is just a CRC32 of the property name + the type
CCRC32 Hash;
Hash.Hash(*mName);
Hash.Hash(GetTypeNameString());
mCachedNameIsCorrect = Hash.Digest() == mID;
mHasCachedNameCheck = true;
}
return mCachedNameIsCorrect;
}
}
return true;
}
TString IPropertyTemplate::FindStructSource() const
{
const CStructTemplate *pkStruct = mpParent;
@@ -95,6 +126,7 @@ void CStructTemplate::CopyStructData(const CStructTemplate *pkStruct)
mVersionPropertyCounts = pkStruct->mVersionPropertyCounts;
mIsSingleProperty = pkStruct->mIsSingleProperty;
mSourceFile = pkStruct->mSourceFile;
mTypeName = pkStruct->mTypeName;
mSubProperties.resize(pkStruct->mSubProperties.size());
@@ -271,6 +303,30 @@ EPropertyType PropStringToPropEnum(TString Prop)
return eInvalidProperty;
}
const char* HashablePropTypeName(EPropertyType Prop)
{
// Variants that match Retro's internal type names for generating property IDs. case sensitive
switch (Prop)
{
case eBoolProperty: return "bool";
case eLongProperty: return "int";
case eEnumProperty: return "enum";
case eBitfieldProperty: return "bitfield";
case eFloatProperty: return "float";
case eStringProperty: return "string";
case eColorProperty: return "Color";
case eVector3Property: return "Vector3f";
case eSoundProperty: return "SfxId";
case eAssetProperty: return "asset";
case eMayaSplineProperty: return "MayaSpline";
// All other types are either invalid or need a custom reimplementation because they can return multiple strings (like struct)
default:
ASSERT(false);
return nullptr;
}
}
// ************ DEBUG ************
void CStructTemplate::DebugPrintProperties(TString base)
{

View File

@@ -40,6 +40,8 @@ protected:
u32 mID;
ECookPreference mCookPreference;
std::vector<u32> mAllowedVersions;
mutable bool mHasCachedNameCheck;
mutable bool mCachedNameIsCorrect;
public:
IPropertyTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
@@ -49,6 +51,8 @@ public:
, mpMasterTemplate(pMaster)
, mName("UNSET PROPERTY NAME")
, mCookPreference(eNoCookPreference)
, mHasCachedNameCheck(false)
, mCachedNameIsCorrect(false)
{
}
@@ -59,6 +63,8 @@ public:
, mpMasterTemplate(pMaster)
, mName(rkName)
, mCookPreference(CookPreference)
, mHasCachedNameCheck(false)
, mCachedNameIsCorrect(false)
{
}
@@ -93,6 +99,7 @@ public:
virtual bool HasValidRange() const { return false; }
virtual TString RangeToString() const { return ""; }
virtual TString Suffix() const { return ""; }
virtual const char* GetTypeNameString() const { return HashablePropTypeName(Type()); }
virtual void SetParam(const TString& rkParamName, const TString& rkValue)
{
@@ -118,6 +125,7 @@ public:
TIDString IDString(bool FullPath) const;
bool IsDescendantOf(const CStructTemplate *pStruct) const;
bool IsFromStructTemplate() const;
bool IsNameCorrect() const;
TString FindStructSource() const;
CStructTemplate* RootStruct();
@@ -129,7 +137,7 @@ public:
inline CStructTemplate* Parent() const { return mpParent; }
inline CScriptTemplate* ScriptTemplate() const { return mpScriptTemplate; }
inline CMasterTemplate* MasterTemplate() const { return mpMasterTemplate; }
inline void SetName(const TString& rkName) { mName = rkName; }
inline void SetName(const TString& rkName) { mName = rkName; mHasCachedNameCheck = false; }
inline void SetDescription(const TString& rkDesc) { mDescription = rkDesc; }
};
@@ -302,13 +310,13 @@ public:
};
// Typedefs for all property types that don't need further functionality.
typedef TTypedPropertyTemplate<bool, eBoolProperty, CBoolValue, true> TBoolTemplate;
typedef TNumericalPropertyTemplate<s8, eByteProperty, CByteValue> TByteTemplate;
typedef TNumericalPropertyTemplate<s16, eShortProperty, CShortValue> TShortTemplate;
typedef TNumericalPropertyTemplate<s32, eLongProperty, CLongValue> TLongTemplate;
typedef TNumericalPropertyTemplate<float, eFloatProperty, CFloatValue> TFloatTemplate;
typedef TTypedPropertyTemplate<CVector3f, eVector3Property, CVector3Value, true> TVector3Template;
typedef TTypedPropertyTemplate<CColor, eColorProperty, CColorValue, true> TColorTemplate;
typedef TTypedPropertyTemplate<bool, eBoolProperty, CBoolValue, true> TBoolTemplate;
typedef TNumericalPropertyTemplate<s8, eByteProperty, CByteValue> TByteTemplate;
typedef TNumericalPropertyTemplate<s16, eShortProperty, CShortValue> TShortTemplate;
typedef TNumericalPropertyTemplate<s32, eLongProperty, CLongValue> TLongTemplate;
typedef TNumericalPropertyTemplate<float, eFloatProperty, CFloatValue> TFloatTemplate;
typedef TTypedPropertyTemplate<CVector3f, eVector3Property, CVector3Value, true> TVector3Template;
typedef TTypedPropertyTemplate<CColor, eColorProperty, CColorValue, true> TColorTemplate;
// TCharacterTemplate, TSoundTemplate, TStringTemplate, and TMayaSplineTemplate get their own subclasses so they can reimplement a couple functions
class TCharacterTemplate : public TTypedPropertyTemplate<CAnimationParameters, eCharacterProperty, CCharacterValue, false>
@@ -327,6 +335,13 @@ public:
{
return new TCharacterProperty(this, pInstance, pParent, CAnimationParameters(Game()));
}
const char* GetTypeNameString() const
{
return (Game() < eCorruptionProto ? "AnimationParameters" : "CharacterAnimationSet");
}
IMPLEMENT_TEMPLATE_CLONE(TCharacterTemplate)
};
class TSoundTemplate : public TTypedPropertyTemplate<u32, eSoundProperty, CSoundValue, false>
@@ -345,6 +360,8 @@ public:
{
return new TSoundProperty(this, pInstance, pParent, -1);
}
IMPLEMENT_TEMPLATE_CLONE(TSoundTemplate)
};
class TStringTemplate : public TTypedPropertyTemplate<TString, eStringProperty, CStringValue, false>
@@ -363,6 +380,8 @@ public:
{
return new TStringProperty(this, pInstance, pParent);
}
IMPLEMENT_TEMPLATE_CLONE(TStringTemplate)
};
class TMayaSplineTemplate : public TTypedPropertyTemplate<std::vector<u8>, eMayaSplineProperty, CMayaSplineValue, false>
@@ -381,6 +400,8 @@ public:
{
return new TMayaSplineProperty(this, pInstance, pParent);
}
IMPLEMENT_TEMPLATE_CLONE(TMayaSplineTemplate)
};
// CAssetTemplate - Property template for assets. Tracks a list of resource types that
@@ -448,15 +469,18 @@ class CEnumTemplate : public TTypedPropertyTemplate<s32, eEnumProperty, CHexLong
};
std::vector<SEnumerator> mEnumerators;
TString mSourceFile;
bool mUsesHashes;
public:
CEnumTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent)
, mUsesHashes(false)
{
}
CEnumTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent)
, mUsesHashes(false)
{
}
@@ -480,6 +504,7 @@ public:
const CEnumTemplate *pkEnum = static_cast<const CEnumTemplate*>(pkTemp);
mEnumerators = pkEnum->mEnumerators;
mSourceFile = pkEnum->mSourceFile;
mUsesHashes = pkEnum->mUsesHashes;
}
virtual bool Matches(const IPropertyTemplate *pkTemp) const
@@ -488,7 +513,13 @@ public:
return ( (TTypedPropertyTemplate::Matches(pkTemp)) &&
(mEnumerators == pkEnum->mEnumerators) &&
(mSourceFile == pkEnum->mSourceFile) );
(mSourceFile == pkEnum->mSourceFile) &&
(mUsesHashes == pkEnum->mUsesHashes) );
}
virtual const char* GetTypeNameString() const
{
return (mUsesHashes ? "enum" : "choice");
}
inline TString SourceFile() const { return mSourceFile; }
@@ -603,6 +634,7 @@ protected:
std::vector<u32> mVersionPropertyCounts;
bool mIsSingleProperty;
TString mSourceFile;
TString mTypeName;
void DetermineVersionPropertyCounts();
public:
@@ -656,7 +688,8 @@ public:
if ( (IPropertyTemplate::Matches(pkTemp)) &&
(mVersionPropertyCounts == pkStruct->mVersionPropertyCounts) &&
(mIsSingleProperty == pkStruct->mIsSingleProperty) &&
(mSourceFile == pkStruct->mSourceFile) )
(mSourceFile == pkStruct->mSourceFile) &&
(mTypeName == pkStruct->mTypeName) )
{
return StructDataMatches(pkStruct);
}
@@ -664,6 +697,12 @@ public:
return false;
}
const char* GetTypeNameString() const
{
// hack - currently templates embedded within another XML can't have a type name
return mTypeName.IsEmpty() ? *mName : *mTypeName;
}
bool StructDataMatches(const CStructTemplate *pkStruct) const
{
if ( (mIsSingleProperty == pkStruct->mIsSingleProperty) &&