]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_value.cpp
Initial vogl checkin
[vogl] / src / voglcore / vogl_value.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 // File: vogl_value.cpp
28 #include "vogl_core.h"
29 #include "vogl_value.h"
30 #include <float.h>
31
32 namespace vogl
33 {
34     const char *g_value_data_type_strings[cDTTotal + 1] =
35         {
36             "invalid",
37             "bool",
38             "int8",
39             "uint8",
40             "int16",
41             "uint16",
42             "int",
43             "uint",
44             "int64_t",
45             "uint64_t",
46             "float",
47             "double",
48             "void*",
49             "string_hash",
50             "string",
51             "vec3f",
52             "vec3i",
53             "blob",
54             "json",
55             NULL,
56         };
57
58     value_data_type string_to_value_data_type(const char *pStr)
59     {
60         for (uint i = 0; i < cDTTotal; i++)
61             if (!vogl_stricmp(pStr, g_value_data_type_strings[i]))
62                 return static_cast<value_data_type>(i);
63         return cDTInvalid;
64     }
65
66     value &value::operator=(const value &other)
67     {
68         if (this == &other)
69             return *this;
70
71         change_type(other.m_type);
72         m_user_data = other.m_user_data;
73         m_flags = other.m_flags;
74
75         switch (other.m_type)
76         {
77             case cDTString:
78                 m_pStr->set(*other.m_pStr);
79                 break;
80             case cDTVec3F:
81                 m_pVec3F->set(*other.m_pVec3F);
82                 break;
83             case cDTVec3I:
84                 m_pVec3I->set(*other.m_pVec3I);
85                 break;
86             case cDTBlob:
87                 (*m_pBlob) = (*other.m_pBlob);
88                 break;
89             case cDTJSONDoc:
90                 (*m_pJSONDoc) = (*other.m_pJSONDoc);
91                 break;
92             default:
93                 m_uint64 = other.m_uint64;
94                 break;
95         }
96         return *this;
97     }
98
99     bool value::operator==(const value &other) const
100     {
101         if (this == &other)
102             return true;
103
104         if (m_flags != other.m_flags)
105             return false;
106         if (m_flags & cFlagsHasUserData)
107         {
108             if (m_user_data != other.m_user_data)
109                 return false;
110         }
111
112         if (m_type != other.m_type)
113             return false;
114
115         if (m_type == cDTInvalid)
116             return true;
117         else if (is_json_document())
118             return *m_pJSONDoc == *other.m_pJSONDoc;
119
120         if (get_data_size_in_bytes() != other.get_data_size_in_bytes())
121             return false;
122
123         return memcmp(get_data_ptr(), other.get_data_ptr(), other.get_data_size_in_bytes()) == 0;
124     }
125
126     bool value::operator<(const value &other) const
127     {
128         if (this == &other)
129             return true;
130
131         if (m_flags < other.m_flags)
132             return true;
133         else if (m_flags != other.m_flags)
134             return false;
135
136         if (m_flags & cFlagsHasUserData)
137         {
138             if (m_user_data < other.m_user_data)
139                 return true;
140             else if (m_user_data != other.m_user_data)
141                 return false;
142         }
143
144         if (m_type < other.m_type)
145             return true;
146         else if (m_type == other.m_type)
147         {
148             switch (m_type)
149             {
150                 case cDTInvalid:
151                     break;
152                 case cDTString:
153                     return m_pStr->compare(*other.m_pStr, true) < 0;
154                 case cDTBool:
155                     return m_bool < other.m_bool;
156                 case cDTInt8:
157                     return m_int8 < other.m_int8;
158                 case cDTUInt8:
159                     return m_uint8 < other.m_uint8;
160                 case cDTInt16:
161                     return m_int16 < other.m_int16;
162                 case cDTUInt16:
163                     return m_uint16 < other.m_uint16;
164                 case cDTInt:
165                     return m_int < other.m_int;
166                 case cDTStringHash:
167                 case cDTUInt:
168                     return m_uint < other.m_uint;
169                 case cDTFloat:
170                     return m_float < other.m_float;
171                 case cDTDouble:
172                     return m_double < other.m_double;
173                 case cDTInt64:
174                     return m_int64 < other.m_int64;
175                 case cDTUInt64:
176                     return m_uint64 < other.m_uint64;
177                 case cDTVoidPtr:
178                     return m_pPtr < other.m_pPtr;
179                 case cDTVec3F:
180                     return (*m_pVec3F) < (*other.m_pVec3F);
181                 case cDTVec3I:
182                     return (*m_pVec3I) < (*other.m_pVec3I);
183                 case cDTBlob:
184                     return (*m_pBlob) < (*other.m_pBlob);
185                 case cDTJSONDoc:
186                 {
187                     // This is brain dead slow, but I doubt we'll be using this path much if at all.
188                     uint8_vec doc;
189                     m_pJSONDoc->binary_serialize(doc);
190
191                     uint8_vec other_doc;
192                     other.m_pJSONDoc->binary_serialize(other_doc);
193
194                     return doc < other_doc;
195                 }
196                 default:
197                     VOGL_ASSERT_ALWAYS;
198                     break;
199             }
200         }
201
202         return false;
203     }
204
205     bool value::parse(const char *p)
206     {
207         if ((!p) || (!p[0]))
208         {
209             clear();
210             return false;
211         }
212
213         size_t str_len = strlen(p);
214
215         if (vogl_stricmp(p, "false") == 0)
216         {
217             set_bool(false);
218             return true;
219         }
220         else if (vogl_stricmp(p, "true") == 0)
221         {
222             set_bool(true);
223             return true;
224         }
225
226         if (p[0] == '\"')
227         {
228             dynamic_string str;
229             str = p + 1;
230             if (!str.is_empty())
231             {
232                 if (str[str.get_len() - 1] == '\"')
233                 {
234                     str.left(str.get_len() - 1);
235                     set_str(str);
236
237                     return true;
238                 }
239             }
240         }
241
242         if (p[0] == '[')
243         {
244             if (p[str_len - 1] == ']')
245             {
246                 size_t i;
247                 for (i = 1; i < (str_len - 1); i++)
248                 {
249                     if (((static_cast<int>(i) - 1) % 3) == 2)
250                     {
251                         if (p[i] != ',')
252                             break;
253                     }
254                     else if (utils::from_hex(p[i]) < 0)
255                         break;
256                 }
257
258                 if (i == (str_len - 1))
259                 {
260                     size_t size = str_len - 2;
261                     if (size)
262                     {
263                         if (size == 2)
264                             size = 1;
265                         else
266                             size = (size / 3) + 1;
267                     }
268
269                     if (size > cUINT32_MAX)
270                     {
271                         clear();
272                         return false;
273                     }
274
275                     change_type(cDTBlob);
276                     if (!m_pBlob->try_resize(static_cast<uint>(size)))
277                     {
278                         clear();
279                         return false;
280                     }
281
282                     if (size)
283                     {
284                         uint8 *pDst = m_pBlob->get_ptr();
285
286                         for (i = 1; i < (str_len - 1); i += 3)
287                         {
288                             int h = utils::from_hex(p[i]);
289                             int l = utils::from_hex(p[i + 1]);
290
291                             *pDst++ = ((h << 4) | l);
292                         }
293                     }
294
295                     return true;
296                 }
297             }
298         }
299
300         if (strchr(p, ',') != NULL)
301         {
302             float fx = 0, fy = 0, fz = 0;
303 #ifdef _MSC_VER
304             if (sscanf_s(p, "%f,%f,%f", &fx, &fy, &fz) == 3)
305 #else
306             if (sscanf(p, "%f,%f,%f", &fx, &fy, &fz) == 3)
307 #endif
308             {
309                 bool as_float = true;
310                 int ix = 0, iy = 0, iz = 0;
311 #ifdef _MSC_VER
312                 if (sscanf_s(p, "%i,%i,%i", &ix, &iy, &iz) == 3)
313 #else
314                 if (sscanf(p, "%i,%i,%i", &ix, &iy, &iz) == 3)
315 #endif
316                 {
317                     if ((ix == fx) && (iy == fy) && (iz == fz))
318                         as_float = false;
319                 }
320
321                 if (as_float)
322                     set_vec(vec3F(fx, fy, fz));
323                 else
324                     set_vec(vec3I(ix, iy, iz));
325
326                 return true;
327             }
328         }
329
330         if (str_len >= 2)
331         {
332             if ((p[0] == '{') && (p[str_len - 1] == '}'))
333             {
334                 json_document doc;
335                 if (doc.deserialize(p))
336                 {
337                     set_json_document_take_ownership(doc);
338                     return true;
339                 }
340             }
341         }
342
343         const char *q = p;
344         bool success = string_ptr_to_uint64(q, m_uint64);
345         if ((success) && (*q == 0))
346         {
347             if (m_uint64 <= cUINT8_MAX)
348                 set_uint8(static_cast<uint8>(m_uint64));
349             else if (m_uint64 <= cUINT16_MAX)
350                 set_uint16(static_cast<uint16>(m_uint64));
351             else if (m_uint64 <= cUINT32_MAX)
352                 set_uint(static_cast<uint>(m_uint64));
353             else
354                 set_uint64(m_uint64);
355             return true;
356         }
357
358         q = p;
359         success = string_ptr_to_int64(q, m_int64);
360         if ((success) && (*q == 0))
361         {
362             if ((m_int64 >= cINT16_MIN) && (m_int64 <= cINT16_MAX))
363                 set_int16(static_cast<int16>(m_int64));
364             else if ((m_int64 >= cINT32_MIN) && (m_int64 <= cINT32_MAX))
365                 set_int(static_cast<int>(m_int64));
366             else
367                 set_int64(m_int64);
368             return true;
369         }
370
371         q = p;
372         success = string_ptr_to_double(q, m_double);
373         if ((success) && (*q == 0))
374         {
375             float value_as_float = static_cast<float>(m_double);
376             if (value_as_float == m_double)
377                 set_float(value_as_float);
378             else
379                 set_double(m_double);
380             return true;
381         }
382
383         set_string(p);
384
385         return true;
386     }
387
388     // rename quote_strings to parsable? or add another method?
389     // TODO: Get rid of quote_strings and add flags field
390     dynamic_string &value::get_string(dynamic_string &dst, bool quote_strings) const
391     {
392         switch (m_type)
393         {
394             case cDTInvalid:
395                 break;
396             case cDTString:
397             {
398                 if (quote_strings)
399                 {
400                     dst = "\"";
401                     dst += *m_pStr;
402                     dst += "\"";
403                 }
404                 else
405                 {
406                     dst = *m_pStr;
407                 }
408                 break;
409             }
410             case cDTBool:
411                 dst = m_bool ? "TRUE" : "FALSE";
412                 break;
413             case cDTInt8:
414                 dst.format("%i", m_int8);
415                 break;
416             case cDTUInt8:
417                 dst.format("%u", m_uint8);
418                 break;
419             case cDTInt16:
420                 dst.format("%i", m_int16);
421                 break;
422             case cDTUInt16:
423                 dst.format("%u", m_uint16);
424                 break;
425             case cDTInt:
426                 dst.format("%i", m_int);
427                 break;
428             case cDTStringHash:
429             case cDTUInt:
430                 dst.format("%u", m_uint);
431                 break;
432             case cDTInt64:
433                 dst.format("%" PRIi64, m_int64);
434                 break;
435             case cDTUInt64:
436                 dst.format("%" PRIu64, m_uint64);
437                 break;
438             case cDTVoidPtr:
439                 dst.format("0x%" PRIxPTR, reinterpret_cast<uintptr_t>(m_pPtr));
440                 break;
441             case cDTFloat:
442                 dst.format("%1.8f", m_float);
443                 break;
444             case cDTDouble:
445                 dst.format("%1.17f", m_double);
446                 break;
447             case cDTVec3F:
448                 dst.format("%1.8f,%1.8f,%1.8f", (*m_pVec3F)[0], (*m_pVec3F)[1], (*m_pVec3F)[2]);
449                 break;
450             case cDTVec3I:
451                 dst.format("%i,%i,%i", (*m_pVec3I)[0], (*m_pVec3I)[1], (*m_pVec3I)[2]);
452                 break;
453             case cDTBlob:
454             {
455                 uint blob_size = m_pBlob->size();
456                 const uint8 *pSrc = m_pBlob->get_ptr();
457
458                 if (!blob_size)
459                     dst = "[]";
460                 else
461                 {
462                     dst.set_len(blob_size * 3 + 2 - 1);
463                     dst.set_char(0, '[');
464                     dst.set_char(dst.get_len() - 1, ']');
465
466                     for (uint i = 0; i < blob_size; i++)
467                     {
468                         uint8 v = pSrc[i];
469                         dst.set_char(1 + i * 3 + 0, utils::to_hex(v >> 4));
470                         dst.set_char(1 + i * 3 + 1, utils::to_hex(v & 0xF));
471                         if (i < (blob_size - 1))
472                             dst.set_char(1 + i * 3 + 2, ',');
473                     }
474                 }
475
476                 break;
477             }
478             case cDTJSONDoc:
479             {
480                 m_pJSONDoc->serialize(dst);
481                 break;
482             }
483             default:
484                 VOGL_ASSERT_ALWAYS;
485                 break;
486         }
487
488         return dst;
489     }
490
491     bool value::get_int8_or_fail(int8 &val, uint component) const
492     {
493         int64_t i64_val;
494         bool success = get_int64_or_fail(i64_val, component);
495         if ((!success) || (i64_val < cINT8_MIN) || (i64_val > cINT8_MAX))
496             return false;
497
498         val = static_cast<int8>(i64_val);
499         return true;
500     }
501
502     bool value::get_uint8_or_fail(uint8 &val, uint component) const
503     {
504         uint64_t u64_val;
505         bool success = get_uint64_or_fail(u64_val, component);
506         if ((!success) || (u64_val > cUINT8_MAX))
507             return false;
508
509         val = static_cast<uint8>(u64_val);
510         return true;
511     }
512
513     bool value::get_int16_or_fail(int16 &val, uint component) const
514     {
515         int64_t i64_val;
516         bool success = get_int64_or_fail(i64_val, component);
517         if ((!success) || (i64_val < cINT16_MIN) || (i64_val > cINT16_MAX))
518             return false;
519
520         val = static_cast<int16>(i64_val);
521         return true;
522     }
523
524     bool value::get_uint16_or_fail(uint16 &val, uint component) const
525     {
526         uint64_t u64_val;
527         bool success = get_uint64_or_fail(u64_val, component);
528         if ((!success) || (u64_val > cUINT16_MAX))
529             return false;
530
531         val = static_cast<uint16>(u64_val);
532         return true;
533     }
534
535     bool value::get_int_or_fail(int &val, uint component) const
536     {
537         int64_t i64_val;
538         bool success = get_int64_or_fail(i64_val, component);
539         if ((!success) || (i64_val < cINT32_MIN) || (i64_val > cINT32_MAX))
540             return false;
541
542         val = static_cast<int>(i64_val);
543         return true;
544     }
545
546     bool value::get_int64_or_fail(int64_t &val, uint component) const
547     {
548         switch (m_type)
549         {
550             case cDTInvalid:
551             {
552                 return false;
553             }
554             case cDTString:
555             {
556                 const char *p = m_pStr->get_ptr();
557                 return string_ptr_to_int64(p, val);
558             }
559             case cDTBool:
560             {
561                 val = m_bool;
562                 break;
563             }
564             case cDTInt8:
565             {
566                 val = m_int8;
567                 break;
568             }
569             case cDTUInt8:
570             {
571                 val = m_uint8;
572                 break;
573             }
574             case cDTInt16:
575             {
576                 val = m_int16;
577                 break;
578             }
579             case cDTUInt16:
580             {
581                 val = m_uint16;
582                 break;
583             }
584             case cDTInt:
585             {
586                 val = m_int;
587                 break;
588             }
589             case cDTStringHash:
590             case cDTUInt:
591             {
592                 val = m_uint;
593                 break;
594             }
595             case cDTInt64:
596             {
597                 val = m_int64;
598                 break;
599             }
600             case cDTUInt64:
601             {
602                 if (m_uint64 > static_cast<uint64_t>(cINT64_MAX))
603                     return false;
604                 val = static_cast<int64_t>(m_uint64);
605                 break;
606             }
607             case cDTFloat:
608             {
609                 if ((m_float < cINT64_MIN) || (m_float > cINT64_MAX))
610                     return false;
611                 val = static_cast<int64_t>(m_float);
612                 break;
613             }
614             case cDTDouble:
615             {
616                 if ((m_double < cINT64_MIN) || (m_double > cINT64_MAX))
617                     return false;
618                 val = static_cast<int64_t>(m_double);
619                 break;
620             }
621             case cDTVec3F:
622             {
623                 if (component > 2)
624                     return false;
625                 if (((*m_pVec3F)[component] < cINT64_MIN) || ((*m_pVec3F)[component] > cINT64_MAX))
626                     return false;
627                 val = static_cast<int64_t>((*m_pVec3F)[component]);
628                 break;
629             }
630             case cDTVec3I:
631             {
632                 if (component > 2)
633                     return false;
634                 val = (*m_pVec3I)[component];
635                 break;
636             }
637             case cDTBlob:
638             {
639                 if (component >= m_pBlob->size())
640                     return false;
641                 val = m_pBlob->at(component);
642                 break;
643             }
644             case cDTVoidPtr:
645             {
646                 val = reinterpret_cast<int64_t>(m_pPtr);
647                 break;
648             }
649             case cDTJSONDoc:
650             {
651                 if (m_pJSONDoc->is_node())
652                     return false;
653                 val = m_pJSONDoc->as_int64();
654                 break;
655             }
656             default:
657             {
658                 VOGL_ASSERT_ALWAYS;
659                 return false;
660             }
661         }
662         return true;
663     }
664
665     bool value::get_uint_or_fail(uint &val, uint component) const
666     {
667         uint64_t u64_val;
668         bool success = get_uint64_or_fail(u64_val, component);
669         if (u64_val > cUINT32_MAX)
670             return false;
671         val = static_cast<uint>(u64_val);
672         return success;
673     }
674
675     bool value::get_uint64_or_fail(uint64_t &val, uint component) const
676     {
677         switch (m_type)
678         {
679             case cDTInvalid:
680             {
681                 return false;
682             }
683             case cDTString:
684             {
685                 const char *p = m_pStr->get_ptr();
686                 return string_ptr_to_uint64(p, val);
687             }
688             case cDTBool:
689             {
690                 val = m_bool;
691                 break;
692             }
693             case cDTInt8:
694             {
695                 if (m_int8 < 0)
696                     return false;
697                 val = m_int8;
698                 break;
699             }
700             case cDTUInt8:
701             {
702                 val = m_uint8;
703                 break;
704             }
705             case cDTInt16:
706             {
707                 if (m_int16 < 0)
708                     return false;
709                 val = static_cast<uint64_t>(m_int16);
710                 break;
711             }
712             case cDTUInt16:
713             {
714                 val = m_uint16;
715                 break;
716             }
717             case cDTInt:
718             {
719                 if (m_int < 0)
720                     return false;
721                 val = static_cast<uint64_t>(m_int);
722                 break;
723             }
724             case cDTStringHash:
725             case cDTUInt:
726             {
727                 val = m_uint;
728                 break;
729             }
730             case cDTInt64:
731             {
732                 if (m_int64 < 0)
733                     return false;
734                 val = static_cast<uint64_t>(m_int64);
735                 break;
736             }
737             case cDTUInt64:
738             {
739                 val = static_cast<uint64_t>(m_uint64);
740                 break;
741             }
742             case cDTFloat:
743             {
744                 if ((m_float < 0) || (m_float > cUINT64_MAX))
745                     return false;
746                 val = static_cast<uint64_t>(m_float);
747                 break;
748             }
749             case cDTDouble:
750             {
751                 if ((m_double < 0) || (m_double > cUINT64_MAX))
752                     return false;
753                 val = static_cast<uint64_t>(m_double);
754                 break;
755             }
756             case cDTVec3F:
757             {
758                 if (component > 2)
759                     return false;
760                 if (((*m_pVec3F)[component] < 0) || ((*m_pVec3F)[component] > cUINT64_MAX))
761                 {
762                     return false;
763                 }
764                 val = static_cast<uint64_t>((*m_pVec3F)[component]);
765                 break;
766             }
767             case cDTVec3I:
768             {
769                 if (component > 2)
770                     return false;
771                 if ((*m_pVec3I)[component] < 0)
772                 {
773                     return false;
774                 }
775                 val = static_cast<uint64_t>((*m_pVec3I)[component]);
776                 break;
777             }
778             case cDTBlob:
779             {
780                 if (component >= m_pBlob->size())
781                     return false;
782                 val = m_pBlob->at(component);
783                 break;
784             }
785             case cDTVoidPtr:
786             {
787                 val = reinterpret_cast<uint64_t>(m_pPtr);
788                 return false;
789             }
790             case cDTJSONDoc:
791             {
792                 if (m_pJSONDoc->is_node())
793                     return false;
794                 val = m_pJSONDoc->as_uint64();
795                 break;
796             }
797             default:
798                 VOGL_ASSERT_ALWAYS;
799                 break;
800         }
801         return true;
802     }
803
804     bool value::get_bool_or_fail(bool &val, uint component) const
805     {
806         switch (m_type)
807         {
808             case cDTInvalid:
809             {
810                 return false;
811             }
812             case cDTString:
813             {
814                 const char *p = m_pStr->get_ptr();
815                 return string_ptr_to_bool(p, val);
816             }
817             case cDTBool:
818             {
819                 val = m_bool;
820                 break;
821             }
822             case cDTInt8:
823             case cDTUInt8:
824             {
825                 val = (m_uint8 != 0);
826                 break;
827             }
828             case cDTInt16:
829             case cDTUInt16:
830             {
831                 val = (m_uint16 != 0);
832                 break;
833             }
834             case cDTStringHash:
835             case cDTInt:
836             case cDTUInt:
837             {
838                 val = (m_uint != 0);
839                 break;
840             }
841             case cDTInt64:
842             case cDTUInt64:
843             {
844                 val = (m_uint64 != 0);
845                 break;
846             }
847             case cDTFloat:
848             {
849                 val = (m_float != 0);
850                 break;
851             }
852             case cDTDouble:
853             {
854                 val = (m_double != 0);
855                 break;
856             }
857             case cDTVec3F:
858             {
859                 if (component > 2)
860                     return false;
861                 val = ((*m_pVec3F)[component] != 0);
862                 break;
863             }
864             case cDTVec3I:
865             {
866                 if (component > 2)
867                     return false;
868                 val = ((*m_pVec3I)[component] != 0);
869                 break;
870             }
871             case cDTBlob:
872             {
873                 if (component >= m_pBlob->size())
874                     return false;
875                 val = m_pBlob->at(component) != 0;
876                 break;
877             }
878             case cDTVoidPtr:
879             {
880                 val = (m_pPtr != NULL);
881                 break;
882             }
883             case cDTJSONDoc:
884             {
885                 if (m_pJSONDoc->is_node())
886                     return false;
887                 val = m_pJSONDoc->as_bool();
888                 break;
889             }
890             default:
891                 VOGL_ASSERT_ALWAYS;
892                 val = false;
893                 break;
894         }
895         return true;
896     }
897
898     bool value::get_double_or_fail(double &val, uint component) const
899     {
900         switch (m_type)
901         {
902             case cDTInvalid:
903             {
904                 return false;
905             }
906             case cDTString:
907             {
908                 const char *p = m_pStr->get_ptr();
909                 return string_ptr_to_double(p, val);
910             }
911             case cDTBool:
912             {
913                 val = m_bool;
914                 break;
915             }
916             case cDTInt8:
917             {
918                 val = static_cast<double>(m_int8);
919                 break;
920             }
921             case cDTUInt8:
922             {
923                 val = static_cast<double>(m_uint8);
924                 break;
925             }
926             case cDTInt16:
927             {
928                 val = static_cast<double>(m_int16);
929                 break;
930             }
931             case cDTUInt16:
932             {
933                 val = static_cast<double>(m_uint16);
934                 break;
935             }
936             case cDTInt:
937             {
938                 val = static_cast<double>(m_int);
939                 break;
940             }
941             case cDTStringHash:
942             case cDTUInt:
943             {
944                 val = static_cast<double>(m_uint);
945                 break;
946             }
947             case cDTInt64:
948             {
949                 val = static_cast<double>(m_int64);
950                 break;
951             }
952             case cDTUInt64:
953             {
954                 val = static_cast<double>(m_uint64);
955                 break;
956             }
957             case cDTFloat:
958             {
959                 val = m_float;
960                 break;
961             }
962             case cDTDouble:
963             {
964                 val = m_double;
965                 break;
966             }
967             case cDTVec3F:
968             {
969                 if (component > 2)
970                     return false;
971                 val = (*m_pVec3F)[component];
972                 break;
973             }
974             case cDTVec3I:
975             {
976                 if (component > 2)
977                     return false;
978                 val = static_cast<double>((*m_pVec3I)[component]);
979                 break;
980             }
981             case cDTBlob:
982             {
983                 if (component >= m_pBlob->size())
984                     return false;
985                 val = static_cast<double>(m_pBlob->at(component));
986                 break;
987             }
988             case cDTVoidPtr:
989             {
990                 val = 0;
991                 break;
992             }
993             case cDTJSONDoc:
994             {
995                 if (m_pJSONDoc->is_node())
996                     return false;
997                 val = m_pJSONDoc->as_double();
998                 break;
999             }
1000             default:
1001                 VOGL_ASSERT_ALWAYS;
1002                 return false;
1003         }
1004         return true;
1005     }
1006
1007     bool value::get_float_or_fail(float &val, uint component) const
1008     {
1009         double dbl_val;
1010         bool success = get_double_or_fail(dbl_val, component);
1011
1012         if ((dbl_val < -FLT_MAX) || (dbl_val > FLT_MAX))
1013         {
1014             dbl_val = 0;
1015             success = false;
1016         }
1017
1018         val = static_cast<float>(dbl_val);
1019         return success;
1020     }
1021
1022     bool value::get_vec3F_or_fail(vec3F &val) const
1023     {
1024         switch (m_type)
1025         {
1026             case cDTInvalid:
1027             {
1028                 return false;
1029             }
1030             case cDTString:
1031             {
1032                 const char *p = m_pStr->get_ptr();
1033                 float x = 0, y = 0, z = 0;
1034 #ifdef _MSC_VER
1035                 if (sscanf_s(p, "%f,%f,%f", &x, &y, &z) == 3)
1036 #else
1037                 if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
1038 #endif
1039                 {
1040                     val.set(x, y, z);
1041                     return true;
1042                 }
1043                 else
1044                 {
1045                     return false;
1046                 }
1047             }
1048             case cDTBool:
1049             {
1050                 val.set(m_bool);
1051                 break;
1052             }
1053             case cDTUInt8:
1054             {
1055                 val.set(static_cast<float>(m_uint8));
1056                 break;
1057             }
1058             case cDTInt16:
1059             {
1060                 val.set(static_cast<float>(m_int16));
1061                 break;
1062             }
1063             case cDTUInt16:
1064             {
1065                 val.set(static_cast<float>(m_uint16));
1066                 break;
1067             }
1068             case cDTInt:
1069             {
1070                 val.set(static_cast<float>(m_int));
1071                 break;
1072             }
1073             case cDTStringHash:
1074             case cDTUInt:
1075             {
1076                 val.set(static_cast<float>(m_uint));
1077                 break;
1078             }
1079             case cDTInt64:
1080             {
1081                 val.set(static_cast<float>(m_int64));
1082                 break;
1083             }
1084             case cDTUInt64:
1085             {
1086                 val.set(static_cast<float>(m_uint64));
1087                 break;
1088             }
1089             case cDTFloat:
1090             {
1091                 val.set(m_float);
1092                 break;
1093             }
1094             case cDTDouble:
1095             {
1096                 val.set(static_cast<float>(m_double));
1097                 break;
1098             }
1099             case cDTVec3F:
1100             {
1101                 val = *m_pVec3F;
1102                 break;
1103             }
1104             case cDTVec3I:
1105             {
1106                 val.set(static_cast<float>((*m_pVec3I)[0]), static_cast<float>((*m_pVec3I)[1]), static_cast<float>((*m_pVec3I)[2]));
1107                 break;
1108             }
1109             case cDTBlob:
1110             {
1111                 if (!m_pBlob->size())
1112                     return false;
1113                 val.set(static_cast<float>(m_pBlob->at(0)));
1114                 break;
1115             }
1116             case cDTVoidPtr:
1117             {
1118                 val.clear();
1119                 break;
1120             }
1121             case cDTJSONDoc:
1122             {
1123                 if (m_pJSONDoc->is_node())
1124                     return false;
1125                 val.set(m_pJSONDoc->as_double());
1126                 break;
1127             }
1128             default:
1129                 VOGL_ASSERT_ALWAYS;
1130                 return false;
1131         }
1132         return true;
1133     }
1134
1135     bool value::get_vec3I_or_fail(vec3I &val) const
1136     {
1137         switch (m_type)
1138         {
1139             case cDTInvalid:
1140             {
1141                 return false;
1142             }
1143             case cDTString:
1144             {
1145                 const char *p = m_pStr->get_ptr();
1146                 float x = 0, y = 0, z = 0;
1147 #ifdef _MSC_VER
1148                 if (sscanf_s(p, "%f,%f,%f", &x, &y, &z) == 3)
1149 #else
1150                 if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
1151 #endif
1152                 {
1153                     if ((x < INT_MIN) || (x > INT_MAX) || (y < INT_MIN) || (y > INT_MAX) || (z < INT_MIN) || (z > INT_MAX))
1154                         return false;
1155                     val.set((int)x, (int)y, (int)z);
1156                     return true;
1157                 }
1158                 else
1159                     return false;
1160
1161                 break;
1162             }
1163             case cDTBool:
1164             {
1165                 val.set(m_bool);
1166                 break;
1167             }
1168             case cDTUInt8:
1169             {
1170                 val.set(m_uint8);
1171                 break;
1172             }
1173             case cDTInt16:
1174             {
1175                 val.set(m_int16);
1176                 break;
1177             }
1178             case cDTUInt16:
1179             {
1180                 val.set(m_uint16);
1181                 break;
1182             }
1183             case cDTInt:
1184             {
1185                 val.set(m_int);
1186                 break;
1187             }
1188             case cDTStringHash:
1189             case cDTUInt:
1190             {
1191                 if (m_uint > static_cast<uint>(cINT32_MAX))
1192                     return false;
1193                 val.set(m_uint);
1194                 break;
1195             }
1196             case cDTInt64:
1197             {
1198                 if ((m_int64 < cINT32_MIN) || (m_int64 > cINT32_MAX))
1199                     return false;
1200                 val.set(static_cast<int>(m_int64));
1201                 break;
1202             }
1203             case cDTUInt64:
1204             {
1205                 if (m_uint64 > static_cast<uint64_t>(cINT32_MAX))
1206                     return false;
1207                 val.set(static_cast<int>(m_uint64));
1208                 break;
1209             }
1210             case cDTFloat:
1211             {
1212                 val.set(static_cast<int>(m_float));
1213                 break;
1214             }
1215             case cDTDouble:
1216             {
1217                 val.set(static_cast<int>(m_double));
1218                 break;
1219             }
1220             case cDTVec3F:
1221             {
1222                 val.set((int)(*m_pVec3F)[0], (int)(*m_pVec3F)[1], (int)(*m_pVec3F)[2]);
1223                 break;
1224             }
1225             case cDTVec3I:
1226             {
1227                 val = *m_pVec3I;
1228                 break;
1229             }
1230             case cDTBlob:
1231             {
1232                 if (!m_pBlob->size())
1233                     return false;
1234                 val.set(m_pBlob->at(0));
1235                 break;
1236             }
1237             case cDTVoidPtr:
1238             {
1239                 val.clear();
1240                 break;
1241             }
1242             case cDTJSONDoc:
1243             {
1244                 if (m_pJSONDoc->is_node())
1245                     return false;
1246                 val.set(m_pJSONDoc->as_int());
1247                 break;
1248             }
1249             default:
1250                 VOGL_ASSERT_ALWAYS;
1251                 return false;
1252         }
1253         return true;
1254     }
1255
1256     bool value::get_string_hash_or_fail(string_hash &hash) const
1257     {
1258         if (m_type == cDTString)
1259         {
1260             // Hash the string
1261             hash.set(m_pStr->get_ptr());
1262             return true;
1263         }
1264         else if (m_type == cDTStringHash)
1265         {
1266             hash = get_string_hash_ref();
1267             return true;
1268         }
1269         else if (m_type == cDTBlob)
1270         {
1271             // Just hash the blob and hope for the best
1272             hash.set(reinterpret_cast<const char *>(m_pBlob->get_ptr()), m_pBlob->size());
1273             return true;
1274         }
1275         else if (m_type == cDTJSONDoc)
1276         {
1277             // This is slow but it's better than nothing.
1278             uint8_vec data;
1279             m_pJSONDoc->binary_serialize(data);
1280             hash.set(reinterpret_cast<const char *>(data.get_ptr()), data.size());
1281             return true;
1282         }
1283
1284         // Convert to uint32 and hope for the best
1285         uint val;
1286         bool success = get_uint_or_fail(val, 0);
1287         if (!success)
1288             return false;
1289
1290         hash.set_hash(val);
1291         return true;
1292     }
1293
1294     uint value::get_serialize_size(bool serialize_user_data) const
1295     {
1296         uint size = sizeof(uint8);
1297
1298         if (serialize_user_data)
1299             size += sizeof(m_user_data);
1300
1301         switch (m_type)
1302         {
1303             case cDTString:
1304             {
1305                 size += m_pStr->get_serialize_size();
1306                 break;
1307             }
1308             case cDTBool:
1309             {
1310                 size += sizeof(m_bool);
1311                 break;
1312             }
1313             case cDTUInt8:
1314             {
1315                 size += sizeof(m_uint8);
1316                 break;
1317             }
1318             case cDTInt16:
1319             case cDTUInt16:
1320             {
1321                 size += sizeof(m_uint16);
1322                 break;
1323             }
1324             case cDTStringHash:
1325             case cDTInt:
1326             case cDTUInt:
1327             case cDTFloat:
1328             {
1329                 size += sizeof(m_uint);
1330                 break;
1331             }
1332             case cDTInt64:
1333             case cDTUInt64:
1334             case cDTDouble:
1335             case cDTVoidPtr:
1336             {
1337                 size += sizeof(m_uint64);
1338                 break;
1339             }
1340             case cDTVec3F:
1341             {
1342                 size += sizeof(vec3F);
1343                 break;
1344             }
1345             case cDTVec3I:
1346             {
1347                 size += sizeof(vec3I);
1348                 break;
1349             }
1350             case cDTBlob:
1351             {
1352                 size += sizeof(uint) + m_pBlob->size();
1353                 break;
1354             }
1355             case cDTJSONDoc:
1356             {
1357                 // TODO: This binary serializes the sucker and tosses the data to get the serialization size.
1358                 uint8_vec data;
1359                 m_pJSONDoc->binary_serialize(data);
1360                 size += sizeof(uint) + data.size();
1361                 break;
1362             }
1363             default:
1364                 VOGL_ASSERT_ALWAYS;
1365                 break;
1366         }
1367
1368         return size;
1369     }
1370
1371     int value::serialize(void *pBuf, uint buf_size, bool little_endian, bool serialize_user_data) const
1372     {
1373         uint buf_left = buf_size;
1374
1375         uint8 t = (uint8)m_type;
1376         if (!utils::write_obj(t, pBuf, buf_left, little_endian))
1377             return -1;
1378
1379         if (serialize_user_data)
1380         {
1381             if (!utils::write_obj(m_user_data, pBuf, buf_left, little_endian))
1382                 return -1;
1383         }
1384
1385         switch (m_type)
1386         {
1387             case cDTString:
1388             {
1389                 int bytes_written = m_pStr->serialize(pBuf, buf_left, little_endian);
1390                 if (bytes_written < 0)
1391                     return -1;
1392
1393                 pBuf = static_cast<uint8 *>(pBuf) + bytes_written;
1394                 buf_left -= bytes_written;
1395
1396                 break;
1397             }
1398             case cDTBool:
1399             {
1400                 if (!utils::write_obj(m_bool, pBuf, buf_left, little_endian))
1401                     return -1;
1402                 break;
1403             }
1404             case cDTUInt8:
1405             {
1406                 if (!utils::write_obj(m_uint8, pBuf, buf_left, little_endian))
1407                     return -1;
1408                 break;
1409             }
1410             case cDTInt16:
1411             case cDTUInt16:
1412             {
1413                 if (!utils::write_obj(m_uint16, pBuf, buf_left, little_endian))
1414                     return -1;
1415                 break;
1416             }
1417             case cDTStringHash:
1418             case cDTInt:
1419             case cDTUInt:
1420             case cDTFloat:
1421             {
1422                 if (!utils::write_obj(m_uint, pBuf, buf_left, little_endian))
1423                     return -1;
1424                 break;
1425             }
1426             case cDTInt64:
1427             case cDTUInt64:
1428             case cDTDouble:
1429             case cDTVoidPtr:
1430             {
1431                 if (!utils::write_obj(m_uint64, pBuf, buf_left, little_endian))
1432                     return -1;
1433                 break;
1434             }
1435             case cDTVec3F:
1436             {
1437                 for (uint i = 0; i < 3; i++)
1438                     if (!utils::write_obj((*m_pVec3F)[i], pBuf, buf_left, little_endian))
1439                         return -1;
1440                 break;
1441             }
1442             case cDTVec3I:
1443             {
1444                 for (uint i = 0; i < 3; i++)
1445                     if (!utils::write_obj((*m_pVec3I)[i], pBuf, buf_left, little_endian))
1446                         return -1;
1447                 break;
1448             }
1449             case cDTBlob:
1450             {
1451                 uint size = m_pBlob->size();
1452
1453                 if (buf_left < (size + sizeof(uint)))
1454                     return -1;
1455
1456                 if (!utils::write_obj(size, pBuf, buf_left, little_endian))
1457                     return -1;
1458
1459                 if (size)
1460                 {
1461                     memcpy(pBuf, m_pBlob->get_ptr(), size);
1462                     pBuf = static_cast<uint8 *>(pBuf) + size;
1463                     buf_left -= size;
1464                 }
1465
1466                 break;
1467             }
1468             case cDTJSONDoc:
1469             {
1470                 uint8_vec data;
1471                 m_pJSONDoc->binary_serialize(data);
1472
1473                 uint size = data.size();
1474
1475                 if (buf_left < (size + sizeof(uint)))
1476                     return -1;
1477
1478                 if (!utils::write_obj(size, pBuf, buf_left, little_endian))
1479                     return -1;
1480
1481                 if (size)
1482                 {
1483                     memcpy(pBuf, data.get_ptr(), size);
1484                     pBuf = static_cast<uint8 *>(pBuf) + size;
1485                     buf_left -= size;
1486                 }
1487
1488                 break;
1489             }
1490             default:
1491                 VOGL_ASSERT_ALWAYS;
1492                 break;
1493         }
1494
1495         return buf_size - buf_left;
1496     }
1497
1498     int value::deserialize(const void *pBuf, uint buf_size, bool little_endian, bool serialize_user_data)
1499     {
1500         uint buf_left = buf_size;
1501
1502         uint8 t;
1503         if (!utils::read_obj(t, pBuf, buf_left, little_endian))
1504             return -1;
1505
1506         if (t >= cDTTotal)
1507             return -1;
1508
1509         if (serialize_user_data)
1510         {
1511             if (!utils::read_obj(m_user_data, pBuf, buf_left, little_endian))
1512                 return -1;
1513             m_flags |= cFlagsHasUserData;
1514         }
1515         else
1516         {
1517             m_flags &= ~cFlagsHasUserData;
1518         }
1519
1520         switch (t)
1521         {
1522             case cDTString:
1523             {
1524                 change_type(cDTString);
1525
1526                 int bytes_read = m_pStr->deserialize(pBuf, buf_left, little_endian);
1527                 if (bytes_read < 0)
1528                     return -1;
1529
1530                 pBuf = static_cast<const uint8 *>(pBuf) + bytes_read;
1531                 buf_left -= bytes_read;
1532
1533                 break;
1534             }
1535             case cDTBool:
1536             {
1537                 change_type(static_cast<value_data_type>(t));
1538
1539                 if (!utils::read_obj(m_bool, pBuf, buf_left, little_endian))
1540                     return -1;
1541                 break;
1542             }
1543             case cDTUInt8:
1544             {
1545                 change_type(static_cast<value_data_type>(t));
1546
1547                 if (!utils::read_obj(m_uint8, pBuf, buf_left, little_endian))
1548                     return -1;
1549                 break;
1550             }
1551             case cDTInt16:
1552             case cDTUInt16:
1553             {
1554                 change_type(static_cast<value_data_type>(t));
1555
1556                 if (!utils::read_obj(m_uint16, pBuf, buf_left, little_endian))
1557                     return -1;
1558                 break;
1559             }
1560             case cDTStringHash:
1561             case cDTInt:
1562             case cDTUInt:
1563             case cDTFloat:
1564             {
1565                 change_type(static_cast<value_data_type>(t));
1566
1567                 if (!utils::read_obj(m_uint, pBuf, buf_left, little_endian))
1568                     return -1;
1569                 break;
1570             }
1571             case cDTInt64:
1572             case cDTUInt64:
1573             case cDTDouble:
1574             case cDTVoidPtr:
1575             {
1576                 change_type(static_cast<value_data_type>(t));
1577
1578                 if (!utils::read_obj(m_uint64, pBuf, buf_left, little_endian))
1579                     return -1;
1580                 break;
1581             }
1582             case cDTVec3F:
1583             {
1584                 change_type(cDTVec3F);
1585
1586                 for (uint i = 0; i < 3; i++)
1587                     if (!utils::read_obj((*m_pVec3F)[i], pBuf, buf_left, little_endian))
1588                         return -1;
1589                 break;
1590             }
1591             case cDTVec3I:
1592             {
1593                 change_type(cDTVec3I);
1594
1595                 for (uint i = 0; i < 3; i++)
1596                     if (!utils::read_obj((*m_pVec3I)[i], pBuf, buf_left, little_endian))
1597                         return -1;
1598                 break;
1599             }
1600             case cDTBlob:
1601             {
1602                 change_type(cDTBlob);
1603
1604                 uint size = 0;
1605                 if (!utils::read_obj(size, pBuf, buf_left, little_endian))
1606                     return -1;
1607
1608                 if (buf_left < size)
1609                     return -1;
1610
1611                 if (!m_pBlob->try_resize(size))
1612                     return -1;
1613
1614                 if (size)
1615                 {
1616                     memcpy(m_pBlob->get_ptr(), pBuf, size);
1617
1618                     pBuf = static_cast<const uint8 *>(pBuf) + size;
1619                     buf_left -= size;
1620                 }
1621
1622                 break;
1623             }
1624             case cDTJSONDoc:
1625             {
1626                 change_type(cDTJSONDoc);
1627
1628                 uint size = 0;
1629                 if (!utils::read_obj(size, pBuf, buf_left, little_endian))
1630                     return -1;
1631
1632                 if (buf_left < size)
1633                     return -1;
1634
1635                 if (!m_pJSONDoc->binary_deserialize(static_cast<const uint8 *>(pBuf), size))
1636                     return -1;
1637
1638                 pBuf = static_cast<const uint8 *>(pBuf) + size;
1639                 buf_left -= size;
1640
1641                 break;
1642             }
1643             default:
1644                 VOGL_ASSERT_ALWAYS;
1645                 clear();
1646                 return -1;
1647         }
1648
1649         return buf_size - buf_left;
1650     }
1651
1652 } // namespace vogl