xref: /haiku/src/kits/shared/Variant.cpp (revision b46615c55ad2c8fe6de54412055a0713da3d610a)
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