Merge branch 'master' of git://github.com/zinnschlag/openmw into graphics

actorid
scrawl 12 years ago
commit c9f7f1b994

@ -112,14 +112,11 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss)
case '5': oper_str = ">="; break;
}
std::string value_str = "??";
if (ss.mType == ESM::VT_Int)
value_str = str(boost::format("%d") % ss.mI);
else if (ss.mType == ESM::VT_Float)
value_str = str(boost::format("%f") % ss.mF);
std::ostringstream stream;
stream << ss.mValue;
std::string result = str(boost::format("%-12s %-32s %2s %s")
% type_str % func_str % oper_str % value_str);
% type_str % func_str % oper_str % stream.str());
return result;
}
@ -713,31 +710,13 @@ void Record<ESM::Faction>::print()
template<>
void Record<ESM::Global>::print()
{
// nothing to print (well, nothing that's correct anyway)
std::cout << " Type: " << mData.mType << std::endl;
std::cout << " Value: " << mData.mValue << std::endl;
std::cout << " " << mData.mValue << std::endl;
}
template<>
void Record<ESM::GameSetting>::print()
{
std::cout << " Value: ";
switch (mData.mType) {
case ESM::VT_String:
std::cout << "'" << mData.mStr << "' (std::string)";
break;
case ESM::VT_Float:
std::cout << mData.mF << " (float)";
break;
case ESM::VT_Int:
std::cout << mData.mI << " (int)";
break;
default:
std::cout << "unknown type";
}
std::cout << " " << mData.mValue << std::endl;
}
template<>

@ -116,8 +116,7 @@ void CSMDoc::Document::addOptionalGmsts()
{
ESM::GameSetting gmst;
gmst.mId = sFloats[i];
gmst.mF = 0;
gmst.mType = ESM::VT_Float;
gmst.mValue.setType (ESM::VT_Float);
addOptionalGmst (gmst);
}
@ -125,8 +124,7 @@ void CSMDoc::Document::addOptionalGmsts()
{
ESM::GameSetting gmst;
gmst.mId = sIntegers[i];
gmst.mI = 0;
gmst.mType = ESM::VT_Long;
gmst.mValue.setType (ESM::VT_Int);
addOptionalGmst (gmst);
}
@ -134,8 +132,8 @@ void CSMDoc::Document::addOptionalGmsts()
{
ESM::GameSetting gmst;
gmst.mId = sStrings[i];
gmst.mStr = "<no text>";
gmst.mType = ESM::VT_String;
gmst.mValue.setType (ESM::VT_String);
gmst.mValue.setString ("<no text>");
addOptionalGmst (gmst);
}
}
@ -154,8 +152,7 @@ void CSMDoc::Document::addOptionalGlobals()
{
ESM::Global global;
global.mId = sGlobals[i];
global.mType = ESM::VT_Int;
global.mValue = 0;
global.mValue.setType (ESM::VT_Long);
addOptionalGlobal (global);
}
}
@ -192,9 +189,14 @@ void CSMDoc::Document::createBase()
for (int i=0; sGlobals[i]; ++i)
{
ESM::Global record;
record.mId = sGlobals[i];
record.mValue = i==0 ? 1 : 0;
record.mType = ESM::VT_Float;
record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int);
if (i==0)
record.mValue.setInteger (1);
getData().getGlobals().add (record);
}
}

@ -30,7 +30,8 @@ namespace CSMWorld
Display_Integer,
Display_Float,
Display_Var,
Display_VarType
Display_GmstVarType,
Display_GlobalVarType
};
std::string mTitle;

