added variant class

actorid
Marc Zinnschlag 11 years ago
parent 3bd228f71b
commit 65081f5520

@ -1,6 +1,8 @@
#ifndef CSV_WORLD_VARTYPEDELEGATE_H
#define CSV_WORLD_VARTYPEDELEGATE_H
#include <components/esm/variant.hpp>
#include "enumdelegate.hpp"
namespace CSVWorld

@ -39,7 +39,7 @@ add_component_dir (esm
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
loadweap records aipackage effectlist spelllist
loadweap records aipackage effectlist spelllist variant variantimp
)
add_component_dir (misc

@ -9,18 +9,6 @@ namespace ESM
// Pixel color value. Standard four-byte rr,gg,bb,aa format.
typedef int32_t Color;
enum VarType
{
VT_Unknown,
VT_None,
VT_Short, // stored as a float, kinda
VT_Int,
VT_Long, // stored as a float
VT_Float,
VT_String,
VT_Ignored
};
enum Specialization
{
SPC_Combat = 0,

@ -4,6 +4,7 @@
#include <string>
#include "defs.hpp"
#include "variant.hpp"
namespace ESM
{

@ -4,6 +4,7 @@
#include <string>
#include "defs.hpp"
#include "variant.hpp"
namespace ESM
{

@ -5,6 +5,7 @@
#include <vector>
#include "defs.hpp"
#include "variant.hpp"
namespace ESM
{

@ -0,0 +1,256 @@
#include "variant.hpp"
#include <cassert>
#include <stdexcept>
#include "esmreader.hpp"
#include "variantimp.hpp"
ESM::Variant::Variant() : mType (VT_None), mData (0) {}
ESM::Variant::~Variant()
{
delete mData;
}
ESM::Variant& ESM::Variant::operator= (const Variant& variant)
{
if (&variant!=this)
{
VariantDataBase *newData = variant.mData ? variant.mData->clone() : 0;
delete mData;
mType = variant.mType;
mData = newData;
}
return *this;
}
ESM::Variant::Variant (const Variant& variant)
: mType (variant.mType), mData (variant.mData ? variant.mData->clone() : 0)
{}
ESM::VarType ESM::Variant::getType() const
{
return mType;
}
std::string ESM::Variant::toString() const
{
if (!mData)
throw std::runtime_error ("can not convert empty variant to string");
return mData->getString();
}
int ESM::Variant::getInteger() const
{
if (!mData)
throw std::runtime_error ("can not convert empty variant to integer");
return mData->getInteger();
}
float ESM::Variant::getFloat() const
{
if (!mData)
throw std::runtime_error ("can not convert empty variant to float");
return mData->getFloat();
}
void ESM::Variant::read (ESMReader& esm, Format format)
{
// type
VarType type = VT_Unknown;
if (format==Format_Global)
{
std::string typeId = esm.getHNString ("FNAM");
if (typeId == "s")
type = VT_Short;
else if (typeId == "l")
type = VT_Long;
else if (typeId == "f")
type = VT_Float;
else
esm.fail ("illegal global variable type " + typeId);
}
else // GMST
{
esm.getSubName();
NAME name = esm.retSubName();
if (name=="STRV")
{
type = VT_String;
}
else if (name=="INTV")
{
type = VT_Int;
}
else if (name=="FLTV")
{
type = VT_Float;
}
else
esm.fail ("invalid subrecord: " + name.toString());
}
setType (type);
// data
if (mData)
mData->read (esm, format, mType);
}
void ESM::Variant::write (ESMWriter& esm, Format format) const
{
if (mType==VT_Unknown)
{
throw std::runtime_error ("can not serialise variant of unknown type");
}
else if (mType==VT_None)
{
if (format==Format_Global)
throw std::runtime_error ("can not serialise variant of type none to global format");
// nothing to do here for GMST format
}
else
mData->write (esm, format, mType);
}
void ESM::Variant::write (std::ostream& stream) const
{
switch (mType)
{
case VT_Unknown:
stream << "variant unknown";
break;
case VT_None:
stream << "variant none";
break;
case VT_Short:
stream << "variant short: " << mData->getInteger();
break;
case VT_Int:
stream << "variant int: " << mData->getInteger();
break;
case VT_Long:
stream << "variant long: " << mData->getInteger();
break;
case VT_Float:
stream << "variant float: " << mData->getFloat();
break;
case VT_String:
stream << "variant string: \"" << mData->getString() << "\2";
break;
}
}
void ESM::Variant::setType (VarType type)
{
if (type!=mType)
{
VariantDataBase *newData = 0;
switch (type)
{
case VT_Unknown:
case VT_None:
break; // no data
case VT_Short:
case VT_Int:
case VT_Long:
newData = new VariantIntegerData (mData);
break;
case VT_Float:
newData = new VariantFloatData (mData);
break;
case VT_String:
newData = new VariantStringData (mData);
break;
}
delete mData;
mData = newData;
mType = type;
}
}
void ESM::Variant::setString (const std::string& value)
{
if (!mData)
throw std::runtime_error ("can not assign string to empty variant");
mData->setString (value);
}
void ESM::Variant::setInteger (int value)
{
if (!mData)
throw std::runtime_error ("can not assign integer to empty variant");
mData->setInteger (value);
}
void ESM::Variant::setFloat (float value)
{
if (!mData)
throw std::runtime_error ("can not assign float to empty variant");
mData->setFloat (value);
}
bool ESM::Variant::isEqual (const Variant& value) const
{
if (mType!=value.mType)
return false;
if (!mData)
return true;
assert (value.mData);
return mData->isEqual (*value.mData);
}
std::ostream& ESM::operator<< (std::ostream& stream, const Variant& value)
{
value.write (stream);
return stream;
}
bool ESM::operator== (const Variant& left, const Variant& right)
{
return left.isEqual (right);
}
bool ESM::operator!= (const Variant& left, const Variant& right)
{
return !(left==right);
}

@ -0,0 +1,85 @@
#ifndef OPENMW_ESM_VARIANT_H
#define OPENMW_ESM_VARIANT_H
#include <string>
#include <iosfwd>
namespace ESM
{
class ESMReader;
class ESMWriter;
enum VarType
{
VT_Unknown,
VT_None,
VT_Short, // stored as a float, kinda
VT_Int,
VT_Long, // stored as a float
VT_Float,
VT_String
};
class VariantDataBase;
class Variant
{
VarType mType;
VariantDataBase *mData;
public:
enum Format
{
Format_Global,
Format_Gmst
};
Variant();
~Variant();
Variant& operator= (const Variant& variant);
Variant (const Variant& variant);
VarType getType() const;
std::string toString() const;
///< Will throw an exception, if value can not be represented as a string.
int getInteger() const;
///< Will throw an exception, if value can not be represented as an integer (implicit
/// casting of float values is permitted).
float getFloat() const;
///< Will throw an exception, if value can not be represented as a float value.
void read (ESMReader& esm, Format format);
void write (ESMWriter& esm, Format format) const;
void write (std::ostream& stream) const;
///< Write in text format.
void setType (VarType type);
void setString (const std::string& value);
///< Will throw an exception, if type is not compatible with string.
void setInteger (int value);
///< Will throw an exception, if type is not compatible with integer.
void setFloat (float value);
///< Will throw an exception, if type is not compatible with float.
bool isEqual (const Variant& value) const;
};
std::ostream& operator<<(std::ostream& stream, const Variant& value);
bool operator== (const Variant& left, const Variant& right);
bool operator!= (const Variant& left, const Variant& right);
}
#endif

@ -0,0 +1,262 @@
#include "variantimp.hpp"
#include <stdexcept>
#include "esmreader.hpp"
#include "esmwriter.hpp"
ESM::VariantDataBase::~VariantDataBase() {}
std::string ESM::VariantDataBase::getString (bool default_) const
{
if (default_)
return "";
throw std::runtime_error ("can not convert variant to string");
}
int ESM::VariantDataBase::getInteger (bool default_) const
{
if (default_)
return 0;
throw std::runtime_error ("can not convert variant to integer");
}
float ESM::VariantDataBase::getFloat (bool default_) const
{
if (default_)
return 0;
throw std::runtime_error ("can not convert variant to float");
}
void ESM::VariantDataBase::setString (const std::string& value)
{
throw std::runtime_error ("conversion of string to variant not possible");
}
void ESM::VariantDataBase::setInteger (int value)
{
throw std::runtime_error ("conversion of integer to variant not possible");
}
void ESM::VariantDataBase::setFloat (float value)
{
throw std::runtime_error ("conversion of float to variant not possible");
}
ESM::VariantStringData::VariantStringData (const VariantDataBase *data)
{
if (data)
mValue = data->getString (true);
}
ESM::VariantDataBase *ESM::VariantStringData::clone() const
{
return new VariantStringData (*this);
}
std::string ESM::VariantStringData::getString (bool default_) const
{
return mValue;
}
void ESM::VariantStringData::setString (const std::string& value)
{
mValue = value;
}
void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarType type)
{
if (type!=VT_String)
throw std::logic_error ("not a string type");
if (format==Variant::Format_Global)
esm.fail ("global variables of type string not supported");
// GMST
mValue = esm.getHString();
}
void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarType type) const
{
if (type!=VT_String)
throw std::logic_error ("not a string type");
if (format==Variant::Format_Global)
throw std::runtime_error ("global variables of type string not supported");
// GMST
esm.writeHNString ("STRV", mValue);
}
bool ESM::VariantStringData::isEqual (const VariantDataBase& value) const
{
return dynamic_cast<const VariantStringData&> (value).mValue==mValue;
}
ESM::VariantIntegerData::VariantIntegerData (const VariantDataBase *data) : mValue (0)
{
if (data)
mValue = data->getInteger (true);
}
ESM::VariantDataBase *ESM::VariantIntegerData::clone() const
{
return new VariantIntegerData (*this);
}
int ESM::VariantIntegerData::getInteger (bool default_) const
{
return mValue;
}
float ESM::VariantIntegerData::getFloat (bool default_) const
{
return mValue;
}
void ESM::VariantIntegerData::setInteger (int value)
{
mValue = value;
}
void ESM::VariantIntegerData::setFloat (float value)
{
mValue = static_cast<int> (value);
}
void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarType type)
{
if (type!=VT_Short && type!=VT_Long && type!=VT_Int)
throw std::logic_error ("not an integer type");
if (format==Variant::Format_Global)
{
float value;
esm.getHNT (value, "FLTV");
if (type==VT_Short)
{
if (value!=value)
mValue = 0; // nan
else
mValue = static_cast<short> (value);
}
else if (type==VT_Long)
mValue = static_cast<int> (value);
else
esm.fail ("unsupported global variable integer type");
}
else // GMST
{
if (type==VT_Int)
esm.fail ("unsupported global variable integer type");
esm.getHT (mValue);
}
}
void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const
{
if (type!=VT_Short && type!=VT_Long && type!=VT_Int)
throw std::logic_error ("not an integer type");
if (format==Variant::Format_Global)
{
if (type==VT_Short || type==VT_Long)
{
float value = mValue;
esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l");
esm.writeHNT ("FLTV", value);
}
else
throw std::runtime_error ("unsupported global variable integer type");
}
else // GMST
{
if (type==VT_Int)
throw std::runtime_error ("unsupported global variable integer type");
esm.writeHNT ("INTV", mValue);
}
}
bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const
{
return dynamic_cast<const VariantIntegerData&> (value).mValue==mValue;
}
ESM::VariantFloatData::VariantFloatData (const VariantDataBase *data) : mValue (0)
{
if (data)
mValue = data->getFloat (true);
}
ESM::VariantDataBase *ESM::VariantFloatData::clone() const
{
return new VariantFloatData (*this);
}
int ESM::VariantFloatData::getInteger (bool default_) const
{
return static_cast<int> (mValue);
}
float ESM::VariantFloatData::getFloat (bool default_) const
{
return mValue;
}
void ESM::VariantFloatData::setInteger (int value)
{
mValue = value;
}
void ESM::VariantFloatData::setFloat (float value)
{
mValue = value;
}
void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarType type)
{
if (type!=VT_Float)
throw std::logic_error ("not a float type");
if (format==Variant::Format_Global)
{
esm.getHNT (mValue, "FLTV");
}
else // GMST
{
esm.getHT (mValue);
}
}
void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarType type) const
{
if (type!=VT_Float)
throw std::logic_error ("not a float type");
if (format==Variant::Format_Global)
{
esm.writeHNString ("FNAM", "f");
esm.writeHNT ("FLTV", mValue);
}
else // GMST
{
esm.writeHNT ("INTV", mValue);
}
}
bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const
{
return dynamic_cast<const VariantFloatData&> (value).mValue==mValue;
}

