Merge pull request #2948 from ace20022/blu_lang_fix
[vuplus_xbmc] / xbmc / utils / Variant.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sstream>
24
25 #include "Variant.h"
26
27 #ifndef strtoll
28 #ifdef TARGET_WINDOWS
29 #define strtoll  _strtoi64
30 #define strtoull _strtoui64
31 #define wcstoll  _wcstoi64
32 #define wcstoull _wcstoui64
33 #else // TARGET_WINDOWS
34 #define strtoll(str, endptr, base)  (int64_t)strtod(str, endptr)
35 #define strtoull(str, endptr, base) (uint64_t)strtod(str, endptr)
36 #define wcstoll(str, endptr, base)  (int64_t)wcstod(str, endptr)
37 #define wcstoull(str, endptr, base) (uint64_t)wcstod(str, endptr)
38 #endif // TARGET_WINDOWS
39 #endif // strtoll
40
41 using namespace std;
42
43 string trimRight(const string &str)
44 {
45   string tmp = str;
46   // find_last_not_of will return string::npos (which is defined as -1)
47   // or a value between 0 and size() - 1 => find_last_not_of() + 1 will
48   // always result in a valid index between 0 and size()
49   tmp.erase(tmp.find_last_not_of(" \n\r\t") + 1);
50
51   return tmp;
52 }
53
54 wstring trimRight(const wstring &str)
55 {
56   wstring tmp = str;
57   // find_last_not_of will return string::npos (which is defined as -1)
58   // or a value between 0 and size() - 1 => find_last_not_of() + 1 will
59   // always result in a valid index between 0 and size()
60   tmp.erase(tmp.find_last_not_of(L" \n\r\t") + 1);
61
62   return tmp;
63 }
64
65 int64_t str2int64(const string &str, int64_t fallback /* = 0 */)
66 {
67   char *end = NULL;
68   string tmp = trimRight(str);
69   int64_t result = strtoll(tmp.c_str(), &end, 0);
70   if (end == NULL || *end == '\0')
71     return result;
72
73   return fallback;
74 }
75
76 int64_t str2int64(const wstring &str, int64_t fallback /* = 0 */)
77 {
78   wchar_t *end = NULL;
79   wstring tmp = trimRight(str);
80   int64_t result = wcstoll(tmp.c_str(), &end, 0);
81   if (end == NULL || *end == '\0')
82     return result;
83
84   return fallback;
85 }
86
87 uint64_t str2uint64(const string &str, uint64_t fallback /* = 0 */)
88 {
89   char *end = NULL;
90   string tmp = trimRight(str);
91   uint64_t result = strtoull(tmp.c_str(), &end, 0);
92   if (end == NULL || *end == '\0')
93     return result;
94
95   return fallback;
96 }
97
98 uint64_t str2uint64(const wstring &str, uint64_t fallback /* = 0 */)
99 {
100   wchar_t *end = NULL;
101   wstring tmp = trimRight(str);
102   uint64_t result = wcstoull(tmp.c_str(), &end, 0);
103   if (end == NULL || *end == '\0')
104     return result;
105
106   return fallback;
107 }
108
109 double str2double(const string &str, double fallback /* = 0.0 */)
110 {
111   char *end = NULL;
112   string tmp = trimRight(str);
113   double result = strtod(tmp.c_str(), &end);
114   if (end == NULL || *end == '\0')
115     return result;
116
117   return fallback;
118 }
119
120 double str2double(const wstring &str, double fallback /* = 0.0 */)
121 {
122   wchar_t *end = NULL;
123   wstring tmp = trimRight(str);
124   double result = wcstod(tmp.c_str(), &end);
125   if (end == NULL || *end == '\0')
126     return result;
127
128   return fallback;
129 }
130
131 CVariant CVariant::ConstNullVariant = CVariant::VariantTypeConstNull;
132
133 CVariant::CVariant(VariantType type)
134 {
135   m_type = type;
136
137   switch (type)
138   {
139     case VariantTypeInteger:
140       m_data.integer = 0;
141       break;
142     case VariantTypeUnsignedInteger:
143       m_data.unsignedinteger = 0;
144       break;
145     case VariantTypeBoolean:
146       m_data.boolean = false;
147       break;
148     case VariantTypeDouble:
149       m_data.dvalue = 0.0;
150       break;
151     case VariantTypeString:
152       m_data.string = new string();
153       break;
154     case VariantTypeWideString:
155       m_data.wstring = new wstring();
156       break;
157     case VariantTypeArray:
158       m_data.array = new VariantArray();
159       break;
160     case VariantTypeObject:
161       m_data.map = new VariantMap();
162       break;
163     default:
164       memset(&m_data, 0, sizeof(m_data));
165       break;
166   }
167 }
168
169 CVariant::CVariant(int integer)
170 {
171   m_type = VariantTypeInteger;
172   m_data.integer = integer;
173 }
174
175 CVariant::CVariant(int64_t integer)
176 {
177   m_type = VariantTypeInteger;
178   m_data.integer = integer;
179 }
180
181 CVariant::CVariant(unsigned int unsignedinteger)
182 {
183   m_type = VariantTypeUnsignedInteger;
184   m_data.unsignedinteger = unsignedinteger;
185 }
186
187 CVariant::CVariant(uint64_t unsignedinteger)
188 {
189   m_type = VariantTypeUnsignedInteger;
190   m_data.unsignedinteger = unsignedinteger;
191 }
192
193 CVariant::CVariant(double value)
194 {
195   m_type = VariantTypeDouble;
196   m_data.dvalue = value;
197 }
198
199 CVariant::CVariant(float value)
200 {
201   m_type = VariantTypeDouble;
202   m_data.dvalue = (double)value;
203 }
204
205 CVariant::CVariant(bool boolean)
206 {
207   m_type = VariantTypeBoolean;
208   m_data.boolean = boolean;
209 }
210
211 CVariant::CVariant(const char *str)
212 {
213   m_type = VariantTypeString;
214   m_data.string = new string(str);
215 }
216
217 CVariant::CVariant(const char *str, unsigned int length)
218 {
219   m_type = VariantTypeString;
220   m_data.string = new string(str, length);
221 }
222
223 CVariant::CVariant(const string &str)
224 {
225   m_type = VariantTypeString;
226   m_data.string = new string(str);
227 }
228
229 CVariant::CVariant(const wchar_t *str)
230 {
231   m_type = VariantTypeWideString;
232   m_data.wstring = new wstring(str);
233 }
234
235 CVariant::CVariant(const wchar_t *str, unsigned int length)
236 {
237   m_type = VariantTypeWideString;
238   m_data.wstring = new wstring(str, length);
239 }
240
241 CVariant::CVariant(const wstring &str)
242 {
243   m_type = VariantTypeWideString;
244   m_data.wstring = new wstring(str);
245 }
246
247 CVariant::CVariant(const std::vector<std::string> &strArray)
248 {
249   m_type = VariantTypeArray;
250   m_data.array = new VariantArray;
251   m_data.array->reserve(strArray.size());
252   for (unsigned int index = 0; index < strArray.size(); index++)
253     m_data.array->push_back(strArray.at(index));
254 }
255
256 CVariant::CVariant(const std::map<std::string, std::string> &strMap)
257 {
258   m_type = VariantTypeObject;
259   m_data.map = new VariantMap;
260   for (std::map<std::string, std::string>::const_iterator it = strMap.begin(); it != strMap.end(); it++)
261     m_data.map->insert(make_pair(it->first, CVariant(it->second)));
262 }
263
264 CVariant::CVariant(const std::map<std::string, CVariant> &variantMap)
265 {
266   m_type = VariantTypeObject;
267   m_data.map = new VariantMap(variantMap.begin(), variantMap.end());
268 }
269
270 CVariant::CVariant(const CVariant &variant)
271 {
272   m_type = VariantTypeNull;
273   *this = variant;
274 }
275
276 CVariant::~CVariant()
277 {
278   cleanup();
279 }
280
281 void CVariant::cleanup()
282 {
283   if (m_type == VariantTypeString)
284     delete m_data.string;
285   else if (m_type == VariantTypeWideString)
286     delete m_data.wstring;
287   else if (m_type == VariantTypeArray)
288     delete m_data.array;
289   else if (m_type == VariantTypeObject)
290     delete m_data.map;
291   m_type = VariantTypeNull;
292 }
293
294 bool CVariant::isInteger() const
295 {
296   return m_type == VariantTypeInteger;
297 }
298
299 bool CVariant::isUnsignedInteger() const
300 {
301   return m_type == VariantTypeUnsignedInteger;
302 }
303
304 bool CVariant::isBoolean() const
305 {
306   return m_type == VariantTypeBoolean;
307 }
308
309 bool CVariant::isDouble() const
310 {
311   return m_type == VariantTypeDouble;
312 }
313
314 bool CVariant::isString() const
315 {
316   return m_type == VariantTypeString;
317 }
318
319 bool CVariant::isWideString() const
320 {
321   return m_type == VariantTypeWideString;
322 }
323
324 bool CVariant::isArray() const
325 {
326   return m_type == VariantTypeArray;
327 }
328
329 bool CVariant::isObject() const
330 {
331   return m_type == VariantTypeObject;
332 }
333
334 bool CVariant::isNull() const
335 {
336   return m_type == VariantTypeNull || m_type == VariantTypeConstNull;
337 }
338
339 CVariant::VariantType CVariant::type() const
340 {
341   return m_type;
342 }
343
344 int64_t CVariant::asInteger(int64_t fallback) const
345 {
346   switch (m_type)
347   {
348     case VariantTypeInteger:
349       return m_data.integer;
350     case VariantTypeUnsignedInteger:
351       return (int64_t)m_data.unsignedinteger;
352     case VariantTypeDouble:
353       return (int64_t)m_data.dvalue;
354     case VariantTypeString:
355       return str2int64(*m_data.string, fallback);
356     case VariantTypeWideString:
357       return str2int64(*m_data.wstring, fallback);
358     default:
359       return fallback;
360   }
361   
362   return fallback;
363 }
364
365 uint64_t CVariant::asUnsignedInteger(uint64_t fallback) const
366 {
367   switch (m_type)
368   {
369     case VariantTypeUnsignedInteger:
370       return m_data.unsignedinteger;
371     case VariantTypeInteger:
372       return (uint64_t)m_data.integer;
373     case VariantTypeDouble:
374       return (uint64_t)m_data.dvalue;
375     case VariantTypeString:
376       return str2uint64(*m_data.string, fallback);
377     case VariantTypeWideString:
378       return str2uint64(*m_data.wstring, fallback);
379     default:
380       return fallback;
381   }
382   
383   return fallback;
384 }
385
386 double CVariant::asDouble(double fallback) const
387 {
388   switch (m_type)
389   {
390     case VariantTypeDouble:
391       return m_data.dvalue;
392     case VariantTypeInteger:
393       return (double)m_data.integer;
394     case VariantTypeUnsignedInteger:
395       return (double)m_data.unsignedinteger;
396     case VariantTypeString:
397       return str2double(*m_data.string, fallback);
398     case VariantTypeWideString:
399       return str2double(*m_data.wstring, fallback);
400     default:
401       return fallback;
402   }
403   
404   return fallback;
405 }
406
407 float CVariant::asFloat(float fallback) const
408 {
409   switch (m_type)
410   {
411     case VariantTypeDouble:
412       return (float)m_data.dvalue;
413     case VariantTypeInteger:
414       return (float)m_data.integer;
415     case VariantTypeUnsignedInteger:
416       return (float)m_data.unsignedinteger;
417     case VariantTypeString:
418       return (float)str2double(*m_data.string, fallback);
419     case VariantTypeWideString:
420       return (float)str2double(*m_data.wstring, fallback);
421     default:
422       return fallback;
423   }
424   
425   return fallback;
426 }
427
428 bool CVariant::asBoolean(bool fallback) const
429 {
430   switch (m_type)
431   {
432     case VariantTypeBoolean:
433       return m_data.boolean;
434     case VariantTypeInteger:
435       return (m_data.integer != 0);
436     case VariantTypeUnsignedInteger:
437       return (m_data.unsignedinteger != 0);
438     case VariantTypeDouble:
439       return (m_data.dvalue != 0);
440     case VariantTypeString:
441       if (m_data.string->empty() || m_data.string->compare("0") == 0 || m_data.string->compare("false") == 0)
442         return false;
443       return true;
444     case VariantTypeWideString:
445       if (m_data.wstring->empty() || m_data.wstring->compare(L"0") == 0 || m_data.wstring->compare(L"false") == 0)
446         return false;
447       return true;
448     default:
449       return fallback;
450   }
451   
452   return fallback;
453 }
454
455 std::string CVariant::asString(const std::string &fallback /* = "" */) const
456 {
457   switch (m_type)
458   {
459     case VariantTypeString:
460       return *m_data.string;
461     case VariantTypeBoolean:
462       return m_data.boolean ? "true" : "false";
463     case VariantTypeInteger:
464     case VariantTypeUnsignedInteger:
465     case VariantTypeDouble:
466     {
467       std::ostringstream strStream;
468       if (m_type == VariantTypeInteger)
469         strStream << m_data.integer;
470       else if (m_type == VariantTypeUnsignedInteger)
471         strStream << m_data.unsignedinteger;
472       else
473         strStream << m_data.dvalue;
474       return strStream.str();
475     }
476     default:
477       return fallback;
478   }
479   
480   return fallback;
481 }
482
483 std::wstring CVariant::asWideString(const std::wstring &fallback /* = L"" */) const
484 {
485   switch (m_type)
486   {
487     case VariantTypeWideString:
488       return *m_data.wstring;
489     case VariantTypeBoolean:
490       return m_data.boolean ? L"true" : L"false";
491     case VariantTypeInteger:
492     case VariantTypeUnsignedInteger:
493     case VariantTypeDouble:
494     {
495       std::wostringstream strStream;
496       if (m_type == VariantTypeInteger)
497         strStream << m_data.integer;
498       else if (m_type == VariantTypeUnsignedInteger)
499         strStream << m_data.unsignedinteger;
500       else
501         strStream << m_data.dvalue;
502       return strStream.str();
503       break;
504     }
505     default:
506       return fallback;
507   }
508   
509   return fallback;
510 }
511
512 CVariant &CVariant::operator[](const std::string &key)
513 {
514   if (m_type == VariantTypeNull)
515   {
516     m_type = VariantTypeObject;
517     m_data.map = new VariantMap;
518   }
519
520   if (m_type == VariantTypeObject)
521     return (*m_data.map)[key];
522   else
523     return ConstNullVariant;
524 }
525
526 const CVariant &CVariant::operator[](const std::string &key) const
527 {
528   VariantMap::const_iterator it;
529   if (m_type == VariantTypeObject && (it = m_data.map->find(key)) != m_data.map->end())
530     return it->second;
531   else
532     return ConstNullVariant;
533 }
534
535 CVariant &CVariant::operator[](unsigned int position)
536 {
537   if (m_type == VariantTypeArray && size() > position)
538     return m_data.array->at(position);
539   else
540     return ConstNullVariant;
541 }
542
543 const CVariant &CVariant::operator[](unsigned int position) const
544 {
545   if (m_type == VariantTypeArray && size() > position)
546     return m_data.array->at(position);
547   else
548     return ConstNullVariant;
549 }
550
551 CVariant &CVariant::operator=(const CVariant &rhs)
552 {
553   if (m_type == VariantTypeConstNull)
554     return *this;
555
556   cleanup();
557
558   m_type = rhs.m_type;
559
560   switch (m_type)
561   {
562   case VariantTypeInteger:
563     m_data.integer = rhs.m_data.integer;
564     break;
565   case VariantTypeUnsignedInteger:
566     m_data.integer = rhs.m_data.unsignedinteger;
567     break;
568   case VariantTypeBoolean:
569     m_data.boolean = rhs.m_data.boolean;
570     break;
571   case VariantTypeDouble:
572     m_data.dvalue = rhs.m_data.dvalue;
573     break;
574   case VariantTypeString:
575     m_data.string = new string(*rhs.m_data.string);
576     break;
577   case VariantTypeWideString:
578     m_data.wstring = new wstring(*rhs.m_data.wstring);
579     break;
580   case VariantTypeArray:
581     m_data.array = new VariantArray(rhs.m_data.array->begin(), rhs.m_data.array->end());
582     break;
583   case VariantTypeObject:
584     m_data.map = new VariantMap(rhs.m_data.map->begin(), rhs.m_data.map->end());
585     break;
586   default:
587     break;
588   }
589
590   return *this;
591 }
592
593 bool CVariant::operator==(const CVariant &rhs) const
594 {
595   if (m_type == rhs.m_type)
596   {
597     switch (m_type)
598     {
599     case VariantTypeInteger:
600       return m_data.integer == rhs.m_data.integer;
601     case VariantTypeUnsignedInteger:
602       return m_data.unsignedinteger == rhs.m_data.unsignedinteger;
603     case VariantTypeBoolean:
604       return m_data.boolean == rhs.m_data.boolean;
605     case VariantTypeDouble:
606       return m_data.dvalue == rhs.m_data.dvalue;
607     case VariantTypeString:
608       return *m_data.string == *rhs.m_data.string;
609     case VariantTypeWideString:
610       return *m_data.wstring == *rhs.m_data.wstring;
611     case VariantTypeArray:
612       return *m_data.array == *rhs.m_data.array;
613     case VariantTypeObject:
614       return *m_data.map == *rhs.m_data.map;
615     default:
616       break;
617     }
618   }
619
620   return false;
621 }
622
623 void CVariant::push_back(const CVariant &variant)
624 {
625   if (m_type == VariantTypeNull)
626   {
627     m_type = VariantTypeArray;
628     m_data.array = new VariantArray;
629   }
630
631   if (m_type == VariantTypeArray)
632     m_data.array->push_back(variant);
633 }
634
635 void CVariant::append(const CVariant &variant)
636 {
637   push_back(variant);
638 }
639
640 const char *CVariant::c_str() const
641 {
642   if (m_type == VariantTypeString)
643     return m_data.string->c_str();
644   else
645     return NULL;
646 }
647
648 void CVariant::swap(CVariant &rhs)
649 {
650   VariantType  temp_type = m_type;
651   VariantUnion temp_data = m_data;
652
653   m_type = rhs.m_type;
654   m_data = rhs.m_data;
655
656   rhs.m_type = temp_type;
657   rhs.m_data = temp_data;
658 }
659
660 CVariant::iterator_array CVariant::begin_array()
661 {
662   if (m_type == VariantTypeArray)
663     return m_data.array->begin();
664   else
665     return iterator_array();
666 }
667
668 CVariant::const_iterator_array CVariant::begin_array() const
669 {
670   if (m_type == VariantTypeArray)
671     return m_data.array->begin();
672   else
673     return const_iterator_array();
674 }
675
676 CVariant::iterator_array CVariant::end_array()
677 {
678   if (m_type == VariantTypeArray)
679     return m_data.array->end();
680   else
681     return iterator_array();
682 }
683
684 CVariant::const_iterator_array CVariant::end_array() const
685 {
686   if (m_type == VariantTypeArray)
687     return m_data.array->end();
688   else
689     return const_iterator_array();
690 }
691
692 CVariant::iterator_map CVariant::begin_map()
693 {
694   if (m_type == VariantTypeObject)
695     return m_data.map->begin();
696   else
697     return iterator_map();
698 }
699
700 CVariant::const_iterator_map CVariant::begin_map() const
701 {
702   if (m_type == VariantTypeObject)
703     return m_data.map->begin();
704   else
705     return const_iterator_map();
706 }
707
708 CVariant::iterator_map CVariant::end_map()
709 {
710   if (m_type == VariantTypeObject)
711     return m_data.map->end();
712   else
713     return iterator_map();
714 }
715
716 CVariant::const_iterator_map CVariant::end_map() const
717 {
718   if (m_type == VariantTypeObject)
719     return m_data.map->end();
720   else
721     return const_iterator_map();
722 }
723
724 unsigned int CVariant::size() const
725 {
726   if (m_type == VariantTypeObject)
727     return m_data.map->size();
728   else if (m_type == VariantTypeArray)
729     return m_data.array->size();
730   else if (m_type == VariantTypeString)
731     return m_data.string->size();
732   else if (m_type == VariantTypeWideString)
733     return m_data.wstring->size();
734   else
735     return 0;
736 }
737
738 bool CVariant::empty() const
739 {
740   if (m_type == VariantTypeObject)
741     return m_data.map->empty();
742   else if (m_type == VariantTypeArray)
743     return m_data.array->empty();
744   else if (m_type == VariantTypeString)
745     return m_data.string->empty();
746   else if (m_type == VariantTypeWideString)
747     return m_data.wstring->empty();
748   else if (m_type == VariantTypeNull)
749     return true;
750
751   return false;
752 }
753
754 void CVariant::clear()
755 {
756   if (m_type == VariantTypeObject)
757     m_data.map->clear();
758   else if (m_type == VariantTypeArray)
759     m_data.array->clear();
760   else if (m_type == VariantTypeString)
761     m_data.string->clear();
762   else if (m_type == VariantTypeWideString)
763     m_data.wstring->clear();
764 }
765
766 void CVariant::erase(const std::string &key)
767 {
768   if (m_type == VariantTypeNull)
769   {
770     m_type = VariantTypeObject;
771     m_data.map = new VariantMap;
772   }
773   else if (m_type == VariantTypeObject)
774     m_data.map->erase(key);
775 }
776
777 void CVariant::erase(unsigned int position)
778 {
779   if (m_type == VariantTypeNull)
780   {
781     m_type = VariantTypeArray;
782     m_data.array = new VariantArray;
783   }
784
785   if (m_type == VariantTypeArray && position < size())
786     m_data.array->erase(m_data.array->begin() + position);
787 }
788
789 bool CVariant::isMember(const std::string &key) const
790 {
791   if (m_type == VariantTypeObject)
792     return m_data.map->find(key) != m_data.map->end();
793
794   return false;
795 }