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
17 template<typename NumberType>
18 inline NumberType
_ToNumber() const19 BVariant::_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
~BVariant()50 BVariant::~BVariant()
51 {
52 Unset();
53 }
54
55
56 status_t
SetToTypedData(const void * data,type_code type)57 BVariant::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
115 void
Unset()116 BVariant::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
136 bool
operator ==(const BVariant & other) const137 BVariant::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
189 size_t
Size() const190 BVariant::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
200 const uint8*
Bytes() const201 BVariant::Bytes() const
202 {
203 if (fType == B_STRING_TYPE)
204 return (const uint8*)fString;
205 return fBytes;
206 }
207
208
209 bool
ToBool() const210 BVariant::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
247 int8
ToInt8() const248 BVariant::ToInt8() const
249 {
250 return _ToNumber<int8>();
251 }
252
253
254 uint8
ToUInt8() const255 BVariant::ToUInt8() const
256 {
257 return _ToNumber<uint8>();
258 }
259
260
261 int16
ToInt16() const262 BVariant::ToInt16() const
263 {
264 return _ToNumber<int16>();
265 }
266
267
268 uint16
ToUInt16() const269 BVariant::ToUInt16() const
270 {
271 return _ToNumber<uint16>();
272 }
273
274
275 int32
ToInt32() const276 BVariant::ToInt32() const
277 {
278 return _ToNumber<int32>();
279 }
280
281
282 uint32
ToUInt32() const283 BVariant::ToUInt32() const
284 {
285 return _ToNumber<uint32>();
286 }
287
288
289 int64
ToInt64() const290 BVariant::ToInt64() const
291 {
292 return _ToNumber<int64>();
293 }
294
295
296 uint64
ToUInt64() const297 BVariant::ToUInt64() const
298 {
299 return _ToNumber<uint64>();
300 }
301
302
303 float
ToFloat() const304 BVariant::ToFloat() const
305 {
306 return _ToNumber<float>();
307 }
308
309
310 double
ToDouble() const311 BVariant::ToDouble() const
312 {
313 return _ToNumber<double>();
314 }
315
316
317 BRect
ToRect() const318 BVariant::ToRect() const
319 {
320 return BRect(fRect.left, fRect.top, fRect.right, fRect.bottom);
321 }
322
323
324 void*
ToPointer() const325 BVariant::ToPointer() const
326 {
327 return fType == B_POINTER_TYPE ? fString : NULL;
328 }
329
330
331 const char*
ToString() const332 BVariant::ToString() const
333 {
334 return fType == B_STRING_TYPE ? fString : NULL;
335 }
336
337
338 void
_SetTo(const BVariant & other)339 BVariant::_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
360 BReferenceable*
ToReferenceable() const361 BVariant::ToReferenceable() const
362 {
363 return (fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0
364 ? fReferenceable : NULL;
365 }
366
367
368 void
SwapEndianess()369 BVariant::SwapEndianess()
370 {
371 if (!IsNumber() || fType == B_POINTER_TYPE)
372 return;
373
374 swap_data(fType, fBytes, Size(), B_SWAP_ALWAYS);
375 }
376
377
378 status_t
AddToMessage(BMessage & message,const char * fieldName) const379 BVariant::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
417 status_t
SetFromMessage(const BMessage & message,const char * fieldName)418 BVariant::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
SizeOfType(type_code type)440 BVariant::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
TypeIsNumber(type_code type)476 BVariant::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
TypeIsInteger(type_code type,bool * _isSigned)497 BVariant::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
TypeIsFloat(type_code type)521 BVariant::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
533 void
_SetTo(bool value)534 BVariant::_SetTo(bool value)
535 {
536 fType = B_BOOL_TYPE;
537 fFlags = 0;
538 fBool = value;
539 }
540
541
542 void
_SetTo(int8 value)543 BVariant::_SetTo(int8 value)
544 {
545 fType = B_INT8_TYPE;
546 fFlags = 0;
547 fInt8 = value;
548 }
549
550
551 void
_SetTo(uint8 value)552 BVariant::_SetTo(uint8 value)
553 {
554 fType = B_UINT8_TYPE;
555 fFlags = 0;
556 fUInt8 = value;
557 }
558
559
560 void
_SetTo(int16 value)561 BVariant::_SetTo(int16 value)
562 {
563 fType = B_INT16_TYPE;
564 fFlags = 0;
565 fInt16 = value;
566 }
567
568
569 void
_SetTo(uint16 value)570 BVariant::_SetTo(uint16 value)
571 {
572 fType = B_UINT16_TYPE;
573 fFlags = 0;
574 fUInt16 = value;
575 }
576
577
578 void
_SetTo(int32 value)579 BVariant::_SetTo(int32 value)
580 {
581 fType = B_INT32_TYPE;
582 fFlags = 0;
583 fInt32 = value;
584 }
585
586
587 void
_SetTo(uint32 value)588 BVariant::_SetTo(uint32 value)
589 {
590 fType = B_UINT32_TYPE;
591 fFlags = 0;
592 fUInt32 = value;
593 }
594
595
596 void
_SetTo(int64 value)597 BVariant::_SetTo(int64 value)
598 {
599 fType = B_INT64_TYPE;
600 fFlags = 0;
601 fInt64 = value;
602 }
603
604
605 void
_SetTo(uint64 value)606 BVariant::_SetTo(uint64 value)
607 {
608 fType = B_UINT64_TYPE;
609 fFlags = 0;
610 fUInt64 = value;
611 }
612
613
614 void
_SetTo(float value)615 BVariant::_SetTo(float value)
616 {
617 fType = B_FLOAT_TYPE;
618 fFlags = 0;
619 fFloat = value;
620 }
621
622
623 void
_SetTo(double value)624 BVariant::_SetTo(double value)
625 {
626 fType = B_DOUBLE_TYPE;
627 fFlags = 0;
628 fDouble = value;
629 }
630
631
632 void
_SetTo(float left,float top,float right,float bottom)633 BVariant::_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
644 void
_SetTo(const void * value)645 BVariant::_SetTo(const void* value)
646 {
647 fType = B_POINTER_TYPE;
648 fFlags = 0;
649 fPointer = (void*)value;
650 }
651
652
653 bool
_SetTo(const char * value,uint32 flags)654 BVariant::_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
676 void
_SetTo(BReferenceable * value,type_code type)677 BVariant::_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