@ -0,0 +1,179 @@
#ifndef OPENMW_ESM_VARIANTIMP_H
#define OPENMW_ESM_VARIANTIMP_H
#include <string>
#include "variant.hpp"
namespace ESM
{
class VariantDataBase
{
public:
virtual ~VariantDataBase();
virtual VariantDataBase *clone() const = 0;
virtual std::string getString (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as a string.
///
/// \note Numeric values are not converted to strings.
///
/// \param default_ Return a default value instead of throwing an exception.
///
/// Default-implementation: throw an exception.
virtual int getInteger (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as an integer (implicit
/// casting of float values is permitted).
///
/// \param default_ Return a default value instead of throwing an exception.
///
/// Default-implementation: throw an exception.
virtual float getFloat (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as a float value.
///
/// \param default_ Return a default value instead of throwing an exception.
///
/// Default-implementation: throw an exception.
virtual void setString (const std::string& value);
///< Will throw an exception, if type is not compatible with string.
///
/// Default-implementation: throw an exception.
virtual void setInteger (int value);
///< Will throw an exception, if type is not compatible with integer.
///
/// Default-implementation: throw an exception.
virtual void setFloat (float value);
///< Will throw an exception, if type is not compatible with float.
///
/// Default-implementation: throw an exception.
virtual void read (ESMReader& esm, Variant::Format format, VarType type) = 0;
///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail
virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const = 0;
///< If \a type is not supported by \a format, an exception is thrown.
virtual bool isEqual (const VariantDataBase& value) const = 0;
///< If the (C++) type of \a value does not match the type of *this, an exception is thrown.
};
class VariantStringData : public VariantDataBase
{
std::string mValue;
public:
VariantStringData (const VariantDataBase *data = 0);
///< Calling the constructor with an incompatible data type will result in a silent
/// default initialisation.
virtual VariantDataBase *clone() const;
virtual std::string getString (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as a string.
///
/// \note Numeric values are not converted to strings.
///
/// \param default_ Return a default value instead of throwing an exception.
virtual void setString (const std::string& value);
///< Will throw an exception, if type is not compatible with string.
virtual void read (ESMReader& esm, Variant::Format format, VarType type);
///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail
virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const;
///< If \a type is not supported by \a format, an exception is thrown.
virtual bool isEqual (const VariantDataBase& value) const;
///< If the (C++) type of \a value does not match the type of *this, an exception is thrown.
};
class VariantIntegerData : public VariantDataBase
{
int mValue;
public:
VariantIntegerData (const VariantDataBase *data = 0);
///< Calling the constructor with an incompatible data type will result in a silent
/// default initialisation.
virtual VariantDataBase *clone() const;
virtual int getInteger (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as an integer (implicit
/// casting of float values is permitted).
///
/// \param default_ Return a default value instead of throwing an exception.
virtual float getFloat (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as a float value.
///
/// \param default_ Return a default value instead of throwing an exception.
virtual void setInteger (int value);
///< Will throw an exception, if type is not compatible with integer.
virtual void setFloat (float value);
///< Will throw an exception, if type is not compatible with float.
virtual void read (ESMReader& esm, Variant::Format format, VarType type);
///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail
virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const;
///< If \a type is not supported by \a format, an exception is thrown.
virtual bool isEqual (const VariantDataBase& value) const;
///< If the (C++) type of \a value does not match the type of *this, an exception is thrown.
};
class VariantFloatData : public VariantDataBase
{
float mValue;
public:
VariantFloatData (const VariantDataBase *data = 0);
///< Calling the constructor with an incompatible data type will result in a silent
/// default initialisation.
virtual VariantDataBase *clone() const;
virtual int getInteger (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as an integer (implicit
/// casting of float values is permitted).
///
/// \param default_ Return a default value instead of throwing an exception.
virtual float getFloat (bool default_ = false) const;
///< Will throw an exception, if value can not be represented as a float value.
///
/// \param default_ Return a default value instead of throwing an exception.
virtual void setInteger (int value);
///< Will throw an exception, if type is not compatible with integer.
virtual void setFloat (float value);
///< Will throw an exception, if type is not compatible with float.
virtual void read (ESMReader& esm, Variant::Format format, VarType type);
///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail
virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const;
///< If \a type is not supported by \a format, an exception is thrown.
virtual bool isEqual (const VariantDataBase& value) const;
///< If the (C++) type of \a value does not match the type of *this, an exception is thrown.
};
}
#endif
Loading…
Cancel
Save