You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/components/esm/variant.cpp

342 lines
6.9 KiB
C++

#include "variant.hpp"
#include <cassert>
#include <stdexcept>
#include "esmreader.hpp"
#include "variantimp.hpp"
#include "defs.hpp"
namespace
{
const uint32_t STRV = ESM::FourCC<'S','T','R','V'>::value;
const uint32_t INTV = ESM::FourCC<'I','N','T','V'>::value;
const uint32_t FLTV = ESM::FourCC<'F','L','T','V'>::value;
const uint32_t STTV = ESM::FourCC<'S','T','T','V'>::value;
}
ESM::Variant::Variant() : mType (VT_None), mData (0) {}
ESM::Variant::Variant(const std::string &value)
{
mData = 0;
mType = VT_None;
setType(VT_String);
setString(value);
}
ESM::Variant::Variant(int value)
{
mData = 0;
mType = VT_None;
setType(VT_Long);
setInteger(value);
}
ESM::Variant::Variant(float value)
{
mData = 0;
mType = VT_None;
setType(VT_Float);
setFloat(value);
}
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::getString() 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 if (format==Format_Gmst)
{
if (!esm.hasMoreSubs())
{
type = VT_None;
}
else
{
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());
}
}
else if (format == Format_Info)
{
esm.getSubName();
NAME name = esm.retSubName();
if (name==INTV)
{
type = VT_Int;
}
else if (name==FLTV)
{
type = VT_Float;
}
else
esm.fail ("invalid subrecord: " + name.toString());
}
else if (format == Format_Local)
{
esm.getSubName();
NAME name = esm.retSubName();
if (name==INTV)
{
type = VT_Int;
}
else if (name==FLTV)
{
type = VT_Float;
}
else if (name==STTV)
{
type = VT_Short;
}
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");
if (format==Format_Info)
throw std::runtime_error ("can not serialise variant of type none to info format");
if (format==Format_Local)
throw std::runtime_error ("can not serialise variant of type none to local 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() << "\"";
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);
}