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