haiku/src/kits/shared/Variant.cpp

686 lines
12 KiB
C++

/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2011, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include <Variant.h>
#include <stdlib.h>
#include <string.h>
#include <ByteOrder.h>
#include <Message.h>
template<typename NumberType>
inline NumberType
BVariant::_ToNumber() const
{
switch (fType) {
case B_BOOL_TYPE:
return fBool ? 1 : 0;
case B_INT8_TYPE:
return (NumberType)fInt8;
case B_UINT8_TYPE:
return (NumberType)fUInt8;
case B_INT16_TYPE:
return (NumberType)fInt16;
case B_UINT16_TYPE:
return (NumberType)fUInt16;
case B_INT32_TYPE:
return (NumberType)fInt32;
case B_UINT32_TYPE:
return (NumberType)fUInt32;
case B_INT64_TYPE:
return (NumberType)fInt64;
case B_UINT64_TYPE:
return (NumberType)fUInt64;
case B_FLOAT_TYPE:
return (NumberType)fFloat;
case B_DOUBLE_TYPE:
return (NumberType)fDouble;
default:
return 0;
}
}
BVariant::~BVariant()
{
Unset();
}
status_t
BVariant::SetToTypedData(const void* data, type_code type)
{
Unset();
switch (type) {
case B_BOOL_TYPE:
fBool = *(bool*)data;
break;
case B_INT8_TYPE:
fInt8 = *(int8*)data;
break;
case B_UINT8_TYPE:
fUInt8 = *(uint8*)data;
break;
case B_INT16_TYPE:
fInt16 = *(int16*)data;
break;
case B_UINT16_TYPE:
fUInt16 = *(uint16*)data;
break;
case B_INT32_TYPE:
fInt32 = *(int32*)data;
break;
case B_UINT32_TYPE:
fUInt32 = *(uint32*)data;
break;
case B_INT64_TYPE:
fInt64 = *(int64*)data;
break;
case B_UINT64_TYPE:
fUInt64 = *(uint64*)data;
break;
case B_FLOAT_TYPE:
fFloat = *(float*)data;
break;
case B_DOUBLE_TYPE:
fDouble = *(double*)data;
break;
case B_POINTER_TYPE:
fPointer = *(void**)data;
break;
case B_STRING_TYPE:
return _SetTo((const char*)data, 0) ? B_OK : B_NO_MEMORY;
case B_RECT_TYPE:
{
BRect *rect = (BRect *)data;
_SetTo(rect->left, rect->top, rect->right, rect->bottom);
break;
}
default:
return B_BAD_TYPE;
}
fType = type;
return B_OK;
}
void
BVariant::Unset()
{
if ((fFlags & B_VARIANT_OWNS_DATA) != 0) {
switch (fType) {
case B_STRING_TYPE:
free(fString);
break;
default:
break;
}
} else if ((fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0) {
if (fReferenceable != NULL)
fReferenceable->ReleaseReference();
}
fType = 0;
fFlags = 0;
}
bool
BVariant::operator==(const BVariant& other) const
{
if (fType == 0)
return other.fType == 0;
if (other.fType == 0)
return false;
// TODO: The number comparisons are not really accurate. Particularly a
// conversion between signed and unsigned integers might actually change the
// value.
switch (fType) {
case B_BOOL_TYPE:
return fBool == other.ToBool();
case B_INT8_TYPE:
case B_INT16_TYPE:
case B_INT32_TYPE:
case B_INT64_TYPE:
if (!other.IsNumber())
return false;
return ToInt64() == other.ToInt64();
case B_UINT8_TYPE:
case B_UINT16_TYPE:
case B_UINT32_TYPE:
case B_UINT64_TYPE:
if (!other.IsNumber())
return false;
return ToUInt64() == other.ToUInt64();
case B_FLOAT_TYPE:
case B_DOUBLE_TYPE:
if (!other.IsNumber())
return false;
return ToDouble() == other.ToDouble();
case B_POINTER_TYPE:
return other.fType == B_POINTER_TYPE
&& fPointer == other.fPointer;
case B_STRING_TYPE:
if (other.fType != B_STRING_TYPE)
return false;
if (fString == NULL || other.fString == NULL)
return fString == other.fString;
return strcmp(fString, other.fString) == 0;
case B_RECT_TYPE:
return BRect(fRect.left, fRect.top, fRect.right, fRect.bottom)
== BRect(other.fRect.left, other.fRect.top, other.fRect.right,
other.fRect.bottom);
default:
return false;
}
}
size_t
BVariant::Size() const
{
if (fType == B_STRING_TYPE)
return fString != NULL ? strlen(fString) + 1 : 0;
if ((fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0)
return sizeof(this->fReferenceable);
return SizeOfType(fType);
}
const uint8*
BVariant::Bytes() const
{
if (fType == B_STRING_TYPE)
return (const uint8*)fString;
return fBytes;
}
bool
BVariant::ToBool() const
{
switch (fType) {
case B_BOOL_TYPE:
return fBool;
case B_INT8_TYPE:
return fInt8 != 0;
case B_UINT8_TYPE:
return fUInt8 != 0;
case B_INT16_TYPE:
return fInt16 != 0;
case B_UINT16_TYPE:
return fUInt16 != 0;
case B_INT32_TYPE:
return fInt32 != 0;
case B_UINT32_TYPE:
return fUInt32 != 0;
case B_INT64_TYPE:
return fInt64 != 0;
case B_UINT64_TYPE:
return fUInt64 != 0;
case B_FLOAT_TYPE:
return fFloat != 0;
case B_DOUBLE_TYPE:
return fDouble != 0;
case B_POINTER_TYPE:
return fPointer != NULL;
case B_STRING_TYPE:
return fString != NULL;
// TODO: We should probably check for actual values like "true",
// "false", "on", "off", etc.
default:
return false;
}
}
int8
BVariant::ToInt8() const
{
return _ToNumber<int8>();
}
uint8
BVariant::ToUInt8() const
{
return _ToNumber<uint8>();
}
int16
BVariant::ToInt16() const
{
return _ToNumber<int16>();
}
uint16
BVariant::ToUInt16() const
{
return _ToNumber<uint16>();
}
int32
BVariant::ToInt32() const
{
return _ToNumber<int32>();
}
uint32
BVariant::ToUInt32() const
{
return _ToNumber<uint32>();
}
int64
BVariant::ToInt64() const
{
return _ToNumber<int64>();
}
uint64
BVariant::ToUInt64() const
{
return _ToNumber<uint64>();
}
float
BVariant::ToFloat() const
{
return _ToNumber<float>();
}
double
BVariant::ToDouble() const
{
return _ToNumber<double>();
}
BRect
BVariant::ToRect() const
{
return BRect(fRect.left, fRect.top, fRect.right, fRect.bottom);
}
void*
BVariant::ToPointer() const
{
return fType == B_POINTER_TYPE ? fString : NULL;
}
const char*
BVariant::ToString() const
{
return fType == B_STRING_TYPE ? fString : NULL;
}
void
BVariant::_SetTo(const BVariant& other)
{
if ((other.fFlags & B_VARIANT_OWNS_DATA) != 0) {
switch (other.fType) {
case B_STRING_TYPE:
fType = B_STRING_TYPE;
fString = strdup(other.fString);
fFlags = B_VARIANT_OWNS_DATA;
return;
default:
break;
}
} else if ((other.fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0) {
if (other.fReferenceable != NULL)
other.fReferenceable->AcquireReference();
}
memcpy((void*)this, (void*)&other, sizeof(BVariant));
}
BReferenceable*
BVariant::ToReferenceable() const
{
return (fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0
? fReferenceable : NULL;
}
void
BVariant::SwapEndianess()
{
if (!IsNumber() || fType == B_POINTER_TYPE)
return;
swap_data(fType, fBytes, Size(), B_SWAP_ALWAYS);
}
status_t
BVariant::AddToMessage(BMessage& message, const char* fieldName) const
{
switch (fType) {
case B_BOOL_TYPE:
return message.AddBool(fieldName, fBool);
case B_INT8_TYPE:
return message.AddInt8(fieldName, fInt8);
case B_UINT8_TYPE:
return message.AddUInt8(fieldName, fUInt8);
case B_INT16_TYPE:
return message.AddInt16(fieldName, fInt16);
case B_UINT16_TYPE:
return message.AddUInt16(fieldName, fUInt16);
case B_INT32_TYPE:
return message.AddInt32(fieldName, fInt32);
case B_UINT32_TYPE:
return message.AddUInt32(fieldName, fUInt32);
case B_INT64_TYPE:
return message.AddInt64(fieldName, fInt64);
case B_UINT64_TYPE:
return message.AddUInt64(fieldName, fUInt64);
case B_FLOAT_TYPE:
return message.AddFloat(fieldName, fFloat);
case B_DOUBLE_TYPE:
return message.AddDouble(fieldName, fDouble);
case B_POINTER_TYPE:
return message.AddPointer(fieldName, fPointer);
case B_STRING_TYPE:
return message.AddString(fieldName, fString);
case B_RECT_TYPE:
return message.AddRect(fieldName, BRect(fRect.left, fRect.top,
fRect.right, fRect.bottom));
default:
return B_UNSUPPORTED;
}
}
status_t
BVariant::SetFromMessage(const BMessage& message, const char* fieldName)
{
// get the message field info
type_code type;
int32 count;
status_t error = message.GetInfo(fieldName, &type, &count);
if (error != B_OK)
return error;
// get the data
const void* data;
ssize_t numBytes;
error = message.FindData(fieldName, type, &data, &numBytes);
if (error != B_OK)
return error;
// init the object
return SetToTypedData(data, type);
}
/*static*/ size_t
BVariant::SizeOfType(type_code type)
{
switch (type) {
case B_BOOL_TYPE:
return 1;
case B_INT8_TYPE:
return 1;
case B_UINT8_TYPE:
return 1;
case B_INT16_TYPE:
return 2;
case B_UINT16_TYPE:
return 2;
case B_INT32_TYPE:
return 4;
case B_UINT32_TYPE:
return 4;
case B_INT64_TYPE:
return 8;
case B_UINT64_TYPE:
return 8;
case B_FLOAT_TYPE:
return sizeof(float);
case B_DOUBLE_TYPE:
return sizeof(double);
case B_POINTER_TYPE:
return sizeof(void*);
case B_RECT_TYPE:
return sizeof(BRect);
default:
return 0;
}
}
/*static*/ bool
BVariant::TypeIsNumber(type_code type)
{
switch (type) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
case B_INT16_TYPE:
case B_UINT16_TYPE:
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_FLOAT_TYPE:
case B_DOUBLE_TYPE:
return true;
default:
return false;
}
}
/*static*/ bool
BVariant::TypeIsInteger(type_code type, bool* _isSigned)
{
switch (type) {
case B_INT8_TYPE:
case B_INT16_TYPE:
case B_INT32_TYPE:
case B_INT64_TYPE:
if (_isSigned != NULL)
*_isSigned = true;
return true;
case B_UINT8_TYPE:
case B_UINT16_TYPE:
case B_UINT32_TYPE:
case B_UINT64_TYPE:
if (_isSigned != NULL)
*_isSigned = false;
return true;
default:
return false;
}
}
/*static*/ bool
BVariant::TypeIsFloat(type_code type)
{
switch (type) {
case B_FLOAT_TYPE:
case B_DOUBLE_TYPE:
return true;
default:
return false;
}
}
void
BVariant::_SetTo(bool value)
{
fType = B_BOOL_TYPE;
fFlags = 0;
fBool = value;
}
void
BVariant::_SetTo(int8 value)
{
fType = B_INT8_TYPE;
fFlags = 0;
fInt8 = value;
}
void
BVariant::_SetTo(uint8 value)
{
fType = B_UINT8_TYPE;
fFlags = 0;
fUInt8 = value;
}
void
BVariant::_SetTo(int16 value)
{
fType = B_INT16_TYPE;
fFlags = 0;
fInt16 = value;
}
void
BVariant::_SetTo(uint16 value)
{
fType = B_UINT16_TYPE;
fFlags = 0;
fUInt16 = value;
}
void
BVariant::_SetTo(int32 value)
{
fType = B_INT32_TYPE;
fFlags = 0;
fInt32 = value;
}
void
BVariant::_SetTo(uint32 value)
{
fType = B_UINT32_TYPE;
fFlags = 0;
fUInt32 = value;
}
void
BVariant::_SetTo(int64 value)
{
fType = B_INT64_TYPE;
fFlags = 0;
fInt64 = value;
}
void
BVariant::_SetTo(uint64 value)
{
fType = B_UINT64_TYPE;
fFlags = 0;
fUInt64 = value;
}
void
BVariant::_SetTo(float value)
{
fType = B_FLOAT_TYPE;
fFlags = 0;
fFloat = value;
}
void
BVariant::_SetTo(double value)
{
fType = B_DOUBLE_TYPE;
fFlags = 0;
fDouble = value;
}
void
BVariant::_SetTo(float left, float top, float right, float bottom)
{
fType = B_RECT_TYPE;
fFlags = 0;
fRect.left = left;
fRect.top = top;
fRect.right = right;
fRect.bottom = bottom;
}
void
BVariant::_SetTo(const void* value)
{
fType = B_POINTER_TYPE;
fFlags = 0;
fPointer = (void*)value;
}
bool
BVariant::_SetTo(const char* value, uint32 flags)
{
fType = B_STRING_TYPE;
fFlags = 0;
if (value != NULL) {
if ((flags & B_VARIANT_DONT_COPY_DATA) == 0) {
fString = strdup(value);
fFlags |= B_VARIANT_OWNS_DATA;
if (fString == NULL)
return false;
} else {
fString = (char*)value;
fFlags |= flags & B_VARIANT_OWNS_DATA;
}
} else
fString = NULL;
return true;
}
void
BVariant::_SetTo(BReferenceable* value, type_code type)
{
fType = type;
fFlags = B_VARIANT_REFERENCEABLE_DATA;
fReferenceable = value;
if (fReferenceable != NULL)
fReferenceable->AcquireReference();
}