////////////////////////////////////////////////////////////////////// // This file is part of Remere's Map Editor ////////////////////////////////////////////////////////////////////// // Remere's Map Editor is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Remere's Map Editor is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . ////////////////////////////////////////////////////////////////////// #include "main.h" #include "item_attributes.h" #include "filehandle.h" ItemAttributes::ItemAttributes() : attributes(nullptr) { //// } ItemAttributes::ItemAttributes(const ItemAttributes &o) { if (o.attributes) { attributes = newd ItemAttributeMap(*o.attributes); } } ItemAttributes::~ItemAttributes() { clearAllAttributes(); } void ItemAttributes::createAttributes() { if (!attributes) { attributes = newd ItemAttributeMap; } } void ItemAttributes::clearAllAttributes() { if (attributes) { delete attributes; } attributes = nullptr; } ItemAttributeMap ItemAttributes::getAttributes() const { if (attributes) { return *attributes; } return ItemAttributeMap(); } void ItemAttributes::setAttribute(const std::string &key, const ItemAttribute &value) { createAttributes(); (*attributes)[key] = value; } void ItemAttributes::setAttribute(const std::string &key, const std::string &value) { createAttributes(); (*attributes)[key].set(value); } void ItemAttributes::setAttribute(const std::string &key, int32_t value) { createAttributes(); (*attributes)[key].set(value); } void ItemAttributes::setAttribute(const std::string &key, double value) { createAttributes(); (*attributes)[key].set(value); } void ItemAttributes::setAttribute(const std::string &key, bool value) { createAttributes(); (*attributes)[key].set(value); } void ItemAttributes::eraseAttribute(const std::string &key) { if (!attributes) { return; } ItemAttributeMap::iterator iter = attributes->find(key); if (iter != attributes->end()) { attributes->erase(iter); } } const std::string* ItemAttributes::getStringAttribute(const std::string &key) const { if (!attributes) { return nullptr; } ItemAttributeMap::iterator iter = attributes->find(key); if (iter != attributes->end()) { return iter->second.getString(); } return nullptr; } const int32_t* ItemAttributes::getIntegerAttribute(const std::string &key) const { if (!attributes) { return nullptr; } ItemAttributeMap::iterator iter = attributes->find(key); if (iter != attributes->end()) { return iter->second.getInteger(); } return nullptr; } const double* ItemAttributes::getFloatAttribute(const std::string &key) const { if (!attributes) { return nullptr; } ItemAttributeMap::iterator iter = attributes->find(key); if (iter != attributes->end()) { return iter->second.getFloat(); } return nullptr; } const bool* ItemAttributes::getBooleanAttribute(const std::string &key) const { if (!attributes) { return nullptr; } ItemAttributeMap::iterator iter = attributes->find(key); if (iter != attributes->end()) { return iter->second.getBoolean(); } return nullptr; } bool ItemAttributes::hasStringAttribute(const std::string &key) const { return getStringAttribute(key) != nullptr; } bool ItemAttributes::hasIntegerAttribute(const std::string &key) const { return getIntegerAttribute(key) != nullptr; } bool ItemAttributes::hasFloatAttribute(const std::string &key) const { return getFloatAttribute(key) != nullptr; } bool ItemAttributes::hasBooleanAttribute(const std::string &key) const { return getBooleanAttribute(key) != nullptr; } // Attribute type // Can hold either int, bool or std::string // Without using newd to allocate them ItemAttribute::ItemAttribute() : type(ItemAttribute::NONE) { //// } ItemAttribute::ItemAttribute(const std::string &str) : type(ItemAttribute::STRING) { new (data) std::string(str); } ItemAttribute::ItemAttribute(int32_t i) : type(ItemAttribute::INTEGER) { *reinterpret_cast(data) = i; } ItemAttribute::ItemAttribute(double f) : type(ItemAttribute::DOUBLE) { *reinterpret_cast(data) = f; } ItemAttribute::ItemAttribute(bool b) { *reinterpret_cast(data) = b; } ItemAttribute::ItemAttribute(const ItemAttribute &o) : type(ItemAttribute::NONE) { *this = o; } ItemAttribute &ItemAttribute::operator=(const ItemAttribute &o) { if (&o == this) { return *this; } clear(); type = o.type; if (type == STRING) { new (data) std::string(*reinterpret_cast(&o.data)); } else if (type == INTEGER) { *reinterpret_cast(data) = *reinterpret_cast(&o.data); } else if (type == FLOAT) { *reinterpret_cast(data) = *reinterpret_cast(&o.data); } else if (type == DOUBLE) { *reinterpret_cast(data) = *reinterpret_cast(&o.data); } else if (type == BOOLEAN) { *reinterpret_cast(data) = *reinterpret_cast(&o.data); } else { type = NONE; } return *this; } ItemAttribute::~ItemAttribute() { clear(); } void ItemAttribute::clear() { if (type == STRING) { (reinterpret_cast(&data))->~basic_string(); type = NONE; } } void ItemAttribute::set(const std::string &str) { clear(); type = STRING; new (data) std::string(str); } void ItemAttribute::set(int32_t i) { clear(); type = INTEGER; *reinterpret_cast(&data) = i; } void ItemAttribute::set(double y) { clear(); type = DOUBLE; *reinterpret_cast(&data) = y; } void ItemAttribute::set(bool b) { clear(); type = BOOLEAN; *reinterpret_cast(&data) = b; } const std::string* ItemAttribute::getString() const { if (type == STRING) { return reinterpret_cast(&data); } return nullptr; } const int32_t* ItemAttribute::getInteger() const { if (type == INTEGER) { return reinterpret_cast(&data); } return nullptr; } const double* ItemAttribute::getFloat() const { if (type == DOUBLE) { return reinterpret_cast(&data); } return nullptr; } const bool* ItemAttribute::getBoolean() const { if (type == BOOLEAN) { return reinterpret_cast(&data); } return nullptr; } bool ItemAttributes::unserializeAttributeMap(const IOMap &maphandle, BinaryNode* stream) { uint16_t n; if (stream->getU16(n)) { createAttributes(); std::string key; ItemAttribute attrib; while (n--) { if (!stream->getString(key)) { return false; } if (!attrib.unserialize(maphandle, stream)) { return false; } (*attributes)[key] = attrib; } } return true; } void ItemAttributes::serializeAttributeMap(const IOMap &maphandle, NodeFileWriteHandle &f) const { // Maximum of 65535 attributes per item f.addU16(std::min((size_t)0xFFFF, attributes->size())); ItemAttributeMap::const_iterator attribute = attributes->begin(); int i = 0; while (attribute != attributes->end() && i <= 0xFFFF) { const std::string &key = attribute->first; if (key.size() > 0xFFFF) { f.addString(key.substr(0, 65535)); } else { f.addString(key); } attribute->second.serialize(maphandle, f); ++attribute, ++i; } } bool ItemAttribute::unserialize(const IOMap &maphandle, BinaryNode* stream) { // Read type uint8_t rtype; stream->getU8(rtype); // Read contents switch (rtype) { case STRING: { std::string str; if (!stream->getLongString(str)) { return false; } set(str); break; } case INTEGER: { uint32_t u32; if (!stream->getU32(u32)) { return false; } set(*reinterpret_cast(&u32)); break; } case FLOAT: { uint32_t u32; if (!stream->getU32(u32)) { return false; } set((double)*reinterpret_cast(&u32)); break; } case DOUBLE: { uint64_t u64; if (!stream->getU64(u64)) { return false; } set(*reinterpret_cast(&u64)); break; } case BOOLEAN: { uint8_t b; if (!stream->getU8(b)) { return false; } set(b != 0); } default: break; } return true; } void ItemAttribute::serialize(const IOMap &maphandle, NodeFileWriteHandle &f) const { // Write type f.addU8((uint8_t)(type)); // Write contents switch (type) { case STRING: f.addLongString(*getString()); break; case INTEGER: f.addU32(*(uint32_t*)getInteger()); break; case DOUBLE: f.addU64(*(uint64_t*)getFloat()); break; case BOOLEAN: f.addU8(*(uint8_t*)getBoolean()); default: break; } }