/* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2011, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include #include #include #include #include template 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(); } uint8 BVariant::ToUInt8() const { return _ToNumber(); } int16 BVariant::ToInt16() const { return _ToNumber(); } uint16 BVariant::ToUInt16() const { return _ToNumber(); } int32 BVariant::ToInt32() const { return _ToNumber(); } uint32 BVariant::ToUInt32() const { return _ToNumber(); } int64 BVariant::ToInt64() const { return _ToNumber(); } uint64 BVariant::ToUInt64() const { return _ToNumber(); } float BVariant::ToFloat() const { return _ToNumber(); } double BVariant::ToDouble() const { return _ToNumber(); } 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(); }