mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 10:56:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			281 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "variant.hpp"
 | 
						|
 | 
						|
#include <cassert>
 | 
						|
#include <stdexcept>
 | 
						|
 | 
						|
#include "esmreader.hpp"
 | 
						|
#include "variantimp.hpp"
 | 
						|
 | 
						|
#include "components/esm/defs.hpp"
 | 
						|
 | 
						|
namespace ESM
 | 
						|
{
 | 
						|
    namespace
 | 
						|
    {
 | 
						|
        constexpr uint32_t STRV = fourCC("STRV");
 | 
						|
        constexpr uint32_t INTV = fourCC("INTV");
 | 
						|
        constexpr uint32_t FLTV = fourCC("FLTV");
 | 
						|
        constexpr uint32_t STTV = fourCC("STTV");
 | 
						|
 | 
						|
        template <typename T, bool orDefault = false>
 | 
						|
        struct GetValue
 | 
						|
        {
 | 
						|
            constexpr T operator()(int value) const { return static_cast<T>(value); }
 | 
						|
 | 
						|
            constexpr T operator()(float value) const { return static_cast<T>(value); }
 | 
						|
 | 
						|
            template <typename V>
 | 
						|
            constexpr T operator()(const V&) const
 | 
						|
            {
 | 
						|
                if constexpr (orDefault)
 | 
						|
                    return T{};
 | 
						|
                else
 | 
						|
                    throw std::runtime_error("cannot convert variant");
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        template <typename T>
 | 
						|
        struct SetValue
 | 
						|
        {
 | 
						|
            T mValue;
 | 
						|
 | 
						|
            explicit SetValue(T value)
 | 
						|
                : mValue(value)
 | 
						|
            {
 | 
						|
            }
 | 
						|
 | 
						|
            void operator()(int& value) const { value = static_cast<int>(mValue); }
 | 
						|
 | 
						|
            void operator()(float& value) const { value = static_cast<float>(mValue); }
 | 
						|
 | 
						|
            template <typename V>
 | 
						|
            void operator()(V&) const
 | 
						|
            {
 | 
						|
                throw std::runtime_error("cannot convert variant");
 | 
						|
            }
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    const std::string& Variant::getString() const
 | 
						|
    {
 | 
						|
        return std::get<std::string>(mData);
 | 
						|
    }
 | 
						|
 | 
						|
    int Variant::getInteger() const
 | 
						|
    {
 | 
						|
        return std::visit(GetValue<int>{}, mData);
 | 
						|
    }
 | 
						|
 | 
						|
    float Variant::getFloat() const
 | 
						|
    {
 | 
						|
        return std::visit(GetValue<float>{}, mData);
 | 
						|
    }
 | 
						|
 | 
						|
    void 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);
 | 
						|
 | 
						|
        std::visit(ReadESMVariantValue{ esm, format, mType }, mData);
 | 
						|
    }
 | 
						|
 | 
						|
    void 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
 | 
						|
            std::visit(WriteESMVariantValue{ esm, format, mType }, mData);
 | 
						|
    }
 | 
						|
 | 
						|
    void 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: " << std::get<int>(mData);
 | 
						|
                break;
 | 
						|
 | 
						|
            case VT_Int:
 | 
						|
 | 
						|
                stream << "variant int: " << std::get<int>(mData);
 | 
						|
                break;
 | 
						|
 | 
						|
            case VT_Long:
 | 
						|
 | 
						|
                stream << "variant long: " << std::get<int>(mData);
 | 
						|
                break;
 | 
						|
 | 
						|
            case VT_Float:
 | 
						|
 | 
						|
                stream << "variant float: " << std::get<float>(mData);
 | 
						|
                break;
 | 
						|
 | 
						|
            case VT_String:
 | 
						|
 | 
						|
                stream << "variant string: \"" << std::get<std::string>(mData) << "\"";
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void Variant::setType(VarType type)
 | 
						|
    {
 | 
						|
        if (type != mType)
 | 
						|
        {
 | 
						|
            switch (type)
 | 
						|
            {
 | 
						|
                case VT_Unknown:
 | 
						|
                case VT_None:
 | 
						|
                    mData = std::monostate{};
 | 
						|
                    break;
 | 
						|
 | 
						|
                case VT_Short:
 | 
						|
                case VT_Int:
 | 
						|
                case VT_Long:
 | 
						|
                    mData = std::visit(GetValue<int, true>{}, mData);
 | 
						|
                    break;
 | 
						|
 | 
						|
                case VT_Float:
 | 
						|
                    mData = std::visit(GetValue<float, true>{}, mData);
 | 
						|
                    break;
 | 
						|
 | 
						|
                case VT_String:
 | 
						|
                    mData = std::string{};
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
 | 
						|
            mType = type;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void Variant::setString(const std::string& value)
 | 
						|
    {
 | 
						|
        std::get<std::string>(mData) = value;
 | 
						|
    }
 | 
						|
 | 
						|
    void Variant::setString(std::string&& value)
 | 
						|
    {
 | 
						|
        std::get<std::string>(mData) = std::move(value);
 | 
						|
    }
 | 
						|
 | 
						|
    void Variant::setInteger(int value)
 | 
						|
    {
 | 
						|
        std::visit(SetValue(value), mData);
 | 
						|
    }
 | 
						|
 | 
						|
    void Variant::setFloat(float value)
 | 
						|
    {
 | 
						|
        std::visit(SetValue(value), mData);
 | 
						|
    }
 | 
						|
 | 
						|
    std::ostream& operator<<(std::ostream& stream, const Variant& value)
 | 
						|
    {
 | 
						|
        value.write(stream);
 | 
						|
        return stream;
 | 
						|
    }
 | 
						|
 | 
						|
}
 |