// // Copyright (c) 2008-2017 the Urho3D project. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #include "../Precompiled.h" #include "../Core/StringUtils.h" #include "../IO/VectorBuffer.h" #include namespace Atomic { const Variant Variant::EMPTY; const PODVector Variant::emptyBuffer; const ResourceRef Variant::emptyResourceRef; const ResourceRefList Variant::emptyResourceRefList; const VariantMap Variant::emptyVariantMap; const VariantVector Variant::emptyVariantVector; const StringVector Variant::emptyStringVector; static const char* typeNames[] = { "None", "Int", "Bool", "Float", "Vector2", "Vector3", "Vector4", "Quaternion", "Color", "String", "Buffer", "VoidPtr", "ResourceRef", "ResourceRefList", "VariantVector", "VariantMap", "IntRect", "IntVector2", "Ptr", "Matrix3", "Matrix3x4", "Matrix4", "Double", "StringVector", "Rect", "IntVector3", "Int64", 0 }; Variant& Variant::operator =(const Variant& rhs) { SetType(rhs.GetType()); switch (type_) { case VAR_STRING: *(reinterpret_cast(&value_)) = *(reinterpret_cast(&rhs.value_)); break; case VAR_BUFFER: *(reinterpret_cast*>(&value_)) = *(reinterpret_cast*>(&rhs.value_)); break; case VAR_RESOURCEREF: *(reinterpret_cast(&value_)) = *(reinterpret_cast(&rhs.value_)); break; case VAR_RESOURCEREFLIST: *(reinterpret_cast(&value_)) = *(reinterpret_cast(&rhs.value_)); break; case VAR_VARIANTVECTOR: *(reinterpret_cast(&value_)) = *(reinterpret_cast(&rhs.value_)); break; case VAR_STRINGVECTOR: *(reinterpret_cast(&value_)) = *(reinterpret_cast(&rhs.value_)); break; case VAR_VARIANTMAP: *(reinterpret_cast(&value_)) = *(reinterpret_cast(&rhs.value_)); break; case VAR_PTR: *(reinterpret_cast*>(&value_)) = *(reinterpret_cast*>(&rhs.value_)); break; case VAR_MATRIX3: *(reinterpret_cast(value_.ptr_)) = *(reinterpret_cast(rhs.value_.ptr_)); break; case VAR_MATRIX3X4: *(reinterpret_cast(value_.ptr_)) = *(reinterpret_cast(rhs.value_.ptr_)); break; case VAR_MATRIX4: *(reinterpret_cast(value_.ptr_)) = *(reinterpret_cast(rhs.value_.ptr_)); break; default: value_ = rhs.value_; break; } return *this; } Variant& Variant::operator =(const VectorBuffer& rhs) { SetType(VAR_BUFFER); *(reinterpret_cast*>(&value_)) = rhs.GetBuffer(); return *this; } bool Variant::operator ==(const Variant& rhs) const { if (type_ == VAR_VOIDPTR || type_ == VAR_PTR) return GetVoidPtr() == rhs.GetVoidPtr(); else if (type_ != rhs.type_) return false; switch (type_) { case VAR_INT: return value_.int_ == rhs.value_.int_; case VAR_INT64: return *reinterpret_cast(&value_.int_) == *reinterpret_cast(&rhs.value_.int_); case VAR_BOOL: return value_.bool_ == rhs.value_.bool_; case VAR_FLOAT: return value_.float_ == rhs.value_.float_; case VAR_VECTOR2: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_VECTOR3: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_VECTOR4: case VAR_QUATERNION: case VAR_COLOR: // Hack: use the Vector4 compare for all these classes, as they have the same memory structure return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_STRING: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_BUFFER: return *(reinterpret_cast*>(&value_)) == *(reinterpret_cast*>(&rhs.value_)); case VAR_RESOURCEREF: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_RESOURCEREFLIST: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_VARIANTVECTOR: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_STRINGVECTOR: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_VARIANTMAP: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_INTRECT: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_INTVECTOR2: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_INTVECTOR3: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_MATRIX3: return *(reinterpret_cast(value_.ptr_)) == *(reinterpret_cast(rhs.value_.ptr_)); case VAR_MATRIX3X4: return *(reinterpret_cast(value_.ptr_)) == *(reinterpret_cast(rhs.value_.ptr_)); case VAR_MATRIX4: return *(reinterpret_cast(value_.ptr_)) == *(reinterpret_cast(rhs.value_.ptr_)); case VAR_DOUBLE: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); case VAR_RECT: return *(reinterpret_cast(&value_)) == *(reinterpret_cast(&rhs.value_)); default: return true; } } bool Variant::operator ==(const PODVector& rhs) const { // Use strncmp() instead of PODVector::operator ==() const PODVector& buffer = *(reinterpret_cast*>(&value_)); return type_ == VAR_BUFFER && buffer.Size() == rhs.Size() ? strncmp(reinterpret_cast(&buffer[0]), reinterpret_cast(&rhs[0]), buffer.Size()) == 0 : false; } bool Variant::operator ==(const VectorBuffer& rhs) const { const PODVector& buffer = *(reinterpret_cast*>(&value_)); return type_ == VAR_BUFFER && buffer.Size() == rhs.GetSize() ? strncmp(reinterpret_cast(&buffer[0]), reinterpret_cast(rhs.GetData()), buffer.Size()) == 0 : false; } void Variant::FromString(const String& type, const String& value) { return FromString(GetTypeFromName(type), value.CString()); } void Variant::FromString(const char* type, const char* value) { return FromString(GetTypeFromName(type), value); } void Variant::FromString(VariantType type, const String& value) { return FromString(type, value.CString()); } void Variant::FromString(VariantType type, const char* value) { switch (type) { case VAR_INT: *this = ToInt(value); break; case VAR_INT64: *this = ToInt64(value); break; case VAR_BOOL: *this = ToBool(value); break; case VAR_FLOAT: *this = ToFloat(value); break; case VAR_VECTOR2: *this = ToVector2(value); break; case VAR_VECTOR3: *this = ToVector3(value); break; case VAR_VECTOR4: *this = ToVector4(value); break; case VAR_QUATERNION: *this = ToQuaternion(value); break; case VAR_COLOR: *this = ToColor(value); break; case VAR_STRING: *this = value; break; case VAR_BUFFER: { SetType(VAR_BUFFER); PODVector& buffer = *(reinterpret_cast*>(&value_)); StringToBuffer(buffer, value); } break; case VAR_VOIDPTR: // From string to void pointer not supported, set to null *this = (void*)0; break; case VAR_RESOURCEREF: { StringVector values = String::Split(value, ';'); if (values.Size() == 2) { SetType(VAR_RESOURCEREF); ResourceRef& ref = *(reinterpret_cast(&value_)); ref.type_ = values[0]; ref.name_ = values[1]; } } break; case VAR_RESOURCEREFLIST: { StringVector values = String::Split(value, ';', true); if (values.Size() >= 1) { SetType(VAR_RESOURCEREFLIST); ResourceRefList& refList = *(reinterpret_cast(&value_)); refList.type_ = values[0]; refList.names_.Resize(values.Size() - 1); for (unsigned i = 1; i < values.Size(); ++i) refList.names_[i - 1] = values[i]; } } break; case VAR_INTRECT: *this = ToIntRect(value); break; case VAR_INTVECTOR2: *this = ToIntVector2(value); break; case VAR_INTVECTOR3: *this = ToIntVector3(value); break; case VAR_PTR: // From string to RefCounted pointer not supported, set to null *this = (RefCounted*)0; break; case VAR_MATRIX3: *this = ToMatrix3(value); break; case VAR_MATRIX3X4: *this = ToMatrix3x4(value); break; case VAR_MATRIX4: *this = ToMatrix4(value); break; case VAR_DOUBLE: *this = ToDouble(value); break; case VAR_RECT: *this = ToRect(value); break; default: SetType(VAR_NONE); } } void Variant::SetBuffer(const void* data, unsigned size) { if (size && !data) size = 0; SetType(VAR_BUFFER); PODVector& buffer = *(reinterpret_cast*>(&value_)); buffer.Resize(size); if (size) memcpy(&buffer[0], data, size); } VectorBuffer Variant::GetVectorBuffer() const { return VectorBuffer(type_ == VAR_BUFFER ? *reinterpret_cast*>(&value_) : emptyBuffer); } String Variant::GetTypeName() const { return typeNames[type_]; } String Variant::ToString() const { switch (type_) { case VAR_INT: return String(value_.int_); case VAR_INT64: return String(*reinterpret_cast(&value_.int_)); case VAR_BOOL: return String(value_.bool_); case VAR_FLOAT: return String(value_.float_); case VAR_VECTOR2: return (reinterpret_cast(&value_))->ToString(); case VAR_VECTOR3: return (reinterpret_cast(&value_))->ToString(); case VAR_VECTOR4: return (reinterpret_cast(&value_))->ToString(); case VAR_QUATERNION: return (reinterpret_cast(&value_))->ToString(); case VAR_COLOR: return (reinterpret_cast(&value_))->ToString(); case VAR_STRING: return *(reinterpret_cast(&value_)); case VAR_BUFFER: { const PODVector& buffer = *(reinterpret_cast*>(&value_)); String ret; BufferToString(ret, buffer.Begin().ptr_, buffer.Size()); return ret; } case VAR_VOIDPTR: case VAR_PTR: // Pointer serialization not supported (convert to null) return String(0); case VAR_INTRECT: return (reinterpret_cast(&value_))->ToString(); case VAR_INTVECTOR2: return (reinterpret_cast(&value_))->ToString(); case VAR_INTVECTOR3: return (reinterpret_cast(&value_))->ToString(); case VAR_MATRIX3: return (reinterpret_cast(value_.ptr_))->ToString(); case VAR_MATRIX3X4: return (reinterpret_cast(value_.ptr_))->ToString(); case VAR_MATRIX4: return (reinterpret_cast(value_.ptr_))->ToString(); case VAR_DOUBLE: return String(*reinterpret_cast(&value_)); case VAR_RECT: return (reinterpret_cast(&value_))->ToString(); default: // VAR_RESOURCEREF, VAR_RESOURCEREFLIST, VAR_VARIANTVECTOR, VAR_STRINGVECTOR, VAR_VARIANTMAP // Reference string serialization requires typehash-to-name mapping from the context. Can not support here // Also variant map or vector string serialization is not supported. XML or binary save should be used instead return String::EMPTY; } } bool Variant::IsZero() const { switch (type_) { case VAR_INT: return value_.int_ == 0; case VAR_INT64: return *reinterpret_cast(&value_.int_) == 0; case VAR_BOOL: return value_.bool_ == false; case VAR_FLOAT: return value_.float_ == 0.0f; case VAR_VECTOR2: return *reinterpret_cast(&value_) == Vector2::ZERO; case VAR_VECTOR3: return *reinterpret_cast(&value_) == Vector3::ZERO; case VAR_VECTOR4: return *reinterpret_cast(&value_) == Vector4::ZERO; case VAR_QUATERNION: return *reinterpret_cast(&value_) == Quaternion::IDENTITY; case VAR_COLOR: // WHITE is considered empty (i.e. default) color in the Color class definition return *reinterpret_cast(&value_) == Color::WHITE; case VAR_STRING: return reinterpret_cast(&value_)->Empty(); case VAR_BUFFER: return reinterpret_cast*>(&value_)->Empty(); case VAR_VOIDPTR: return value_.ptr_ == 0; case VAR_RESOURCEREF: return reinterpret_cast(&value_)->name_.Empty(); case VAR_RESOURCEREFLIST: { const StringVector& names = reinterpret_cast(&value_)->names_; for (StringVector::ConstIterator i = names.Begin(); i != names.End(); ++i) { if (!i->Empty()) return false; } return true; } case VAR_VARIANTVECTOR: return reinterpret_cast(&value_)->Empty(); case VAR_STRINGVECTOR: return reinterpret_cast(&value_)->Empty(); case VAR_VARIANTMAP: return reinterpret_cast(&value_)->Empty(); case VAR_INTRECT: return *reinterpret_cast(&value_) == IntRect::ZERO; case VAR_INTVECTOR2: return *reinterpret_cast(&value_) == IntVector2::ZERO; case VAR_INTVECTOR3: return *reinterpret_cast(&value_) == IntVector3::ZERO; case VAR_PTR: return *reinterpret_cast*>(&value_) == (RefCounted*)0; case VAR_MATRIX3: return *reinterpret_cast(value_.ptr_) == Matrix3::IDENTITY; case VAR_MATRIX3X4: return *reinterpret_cast(value_.ptr_) == Matrix3x4::IDENTITY; case VAR_MATRIX4: return *reinterpret_cast(value_.ptr_) == Matrix4::IDENTITY; case VAR_DOUBLE: return *reinterpret_cast(&value_) == 0.0; case VAR_RECT: return *reinterpret_cast(&value_) == Rect::ZERO; default: return true; } } void Variant::SetType(VariantType newType) { if (type_ == newType) return; switch (type_) { case VAR_STRING: (reinterpret_cast(&value_))->~String(); break; case VAR_BUFFER: (reinterpret_cast*>(&value_))->~PODVector(); break; case VAR_RESOURCEREF: (reinterpret_cast(&value_))->~ResourceRef(); break; case VAR_RESOURCEREFLIST: (reinterpret_cast(&value_))->~ResourceRefList(); break; case VAR_VARIANTVECTOR: (reinterpret_cast(&value_))->~VariantVector(); break; case VAR_STRINGVECTOR: (reinterpret_cast(&value_))->~StringVector(); break; case VAR_VARIANTMAP: (reinterpret_cast(&value_))->~VariantMap(); break; case VAR_PTR: (reinterpret_cast*>(&value_))->~WeakPtr(); break; case VAR_MATRIX3: delete reinterpret_cast(value_.ptr_); break; case VAR_MATRIX3X4: delete reinterpret_cast(value_.ptr_); break; case VAR_MATRIX4: delete reinterpret_cast(value_.ptr_); break; default: break; } type_ = newType; switch (type_) { case VAR_STRING: new(reinterpret_cast(&value_)) String(); break; case VAR_BUFFER: new(reinterpret_cast*>(&value_)) PODVector(); break; case VAR_RESOURCEREF: new(reinterpret_cast(&value_)) ResourceRef(); break; case VAR_RESOURCEREFLIST: new(reinterpret_cast(&value_)) ResourceRefList(); break; case VAR_VARIANTVECTOR: new(reinterpret_cast(&value_)) VariantVector(); break; case VAR_STRINGVECTOR: new(reinterpret_cast(&value_)) StringVector(); break; case VAR_VARIANTMAP: new(reinterpret_cast(&value_)) VariantMap(); break; case VAR_PTR: new(reinterpret_cast*>(&value_)) WeakPtr(); break; case VAR_MATRIX3: value_.ptr_ = new Matrix3(); break; case VAR_MATRIX3X4: value_.ptr_ = new Matrix3x4(); break; case VAR_MATRIX4: value_.ptr_ = new Matrix4(); break; default: break; } } template <> int Variant::Get() const { return GetInt(); } template <> unsigned Variant::Get() const { return GetUInt(); } template <> long long Variant::Get() const { return GetInt64(); } template <> unsigned long long Variant::Get() const { return GetUInt64(); } template <> StringHash Variant::Get() const { return GetStringHash(); } template <> bool Variant::Get() const { return GetBool(); } template <> float Variant::Get() const { return GetFloat(); } template <> double Variant::Get() const { return GetDouble(); } template <> const Vector2& Variant::Get() const { return GetVector2(); } template <> const Vector3& Variant::Get() const { return GetVector3(); } template <> const Vector4& Variant::Get() const { return GetVector4(); } template <> const Quaternion& Variant::Get() const { return GetQuaternion(); } template <> const Color& Variant::Get() const { return GetColor(); } template <> const String& Variant::Get() const { return GetString(); } template <> const Rect& Variant::Get() const { return GetRect(); } template <> const IntRect& Variant::Get() const { return GetIntRect(); } template <> const IntVector2& Variant::Get() const { return GetIntVector2(); } template <> const IntVector3& Variant::Get() const { return GetIntVector3(); } template <> const PODVector& Variant::Get&>() const { return GetBuffer(); } template <> void* Variant::Get() const { return GetVoidPtr(); } template <> RefCounted* Variant::Get() const { return GetPtr(); } template <> const Matrix3& Variant::Get() const { return GetMatrix3(); } template <> const Matrix3x4& Variant::Get() const { return GetMatrix3x4(); } template <> const Matrix4& Variant::Get() const { return GetMatrix4(); } template <> ResourceRef Variant::Get() const { return GetResourceRef(); } template <> ResourceRefList Variant::Get() const { return GetResourceRefList(); } template <> VariantVector Variant::Get() const { return GetVariantVector(); } template <> StringVector Variant::Get() const { return GetStringVector(); } template <> VariantMap Variant::Get() const { return GetVariantMap(); } template <> Vector2 Variant::Get() const { return GetVector2(); } template <> Vector3 Variant::Get() const { return GetVector3(); } template <> Vector4 Variant::Get() const { return GetVector4(); } template <> Quaternion Variant::Get() const { return GetQuaternion(); } template <> Color Variant::Get() const { return GetColor(); } template <> String Variant::Get() const { return GetString(); } template <> Rect Variant::Get() const { return GetRect(); } template <> IntRect Variant::Get() const { return GetIntRect(); } template <> IntVector2 Variant::Get() const { return GetIntVector2(); } template <> IntVector3 Variant::Get() const { return GetIntVector3(); } template <> PODVector Variant::Get >() const { return GetBuffer(); } template <> Matrix3 Variant::Get() const { return GetMatrix3(); } template <> Matrix3x4 Variant::Get() const { return GetMatrix3x4(); } template <> Matrix4 Variant::Get() const { return GetMatrix4(); } String Variant::GetTypeName(VariantType type) { return typeNames[type]; } VariantType Variant::GetTypeFromName(const String& typeName) { return GetTypeFromName(typeName.CString()); } VariantType Variant::GetTypeFromName(const char* typeName) { return (VariantType)GetStringListIndex(typeName, typeNames, VAR_NONE); } }