@ -12,13 +12,13 @@ namespace CSMWorld
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mValue;
return record.get().mValue.getFloat();
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mValue = data.toFloat();
record2.mValue.setFloat (data.toFloat());
record.setModified (record2);
}
@ -96,17 +96,17 @@ namespace CSMWorld
template<typename ESXRecordT>
struct VarTypeColumn : public Column<ESXRecordT>
{
VarTypeColumn() : Column<ESXRecordT> ("Type", ColumnBase::Display_VarType) {}
VarTypeColumn (ColumnBase::Display display) : Column<ESXRecordT> ("Type", display) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mType);
return static_cast<int> (record.get().mValue.getType());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mType = static_cast<ESM::VarType> (data.toInt());
record2.mValue.setType (static_cast<ESM::VarType> (data.toInt()));
record.setModified (record2);
}
@ -123,11 +123,21 @@ namespace CSMWorld
virtual QVariant get (const Record<ESXRecordT>& record) const
{
switch (record.get().mType)
switch (record.get().mValue.getType())
{
case ESM::VT_String: return record.get().mStr.c_str(); break;
case ESM::VT_Int: return record.get().mI; break;
case ESM::VT_Float: return record.get().mF; break;
case ESM::VT_String:
return record.get().mValue.getString().c_str(); break;
case ESM::VT_Int:
case ESM::VT_Short:
case ESM::VT_Long:
return record.get().mValue.getInteger(); break;
case ESM::VT_Float:
return record.get().mValue.getFloat(); break;
default: return QVariant();
}
@ -137,11 +147,24 @@ namespace CSMWorld
{
ESXRecordT record2 = record.get();
switch (record2.mType)
switch (record2.mValue.getType())
{
case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break;
case ESM::VT_Int: record2.mI = data.toInt(); break;
case ESM::VT_Float: record2.mF = data.toFloat(); break;
case ESM::VT_String:
record2.mValue.setString (data.toString().toUtf8().constData());
break;
case ESM::VT_Int:
case ESM::VT_Short:
case ESM::VT_Long:
record2.mValue.setInteger (data.toInt());
break;
case ESM::VT_Float:
record2.mValue.setFloat (data.toFloat());
break;
default: break;
}

@ -6,6 +6,7 @@
#include <QAbstractTableModel>
#include <components/esm/esmreader.hpp>
#include <components/esm/defs.hpp>
#include <components/esm/loadglob.hpp>
#include "idtable.hpp"
@ -26,12 +27,13 @@ CSMWorld::Data::Data()
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global));
mGlobals.addColumn (new FloatValueColumn<ESM::Global>);
mGlobals.addColumn (new VarTypeColumn<ESM::Global> (ColumnBase::Display_GlobalVarType));
mGlobals.addColumn (new VarValueColumn<ESM::Global>);
mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>);
mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>);
mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst));
mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting>);
mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting> (ColumnBase::Display_GmstVarType));
mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);

@ -35,8 +35,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
{
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType,
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType,
new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType,
new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float));
}
CSVDoc::ViewManager::~ViewManager()

@ -85,7 +85,7 @@ void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)
{
{ ESM::VT_None, "empty" },
{ ESM::VT_Short, "short" },
{ ESM::VT_Int, "long" },
{ ESM::VT_Int, "integer" },
{ ESM::VT_Long, "long" },
{ ESM::VT_Float, "float" },
{ ESM::VT_String, "string" },

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

@ -31,14 +31,13 @@ namespace
template<typename T>
bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1)
{
if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int ||
select.mType==ESM::VT_Long)
if (select.mValue.getType()==ESM::VT_Int)
{
return selectCompareImp (select.mSelectRule[4], value1, select.mI);
return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getInteger());
}
else if (select.mType==ESM::VT_Float)
else if (select.mValue.getType()==ESM::VT_Float)
{
return selectCompareImp (select.mSelectRule[4], value1, select.mF);
return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getFloat());
}
else
throw std::runtime_error (

@ -610,8 +610,9 @@ std::string WindowManager::getGameSettingString(const std::string &id, const std
const ESM::GameSetting *setting =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().search(id);
if (setting && setting->mType == ESM::VT_String)
return setting->getString();
if (setting && setting->mValue.getType()==ESM::VT_String)
return setting->mValue.getString();
return default_;
}
@ -792,8 +793,8 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r
const ESM::GameSetting *setting =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(tag);
if (setting && setting->mType == ESM::VT_String)
_result = setting->getString();
if (setting && setting->mValue.getType()==ESM::VT_String)
_result = setting->mValue.getString();
else
_result = tag;
}

@ -47,27 +47,24 @@ namespace MWWorld
char type = ' ';
Data value;
switch (iter->mType)
switch (iter->mValue.getType())
{
case ESM::VT_Short:
type = 's';
value.mShort = *reinterpret_cast<const Interpreter::Type_Float *> (
&iter->mValue);
value.mShort = iter->mValue.getInteger();
break;
case ESM::VT_Int:
case ESM::VT_Long:
type = 'l';
value.mLong = *reinterpret_cast<const Interpreter::Type_Float *> (
&iter->mValue);
value.mLong = iter->mValue.getInteger();
break;
case ESM::VT_Float:
type = 'f';
value.mFloat = *reinterpret_cast<const Interpreter::Type_Float *> (
&iter->mValue);
value.mFloat = iter->mValue.getFloat();
break;
default:

@ -363,10 +363,8 @@ namespace MWWorld
const ESM::GameSetting *setting =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().search("sDefaultCellname");
if (setting && setting->mType == ESM::VT_String)
name = setting->getString();
else
name = "Wilderness";
if (setting && setting->mValue.getType()==ESM::VT_String)
name = setting->mValue.getString();
}
}

