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