xref: /haiku/src/kits/shared/Variant.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
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
19 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 
50 BVariant::~BVariant()
51 {
52 	Unset();
53 }
54 
55 
56 status_t
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
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
137 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
190 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*
201 BVariant::Bytes() const
202 {
203 	if (fType == B_STRING_TYPE)
204 		return (const uint8*)fString;
205 	return fBytes;
206 }
207 
208 
209 bool
210 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
248 BVariant::ToInt8() const
249 {
250 	return _ToNumber<int8>();
251 }
252 
253 
254 uint8
255 BVariant::ToUInt8() const
256 {
257 	return _ToNumber<uint8>();
258 }
259 
260 
261 int16
262 BVariant::ToInt16() const
263 {
264 	return _ToNumber<int16>();
265 }
266 
267 
268 uint16
269 BVariant::ToUInt16() const
270 {
271 	return _ToNumber<uint16>();
272 }
273 
274 
275 int32
276 BVariant::ToInt32() const
277 {
278 	return _ToNumber<int32>();
279 }
280 
281 
282 uint32
283 BVariant::ToUInt32() const
284 {
285 	return _ToNumber<uint32>();
286 }
287 
288 
289 int64
290 BVariant::ToInt64() const
291 {
292 	return _ToNumber<int64>();
293 }
294 
295 
296 uint64
297 BVariant::ToUInt64() const
298 {
299 	return _ToNumber<uint64>();
300 }
301 
302 
303 float
304 BVariant::ToFloat() const
305 {
306 	return _ToNumber<float>();
307 }
308 
309 
310 double
311 BVariant::ToDouble() const
312 {
313 	return _ToNumber<double>();
314 }
315 
316 
317 BRect
318 BVariant::ToRect() const
319 {
320 	return BRect(fRect.left, fRect.top, fRect.right, fRect.bottom);
321 }
322 
323 
324 void*
325 BVariant::ToPointer() const
326 {
327 	return fType == B_POINTER_TYPE ? fString : NULL;
328 }
329 
330 
331 const char*
332 BVariant::ToString() const
333 {
334 	return fType == B_STRING_TYPE ? fString : NULL;
335 }
336 
337 
338 void
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*
361 BVariant::ToReferenceable() const
362 {
363 	return (fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0
364 		? fReferenceable : NULL;
365 }
366 
367 
368 void
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
379 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
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
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
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
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
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
534 BVariant::_SetTo(bool value)
535 {
536 	fType = B_BOOL_TYPE;
537 	fFlags = 0;
538 	fBool = value;
539 }
540 
541 
542 void
543 BVariant::_SetTo(int8 value)
544 {
545 	fType = B_INT8_TYPE;
546 	fFlags = 0;
547 	fInt8 = value;
548 }
549 
550 
551 void
552 BVariant::_SetTo(uint8 value)
553 {
554 	fType = B_UINT8_TYPE;
555 	fFlags = 0;
556 	fUInt8 = value;
557 }
558 
559 
560 void
561 BVariant::_SetTo(int16 value)
562 {
563 	fType = B_INT16_TYPE;
564 	fFlags = 0;
565 	fInt16 = value;
566 }
567 
568 
569 void
570 BVariant::_SetTo(uint16 value)
571 {
572 	fType = B_UINT16_TYPE;
573 	fFlags = 0;
574 	fUInt16 = value;
575 }
576 
577 
578 void
579 BVariant::_SetTo(int32 value)
580 {
581 	fType = B_INT32_TYPE;
582 	fFlags = 0;
583 	fInt32 = value;
584 }
585 
586 
587 void
588 BVariant::_SetTo(uint32 value)
589 {
590 	fType = B_UINT32_TYPE;
591 	fFlags = 0;
592 	fUInt32 = value;
593 }
594 
595 
596 void
597 BVariant::_SetTo(int64 value)
598 {
599 	fType = B_INT64_TYPE;
600 	fFlags = 0;
601 	fInt64 = value;
602 }
603 
604 
605 void
606 BVariant::_SetTo(uint64 value)
607 {
608 	fType = B_UINT64_TYPE;
609 	fFlags = 0;
610 	fUInt64 = value;
611 }
612 
613 
614 void
615 BVariant::_SetTo(float value)
616 {
617 	fType = B_FLOAT_TYPE;
618 	fFlags = 0;
619 	fFloat = value;
620 }
621 
622 
623 void
624 BVariant::_SetTo(double value)
625 {
626 	fType = B_DOUBLE_TYPE;
627 	fFlags = 0;
628 	fDouble = value;
629 }
630 
631 
632 void
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
645 BVariant::_SetTo(const void* value)
646 {
647 	fType = B_POINTER_TYPE;
648 	fFlags = 0;
649 	fPointer = (void*)value;
650 }
651 
652 
653 bool
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
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