@ -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,
VT_Int,
VT_Long,
VT_Float,
VT_String,
VT_Ignored
};
enum Specialization
{
SPC_Combat = 0,

@ -1,57 +1,24 @@
#include "loadglob.hpp"
#include "esmreader.hpp"
#include "esmwriter.hpp"
namespace ESM
{
void Global::load (ESMReader &esm)
{
std::string tmp = esm.getHNString("FNAM");
if (tmp == "s")
mType = VT_Short;
else if (tmp == "l")
mType = VT_Int;
else if (tmp == "f")
mType = VT_Float;
else
esm.fail("Illegal global variable type " + tmp);
// Note: Both floats and longs are represented as floats.
esm.getHNT(mValue, "FLTV");
mValue.read (esm, ESM::Variant::Format_Global);
}
void Global::save (ESMWriter &esm)
{
switch(mType)
{
case VT_Short:
esm.writeHNString("FNAM", "s");
break;
case VT_Int:
esm.writeHNString("FNAM", "l");
break;
case VT_Float:
esm.writeHNString("FNAM", "f");
break;
default:
return;
}
esm.writeHNT("FLTV", mValue);
mValue.write (esm, ESM::Variant::Format_Global);
}
void Global::blank()
{
mValue = 0;
mType = VT_Float;
mValue.setType (ESM::VT_None);
}
bool operator== (const Global& left, const Global& right)
{
return left.mId==right.mId && left.mValue==right.mValue && left.mType==right.mType;
return left.mId==right.mId && left.mValue==right.mValue;
}
}

@ -3,7 +3,7 @@
#include <string>
#include "defs.hpp"
#include "variant.hpp"
namespace ESM
{
@ -18,8 +18,7 @@ class ESMWriter;
struct Global
{
std::string mId;
float mValue;
VarType mType;
Variant mValue;
void load(ESMReader &esm);
void save(ESMWriter &esm);

@ -1,104 +1,39 @@
#include "loadgmst.hpp"
#include <stdexcept>
#include "esmreader.hpp"
#include "esmwriter.hpp"
namespace ESM
{
void GameSetting::load (ESMReader &esm)
{
assert(mId != "");
// We are apparently allowed to be empty
if (!esm.hasMoreSubs())
{
mType = VT_None;
return;
}
// Load some data
esm.getSubName();
NAME n = esm.retSubName();
if (n == "STRV")
{
mStr = esm.getHString();
mType = VT_String;
}
else if (n == "INTV")
{
esm.getHT(mI);
mType = VT_Int;
}
else if (n == "FLTV")
{
esm.getHT(mF);
mType = VT_Float;
}
else
esm.fail("Unwanted subrecord type");
mValue.read (esm, ESM::Variant::Format_Gmst);
}
void GameSetting::save (ESMWriter &esm)
{
switch(mType)
{
case VT_String: esm.writeHNString("STRV", mStr); break;
case VT_Int: esm.writeHNT("INTV", mI); break;
case VT_Float: esm.writeHNT("FLTV", mF); break;
default: break;
}
mValue.write (esm, ESM::Variant::Format_Gmst);
}
int GameSetting::getInt() const
{
switch (mType)
{
case VT_Float: return static_cast<int> (mF);
case VT_Int: return mI;
default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type");
}
return mValue.getInteger();
}
float GameSetting::getFloat() const
{
switch (mType)
{
case VT_Float: return mF;
case VT_Int: return mI;
default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type");
}
return mValue.getFloat();
}
std::string GameSetting::getString() const
{
if (mType==VT_String)
return mStr;
throw std::runtime_error ("GMST " + mId + " is not a string");
return mValue.getString();
}
void GameSetting::blank()
{
mStr.clear();
mI = 0;
mF = 0;
mType = VT_Float;
mValue.setType (ESM::VT_None);
}
bool operator== (const GameSetting& left, const GameSetting& right)
{
if (left.mType!=right.mType)
return false;
switch (left.mType)
{
case VT_Float: return left.mF==right.mF;
case VT_Int: return left.mI==right.mI;
case VT_String: return left.mStr==right.mStr;
default: return false;
}
return left.mValue==right.mValue;
}
}

@ -3,7 +3,7 @@
#include <string>
#include "defs.hpp"
#include "variant.hpp"
namespace ESM
{
@ -19,14 +19,13 @@ class ESMWriter;
struct GameSetting
{
std::string mId;
// One of these is used depending on the variable type
std::string mStr;
int mI;
float mF;
VarType mType;
Variant mValue;
void load(ESMReader &esm);
/// \todo remove the get* functions (redundant, since mValue as equivalent functions now).
int getInt() const;
///< Throws an exception if GMST is not of type int or float.

@ -84,22 +84,8 @@ void DialInfo::load(ESMReader &esm)
SelectStruct ss;
ss.mSelectRule = esm.getHString();
esm.isEmptyOrGetName();
if (subName.val == REC_INTV)
{
ss.mType = VT_Int;
esm.getHT(ss.mI);
}
else if (subName.val == REC_FLTV)
{
ss.mType = VT_Float;
esm.getHT(ss.mF);
}
else
esm.fail(
"INFO.SCVR must precede INTV or FLTV, not "
+ subName.toString());
ss.mValue.read (esm, Variant::Format_Info);
mSelects.push_back(ss);
@ -152,12 +138,7 @@ void DialInfo::save(ESMWriter &esm)
for (std::vector<SelectStruct>::iterator it = mSelects.begin(); it != mSelects.end(); ++it)
{
esm.writeHNString("SCVR", it->mSelectRule);
switch(it->mType)
{
case VT_Int: esm.writeHNT("INTV", it->mI); break;
case VT_Float: esm.writeHNT("FLTV", it->mF); break;
default: break;
}
it->mValue.write (esm, Variant::Format_Info);
}
esm.writeHNOString("BNAM", mResultScript);

@ -5,6 +5,7 @@
#include <vector>
#include "defs.hpp"
#include "variant.hpp"
namespace ESM
{
@ -12,8 +13,6 @@ namespace ESM
class ESMReader;
class ESMWriter;
// NOT DONE
/*
* Dialogue information. A series of these follow after DIAL records,
* and form a linked list of dialogue items.
@ -43,9 +42,7 @@ struct DialInfo
struct SelectStruct
{
std::string mSelectRule; // This has a complicated format
float mF; // Only one of 'f' or 'i' is used
int mI;
VarType mType;
Variant mValue;
};
// Journal quest indices (introduced with the quest system in Tribunal)
@ -93,8 +90,7 @@ struct DialInfo
REC_SNAM = 0x4d414e53,
REC_NAME = 0x454d414e,
REC_SCVR = 0x52564353,
REC_INTV = 0x56544e49,
REC_FLTV = 0x56544c46,
REC_BNAM = 0x4d414e42,
REC_QSTN = 0x4e545351,
REC_QSTF = 0x46545351,
@ -106,42 +102,5 @@ struct DialInfo
void save(ESMWriter &esm);
};
/*
Some old and unused D code and comments, that might be useful later:
--------
// We only need to put each item in ONE list. For if your NPC
// matches this response, then it must match ALL criteria, thus it
// will have to look up itself in all the lists. I think the order
// is well optimized in making the lists as small as possible.
if(this.actor.index != -1) actorDial[this.actor][parent]++;
else if(cell != "") cellDial[cell][parent]++;
else if(this.Class != -1) classDial[this.Class][parent]++;
else if(this.npcFaction != -1)
factionDial[this.npcFaction][parent]++;
else if(this.race != -1) raceDial[this.race][parent]++;
else allDial[parent]++; // Lists dialogues that might
// apply to all npcs.
*/
// List of dialogue topics (and greetings, voices, etc.) that
// reference other objects. Eg. raceDial is indexed by the indices of
// all races referenced. The value of raceDial is a new AA, which is
// basically used as a map (the int value is just a count and isn't
// used for anything important.) The indices (or elements of the map)
// are the dialogues that reference the given race. I use an AA
// instead of a list or array, since each dialogue can be added lots
// of times.
/*
int allDial[Dialogue*];
int classDial[int][Dialogue*];
int factionDial[int][Dialogue*];
int actorDial[Item][Dialogue*];
// If I look up cells on cell load, I don't have to resolve these
// names into anything!
int cellDial[char[]][Dialogue*];
int raceDial[int][Dialogue*];
*/
}
#endif

@ -0,0 +1,282 @@
#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::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 // 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());
}
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");
// 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,86 @@
#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,
Format_Info
};
Variant();
~Variant();
Variant& operator= (const Variant& variant);
Variant (const Variant& variant);
VarType getType() const;
std::string getString() 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,280 @@
#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");
if (format==Variant::Format_Info)
esm.fail ("info 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");
if (format==Variant::Format_Info)
throw std::runtime_error ("info 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 if (format==Variant::Format_Gmst || format==Variant::Format_Info)
{
if (type!=VT_Int)
{
std::ostringstream stream;
stream
<< "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info")
<< " variable integer type";
esm.fail (stream.str());
}
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 if (format==Variant::Format_Gmst || format==Variant::Format_Info)
{
if (type==VT_Int)
{
std::ostringstream stream;
stream
<< "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info")
<< " variable integer type";
throw std::runtime_error (stream.str());
}
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 if (format==Variant::Format_Gmst || format==Variant::Format_Info)
{
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 if (format==Variant::Format_Gmst || format==Variant::Format_Info)
{
esm.writeHNT ("FLTV", 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