1/* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2011, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8#include <Variant.h> 9 10#include <stdlib.h> 11#include <string.h> 12 13#include <ByteOrder.h> 14#include <Message.h> 15 16 17template<typename NumberType> 18inline NumberType 19BVariant::_ToNumber() const 20{ 21 switch (fType) { 22 case B_BOOL_TYPE: 23 return fBool ? 1 : 0; 24 case B_INT8_TYPE: 25 return (NumberType)fInt8; 26 case B_UINT8_TYPE: 27 return (NumberType)fUInt8; 28 case B_INT16_TYPE: 29 return (NumberType)fInt16; 30 case B_UINT16_TYPE: 31 return (NumberType)fUInt16; 32 case B_INT32_TYPE: 33 return (NumberType)fInt32; 34 case B_UINT32_TYPE: 35 return (NumberType)fUInt32; 36 case B_INT64_TYPE: 37 return (NumberType)fInt64; 38 case B_UINT64_TYPE: 39 return (NumberType)fUInt64; 40 case B_FLOAT_TYPE: 41 return (NumberType)fFloat; 42 case B_DOUBLE_TYPE: 43 return (NumberType)fDouble; 44 default: 45 return 0; 46 } 47} 48 49 50BVariant::~BVariant() 51{ 52 Unset(); 53} 54 55 56status_t 57BVariant::SetToTypedData(const void* data, type_code type) 58{ 59 Unset(); 60 61 switch (type) { 62 case B_BOOL_TYPE: 63 fBool = *(bool*)data; 64 break; 65 case B_INT8_TYPE: 66 fInt8 = *(int8*)data; 67 break; 68 case B_UINT8_TYPE: 69 fUInt8 = *(uint8*)data; 70 break; 71 case B_INT16_TYPE: 72 fInt16 = *(int16*)data; 73 break; 74 case B_UINT16_TYPE: 75 fUInt16 = *(uint16*)data; 76 break; 77 case B_INT32_TYPE: 78 fInt32 = *(int32*)data; 79 break; 80 case B_UINT32_TYPE: 81 fUInt32 = *(uint32*)data; 82 break; 83 case B_INT64_TYPE: 84 fInt64 = *(int64*)data; 85 break; 86 case B_UINT64_TYPE: 87 fUInt64 = *(uint64*)data; 88 break; 89 case B_FLOAT_TYPE: 90 fFloat = *(float*)data; 91 break; 92 case B_DOUBLE_TYPE: 93 fDouble = *(double*)data; 94 break; 95 case B_POINTER_TYPE: 96 fPointer = *(void**)data; 97 break; 98 case B_STRING_TYPE: 99 return _SetTo((const char*)data, 0) ? B_OK : B_NO_MEMORY; 100 case B_RECT_TYPE: 101 { 102 BRect *rect = (BRect *)data; 103 _SetTo(rect->left, rect->top, rect->right, rect->bottom); 104 break; 105 } 106 default: 107 return B_BAD_TYPE; 108 } 109 110 fType = type; 111 return B_OK; 112} 113 114 115void 116BVariant::Unset() 117{ 118 if ((fFlags & B_VARIANT_OWNS_DATA) != 0) { 119 switch (fType) { 120 case B_STRING_TYPE: 121 free(fString); 122 break; 123 default: 124 break; 125 } 126 } else if ((fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0) { 127 if (fReferenceable != NULL) 128 fReferenceable->ReleaseReference(); 129 } 130 131 fType = 0; 132 fFlags = 0; 133} 134 135 136bool 137BVariant::operator==(const BVariant& other) const 138{ 139 if (fType == 0) 140 return other.fType == 0; 141 if (other.fType == 0) 142 return false; 143 144 // TODO: The number comparisons are not really accurate. Particularly a 145 // conversion between signed and unsigned integers might actually change the 146 // value. 147 148 switch (fType) { 149 case B_BOOL_TYPE: 150 return fBool == other.ToBool(); 151 case B_INT8_TYPE: 152 case B_INT16_TYPE: 153 case B_INT32_TYPE: 154 case B_INT64_TYPE: 155 if (!other.IsNumber()) 156 return false; 157 return ToInt64() == other.ToInt64(); 158 case B_UINT8_TYPE: 159 case B_UINT16_TYPE: 160 case B_UINT32_TYPE: 161 case B_UINT64_TYPE: 162 if (!other.IsNumber()) 163 return false; 164 return ToUInt64() == other.ToUInt64(); 165 case B_FLOAT_TYPE: 166 case B_DOUBLE_TYPE: 167 if (!other.IsNumber()) 168 return false; 169 return ToDouble() == other.ToDouble(); 170 case B_POINTER_TYPE: 171 return other.fType == B_POINTER_TYPE 172 && fPointer == other.fPointer; 173 case B_STRING_TYPE: 174 if (other.fType != B_STRING_TYPE) 175 return false; 176 if (fString == NULL || other.fString == NULL) 177 return fString == other.fString; 178 return strcmp(fString, other.fString) == 0; 179 case B_RECT_TYPE: 180 return BRect(fRect.left, fRect.top, fRect.right, fRect.bottom) 181 == BRect(other.fRect.left, other.fRect.top, other.fRect.right, 182 other.fRect.bottom); 183 default: 184 return false; 185 } 186} 187 188 189size_t 190BVariant::Size() const 191{ 192 if (fType == B_STRING_TYPE) 193 return fString != NULL ? strlen(fString) + 1 : 0; 194 if ((fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0) 195 return sizeof(this->fReferenceable); 196 return SizeOfType(fType); 197} 198 199 200const uint8* 201BVariant::Bytes() const 202{ 203 if (fType == B_STRING_TYPE) 204 return (const uint8*)fString; 205 return fBytes; 206} 207 208 209bool 210BVariant::ToBool() const 211{ 212 switch (fType) { 213 case B_BOOL_TYPE: 214 return fBool; 215 case B_INT8_TYPE: 216 return fInt8 != 0; 217 case B_UINT8_TYPE: 218 return fUInt8 != 0; 219 case B_INT16_TYPE: 220 return fInt16 != 0; 221 case B_UINT16_TYPE: 222 return fUInt16 != 0; 223 case B_INT32_TYPE: 224 return fInt32 != 0; 225 case B_UINT32_TYPE: 226 return fUInt32 != 0; 227 case B_INT64_TYPE: 228 return fInt64 != 0; 229 case B_UINT64_TYPE: 230 return fUInt64 != 0; 231 case B_FLOAT_TYPE: 232 return fFloat != 0; 233 case B_DOUBLE_TYPE: 234 return fDouble != 0; 235 case B_POINTER_TYPE: 236 return fPointer != NULL; 237 case B_STRING_TYPE: 238 return fString != NULL; 239 // TODO: We should probably check for actual values like "true", 240 // "false", "on", "off", etc. 241 default: 242 return false; 243 } 244} 245 246 247int8 248BVariant::ToInt8() const 249{ 250 return _ToNumber<int8>(); 251} 252 253 254uint8 255BVariant::ToUInt8() const 256{ 257 return _ToNumber<uint8>(); 258} 259 260 261int16 262BVariant::ToInt16() const 263{ 264 return _ToNumber<int16>(); 265} 266 267 268uint16 269BVariant::ToUInt16() const 270{ 271 return _ToNumber<uint16>(); 272} 273 274 275int32 276BVariant::ToInt32() const 277{ 278 return _ToNumber<int32>(); 279} 280 281 282uint32 283BVariant::ToUInt32() const 284{ 285 return _ToNumber<uint32>(); 286} 287 288 289int64 290BVariant::ToInt64() const 291{ 292 return _ToNumber<int64>(); 293} 294 295 296uint64 297BVariant::ToUInt64() const 298{ 299 return _ToNumber<uint64>(); 300} 301 302 303float 304BVariant::ToFloat() const 305{ 306 return _ToNumber<float>(); 307} 308 309 310double 311BVariant::ToDouble() const 312{ 313 return _ToNumber<double>(); 314} 315 316 317BRect 318BVariant::ToRect() const 319{ 320 return BRect(fRect.left, fRect.top, fRect.right, fRect.bottom); 321} 322 323 324void* 325BVariant::ToPointer() const 326{ 327 return fType == B_POINTER_TYPE ? fString : NULL; 328} 329 330 331const char* 332BVariant::ToString() const 333{ 334 return fType == B_STRING_TYPE ? fString : NULL; 335} 336 337 338void 339BVariant::_SetTo(const BVariant& other) 340{ 341 if ((other.fFlags & B_VARIANT_OWNS_DATA) != 0) { 342 switch (other.fType) { 343 case B_STRING_TYPE: 344 fType = B_STRING_TYPE; 345 fString = strdup(other.fString); 346 fFlags = B_VARIANT_OWNS_DATA; 347 return; 348 default: 349 break; 350 } 351 } else if ((other.fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0) { 352 if (other.fReferenceable != NULL) 353 other.fReferenceable->AcquireReference(); 354 } 355 356 memcpy((void*)this, (void*)&other, sizeof(BVariant)); 357} 358 359 360BReferenceable* 361BVariant::ToReferenceable() const 362{ 363 return (fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0 364 ? fReferenceable : NULL; 365} 366 367 368void 369BVariant::SwapEndianess() 370{ 371 if (!IsNumber() || fType == B_POINTER_TYPE) 372 return; 373 374 swap_data(fType, fBytes, Size(), B_SWAP_ALWAYS); 375} 376 377 378status_t 379BVariant::AddToMessage(BMessage& message, const char* fieldName) const 380{ 381 switch (fType) { 382 case B_BOOL_TYPE: 383 return message.AddBool(fieldName, fBool); 384 case B_INT8_TYPE: 385 return message.AddInt8(fieldName, fInt8); 386 case B_UINT8_TYPE: 387 return message.AddUInt8(fieldName, fUInt8); 388 case B_INT16_TYPE: 389 return message.AddInt16(fieldName, fInt16); 390 case B_UINT16_TYPE: 391 return message.AddUInt16(fieldName, fUInt16); 392 case B_INT32_TYPE: 393 return message.AddInt32(fieldName, fInt32); 394 case B_UINT32_TYPE: 395 return message.AddUInt32(fieldName, fUInt32); 396 case B_INT64_TYPE: 397 return message.AddInt64(fieldName, fInt64); 398 case B_UINT64_TYPE: 399 return message.AddUInt64(fieldName, fUInt64); 400 case B_FLOAT_TYPE: 401 return message.AddFloat(fieldName, fFloat); 402 case B_DOUBLE_TYPE: 403 return message.AddDouble(fieldName, fDouble); 404 case B_POINTER_TYPE: 405 return message.AddPointer(fieldName, fPointer); 406 case B_STRING_TYPE: 407 return message.AddString(fieldName, fString); 408 case B_RECT_TYPE: 409 return message.AddRect(fieldName, BRect(fRect.left, fRect.top, 410 fRect.right, fRect.bottom)); 411 default: 412 return B_UNSUPPORTED; 413 } 414} 415 416 417status_t 418BVariant::SetFromMessage(const BMessage& message, const char* fieldName) 419{ 420 // get the message field info 421 type_code type; 422 int32 count; 423 status_t error = message.GetInfo(fieldName, &type, &count); 424 if (error != B_OK) 425 return error; 426 427 // get the data 428 const void* data; 429 ssize_t numBytes; 430 error = message.FindData(fieldName, type, &data, &numBytes); 431 if (error != B_OK) 432 return error; 433 434 // init the object 435 return SetToTypedData(data, type); 436} 437 438 439/*static*/ size_t 440BVariant::SizeOfType(type_code type) 441{ 442 switch (type) { 443 case B_BOOL_TYPE: 444 return 1; 445 case B_INT8_TYPE: 446 return 1; 447 case B_UINT8_TYPE: 448 return 1; 449 case B_INT16_TYPE: 450 return 2; 451 case B_UINT16_TYPE: 452 return 2; 453 case B_INT32_TYPE: 454 return 4; 455 case B_UINT32_TYPE: 456 return 4; 457 case B_INT64_TYPE: 458 return 8; 459 case B_UINT64_TYPE: 460 return 8; 461 case B_FLOAT_TYPE: 462 return sizeof(float); 463 case B_DOUBLE_TYPE: 464 return sizeof(double); 465 case B_POINTER_TYPE: 466 return sizeof(void*); 467 case B_RECT_TYPE: 468 return sizeof(BRect); 469 default: 470 return 0; 471 } 472} 473 474 475/*static*/ bool 476BVariant::TypeIsNumber(type_code type) 477{ 478 switch (type) { 479 case B_INT8_TYPE: 480 case B_UINT8_TYPE: 481 case B_INT16_TYPE: 482 case B_UINT16_TYPE: 483 case B_INT32_TYPE: 484 case B_UINT32_TYPE: 485 case B_INT64_TYPE: 486 case B_UINT64_TYPE: 487 case B_FLOAT_TYPE: 488 case B_DOUBLE_TYPE: 489 return true; 490 default: 491 return false; 492 } 493} 494 495 496/*static*/ bool 497BVariant::TypeIsInteger(type_code type, bool* _isSigned) 498{ 499 switch (type) { 500 case B_INT8_TYPE: 501 case B_INT16_TYPE: 502 case B_INT32_TYPE: 503 case B_INT64_TYPE: 504 if (_isSigned != NULL) 505 *_isSigned = true; 506 return true; 507 case B_UINT8_TYPE: 508 case B_UINT16_TYPE: 509 case B_UINT32_TYPE: 510 case B_UINT64_TYPE: 511 if (_isSigned != NULL) 512 *_isSigned = false; 513 return true; 514 default: 515 return false; 516 } 517} 518 519 520/*static*/ bool 521BVariant::TypeIsFloat(type_code type) 522{ 523 switch (type) { 524 case B_FLOAT_TYPE: 525 case B_DOUBLE_TYPE: 526 return true; 527 default: 528 return false; 529 } 530} 531 532 533void 534BVariant::_SetTo(bool value) 535{ 536 fType = B_BOOL_TYPE; 537 fFlags = 0; 538 fBool = value; 539} 540 541 542void 543BVariant::_SetTo(int8 value) 544{ 545 fType = B_INT8_TYPE; 546 fFlags = 0; 547 fInt8 = value; 548} 549 550 551void 552BVariant::_SetTo(uint8 value) 553{ 554 fType = B_UINT8_TYPE; 555 fFlags = 0; 556 fUInt8 = value; 557} 558 559 560void 561BVariant::_SetTo(int16 value) 562{ 563 fType = B_INT16_TYPE; 564 fFlags = 0; 565 fInt16 = value; 566} 567 568 569void 570BVariant::_SetTo(uint16 value) 571{ 572 fType = B_UINT16_TYPE; 573 fFlags = 0; 574 fUInt16 = value; 575} 576 577 578void 579BVariant::_SetTo(int32 value) 580{ 581 fType = B_INT32_TYPE; 582 fFlags = 0; 583 fInt32 = value; 584} 585 586 587void 588BVariant::_SetTo(uint32 value) 589{ 590 fType = B_UINT32_TYPE; 591 fFlags = 0; 592 fUInt32 = value; 593} 594 595 596void 597BVariant::_SetTo(int64 value) 598{ 599 fType = B_INT64_TYPE; 600 fFlags = 0; 601 fInt64 = value; 602} 603 604 605void 606BVariant::_SetTo(uint64 value) 607{ 608 fType = B_UINT64_TYPE; 609 fFlags = 0; 610 fUInt64 = value; 611} 612 613 614void 615BVariant::_SetTo(float value) 616{ 617 fType = B_FLOAT_TYPE; 618 fFlags = 0; 619 fFloat = value; 620} 621 622 623void 624BVariant::_SetTo(double value) 625{ 626 fType = B_DOUBLE_TYPE; 627 fFlags = 0; 628 fDouble = value; 629} 630 631 632void 633BVariant::_SetTo(float left, float top, float right, float bottom) 634{ 635 fType = B_RECT_TYPE; 636 fFlags = 0; 637 fRect.left = left; 638 fRect.top = top; 639 fRect.right = right; 640 fRect.bottom = bottom; 641} 642 643 644void 645BVariant::_SetTo(const void* value) 646{ 647 fType = B_POINTER_TYPE; 648 fFlags = 0; 649 fPointer = (void*)value; 650} 651 652 653bool 654BVariant::_SetTo(const char* value, uint32 flags) 655{ 656 fType = B_STRING_TYPE; 657 fFlags = 0; 658 659 if (value != NULL) { 660 if ((flags & B_VARIANT_DONT_COPY_DATA) == 0) { 661 fString = strdup(value); 662 fFlags |= B_VARIANT_OWNS_DATA; 663 if (fString == NULL) 664 return false; 665 } else { 666 fString = (char*)value; 667 fFlags |= flags & B_VARIANT_OWNS_DATA; 668 } 669 } else 670 fString = NULL; 671 672 return true; 673} 674 675 676void 677BVariant::_SetTo(BReferenceable* value, type_code type) 678{ 679 fType = type; 680 fFlags = B_VARIANT_REFERENCEABLE_DATA; 681 fReferenceable = value; 682 683 if (fReferenceable != NULL) 684 fReferenceable->AcquireReference(); 685} 686