1705656eac
A lot of these classes are not *technically* "trivially copyable" for one reason or another, but in all of these cases it seems OK to me to use memcpy/memset on them. Adding a cast to void* tells GCC that "I know what I'm doing here" and shuts up the warning.
686 lines
12 KiB
C++
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();
|
|
}
|