diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/utils/Variant.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/utils/Variant.cpp')
-rw-r--r-- | xbmc/utils/Variant.cpp | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/xbmc/utils/Variant.cpp b/xbmc/utils/Variant.cpp new file mode 100644 index 0000000..a9327c9 --- /dev/null +++ b/xbmc/utils/Variant.cpp @@ -0,0 +1,885 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Variant.h" + +#include <stdlib.h> +#include <string.h> +#include <utility> + +#ifndef strtoll +#ifdef TARGET_WINDOWS +#define strtoll _strtoi64 +#define strtoull _strtoui64 +#define wcstoll _wcstoi64 +#define wcstoull _wcstoui64 +#else // TARGET_WINDOWS +#if !defined(TARGET_DARWIN) +#define strtoll(str, endptr, base) (int64_t)strtod(str, endptr) +#define strtoull(str, endptr, base) (uint64_t)strtod(str, endptr) +#define wcstoll(str, endptr, base) (int64_t)wcstod(str, endptr) +#define wcstoull(str, endptr, base) (uint64_t)wcstod(str, endptr) +#endif +#endif // TARGET_WINDOWS +#endif // strtoll + +std::string trimRight(const std::string &str) +{ + std::string tmp = str; + // find_last_not_of will return string::npos (which is defined as -1) + // or a value between 0 and size() - 1 => find_last_not_of() + 1 will + // always result in a valid index between 0 and size() + tmp.erase(tmp.find_last_not_of(" \n\r\t") + 1); + + return tmp; +} + +std::wstring trimRight(const std::wstring &str) +{ + std::wstring tmp = str; + // find_last_not_of will return string::npos (which is defined as -1) + // or a value between 0 and size() - 1 => find_last_not_of() + 1 will + // always result in a valid index between 0 and size() + tmp.erase(tmp.find_last_not_of(L" \n\r\t") + 1); + + return tmp; +} + +int64_t str2int64(const std::string &str, int64_t fallback /* = 0 */) +{ + char *end = NULL; + std::string tmp = trimRight(str); + int64_t result = strtoll(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +int64_t str2int64(const std::wstring &str, int64_t fallback /* = 0 */) +{ + wchar_t *end = NULL; + std::wstring tmp = trimRight(str); + int64_t result = wcstoll(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +uint64_t str2uint64(const std::string &str, uint64_t fallback /* = 0 */) +{ + char *end = NULL; + std::string tmp = trimRight(str); + uint64_t result = strtoull(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +uint64_t str2uint64(const std::wstring &str, uint64_t fallback /* = 0 */) +{ + wchar_t *end = NULL; + std::wstring tmp = trimRight(str); + uint64_t result = wcstoull(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +double str2double(const std::string &str, double fallback /* = 0.0 */) +{ + char *end = NULL; + std::string tmp = trimRight(str); + double result = strtod(tmp.c_str(), &end); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +double str2double(const std::wstring &str, double fallback /* = 0.0 */) +{ + wchar_t *end = NULL; + std::wstring tmp = trimRight(str); + double result = wcstod(tmp.c_str(), &end); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +CVariant::CVariant() + : CVariant(VariantTypeNull) +{ +} + +CVariant CVariant::ConstNullVariant = CVariant::VariantTypeConstNull; +CVariant::VariantArray CVariant::EMPTY_ARRAY; +CVariant::VariantMap CVariant::EMPTY_MAP; + +CVariant::CVariant(VariantType type) +{ + m_type = type; + + switch (type) + { + case VariantTypeInteger: + m_data.integer = 0; + break; + case VariantTypeUnsignedInteger: + m_data.unsignedinteger = 0; + break; + case VariantTypeBoolean: + m_data.boolean = false; + break; + case VariantTypeDouble: + m_data.dvalue = 0.0; + break; + case VariantTypeString: + m_data.string = new std::string(); + break; + case VariantTypeWideString: + m_data.wstring = new std::wstring(); + break; + case VariantTypeArray: + m_data.array = new VariantArray(); + break; + case VariantTypeObject: + m_data.map = new VariantMap(); + break; + default: +#ifndef TARGET_WINDOWS_STORE // this corrupts the heap in Win10 UWP version + memset(&m_data, 0, sizeof(m_data)); +#endif + break; + } +} + +CVariant::CVariant(int integer) +{ + m_type = VariantTypeInteger; + m_data.integer = integer; +} + +CVariant::CVariant(int64_t integer) +{ + m_type = VariantTypeInteger; + m_data.integer = integer; +} + +CVariant::CVariant(unsigned int unsignedinteger) +{ + m_type = VariantTypeUnsignedInteger; + m_data.unsignedinteger = unsignedinteger; +} + +CVariant::CVariant(uint64_t unsignedinteger) +{ + m_type = VariantTypeUnsignedInteger; + m_data.unsignedinteger = unsignedinteger; +} + +CVariant::CVariant(double value) +{ + m_type = VariantTypeDouble; + m_data.dvalue = value; +} + +CVariant::CVariant(float value) +{ + m_type = VariantTypeDouble; + m_data.dvalue = (double)value; +} + +CVariant::CVariant(bool boolean) +{ + m_type = VariantTypeBoolean; + m_data.boolean = boolean; +} + +CVariant::CVariant(const char *str) +{ + m_type = VariantTypeString; + m_data.string = new std::string(str); +} + +CVariant::CVariant(const char *str, unsigned int length) +{ + m_type = VariantTypeString; + m_data.string = new std::string(str, length); +} + +CVariant::CVariant(const std::string &str) +{ + m_type = VariantTypeString; + m_data.string = new std::string(str); +} + +CVariant::CVariant(std::string &&str) +{ + m_type = VariantTypeString; + m_data.string = new std::string(std::move(str)); +} + +CVariant::CVariant(const wchar_t *str) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(str); +} + +CVariant::CVariant(const wchar_t *str, unsigned int length) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(str, length); +} + +CVariant::CVariant(const std::wstring &str) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(str); +} + +CVariant::CVariant(std::wstring &&str) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(std::move(str)); +} + +CVariant::CVariant(const std::vector<std::string> &strArray) +{ + m_type = VariantTypeArray; + m_data.array = new VariantArray; + m_data.array->reserve(strArray.size()); + for (const auto& item : strArray) + m_data.array->push_back(CVariant(item)); +} + +CVariant::CVariant(const std::map<std::string, std::string> &strMap) +{ + m_type = VariantTypeObject; + m_data.map = new VariantMap; + for (std::map<std::string, std::string>::const_iterator it = strMap.begin(); it != strMap.end(); ++it) + m_data.map->insert(make_pair(it->first, CVariant(it->second))); +} + +CVariant::CVariant(const std::map<std::string, CVariant> &variantMap) +{ + m_type = VariantTypeObject; + m_data.map = new VariantMap(variantMap.begin(), variantMap.end()); +} + +CVariant::CVariant(const CVariant &variant) +{ + m_type = VariantTypeNull; + *this = variant; +} + +CVariant::CVariant(CVariant&& rhs) noexcept +{ + //Set this so that operator= don't try and run cleanup + //when we're not initialized. + m_type = VariantTypeNull; + + *this = std::move(rhs); +} + +CVariant::~CVariant() +{ + cleanup(); +} + +void CVariant::cleanup() +{ + switch (m_type) + { + case VariantTypeString: + delete m_data.string; + m_data.string = nullptr; + break; + + case VariantTypeWideString: + delete m_data.wstring; + m_data.wstring = nullptr; + break; + + case VariantTypeArray: + delete m_data.array; + m_data.array = nullptr; + break; + + case VariantTypeObject: + delete m_data.map; + m_data.map = nullptr; + break; + default: + break; + } + m_type = VariantTypeNull; +} + +bool CVariant::isInteger() const +{ + return isSignedInteger() || isUnsignedInteger(); +} + +bool CVariant::isSignedInteger() const +{ + return m_type == VariantTypeInteger; +} + +bool CVariant::isUnsignedInteger() const +{ + return m_type == VariantTypeUnsignedInteger; +} + +bool CVariant::isBoolean() const +{ + return m_type == VariantTypeBoolean; +} + +bool CVariant::isDouble() const +{ + return m_type == VariantTypeDouble; +} + +bool CVariant::isString() const +{ + return m_type == VariantTypeString; +} + +bool CVariant::isWideString() const +{ + return m_type == VariantTypeWideString; +} + +bool CVariant::isArray() const +{ + return m_type == VariantTypeArray; +} + +bool CVariant::isObject() const +{ + return m_type == VariantTypeObject; +} + +bool CVariant::isNull() const +{ + return m_type == VariantTypeNull || m_type == VariantTypeConstNull; +} + +CVariant::VariantType CVariant::type() const +{ + return m_type; +} + +int64_t CVariant::asInteger(int64_t fallback) const +{ + switch (m_type) + { + case VariantTypeInteger: + return m_data.integer; + case VariantTypeUnsignedInteger: + return (int64_t)m_data.unsignedinteger; + case VariantTypeDouble: + return (int64_t)m_data.dvalue; + case VariantTypeString: + return str2int64(*m_data.string, fallback); + case VariantTypeWideString: + return str2int64(*m_data.wstring, fallback); + default: + return fallback; + } + + return fallback; +} + +int32_t CVariant::asInteger32(int32_t fallback) const +{ + return static_cast<int32_t>(asInteger(fallback)); +} + +uint64_t CVariant::asUnsignedInteger(uint64_t fallback) const +{ + switch (m_type) + { + case VariantTypeUnsignedInteger: + return m_data.unsignedinteger; + case VariantTypeInteger: + return (uint64_t)m_data.integer; + case VariantTypeDouble: + return (uint64_t)m_data.dvalue; + case VariantTypeString: + return str2uint64(*m_data.string, fallback); + case VariantTypeWideString: + return str2uint64(*m_data.wstring, fallback); + default: + return fallback; + } + + return fallback; +} + +uint32_t CVariant::asUnsignedInteger32(uint32_t fallback) const +{ + return static_cast<uint32_t>(asUnsignedInteger(fallback)); +} + +double CVariant::asDouble(double fallback) const +{ + switch (m_type) + { + case VariantTypeDouble: + return m_data.dvalue; + case VariantTypeInteger: + return (double)m_data.integer; + case VariantTypeUnsignedInteger: + return (double)m_data.unsignedinteger; + case VariantTypeString: + return str2double(*m_data.string, fallback); + case VariantTypeWideString: + return str2double(*m_data.wstring, fallback); + default: + return fallback; + } + + return fallback; +} + +float CVariant::asFloat(float fallback) const +{ + switch (m_type) + { + case VariantTypeDouble: + return (float)m_data.dvalue; + case VariantTypeInteger: + return (float)m_data.integer; + case VariantTypeUnsignedInteger: + return (float)m_data.unsignedinteger; + case VariantTypeString: + return (float)str2double(*m_data.string, static_cast<double>(fallback)); + case VariantTypeWideString: + return (float)str2double(*m_data.wstring, static_cast<double>(fallback)); + default: + return fallback; + } + + return fallback; +} + +bool CVariant::asBoolean(bool fallback) const +{ + switch (m_type) + { + case VariantTypeBoolean: + return m_data.boolean; + case VariantTypeInteger: + return (m_data.integer != 0); + case VariantTypeUnsignedInteger: + return (m_data.unsignedinteger != 0); + case VariantTypeDouble: + return (m_data.dvalue != 0); + case VariantTypeString: + if (m_data.string->empty() || m_data.string->compare("0") == 0 || m_data.string->compare("false") == 0) + return false; + return true; + case VariantTypeWideString: + if (m_data.wstring->empty() || m_data.wstring->compare(L"0") == 0 || m_data.wstring->compare(L"false") == 0) + return false; + return true; + default: + return fallback; + } + + return fallback; +} + +std::string CVariant::asString(const std::string &fallback /* = "" */) const +{ + switch (m_type) + { + case VariantTypeString: + return *m_data.string; + case VariantTypeBoolean: + return m_data.boolean ? "true" : "false"; + case VariantTypeInteger: + return std::to_string(m_data.integer); + case VariantTypeUnsignedInteger: + return std::to_string(m_data.unsignedinteger); + case VariantTypeDouble: + return std::to_string(m_data.dvalue); + default: + return fallback; + } + + return fallback; +} + +std::wstring CVariant::asWideString(const std::wstring &fallback /* = L"" */) const +{ + switch (m_type) + { + case VariantTypeWideString: + return *m_data.wstring; + case VariantTypeBoolean: + return m_data.boolean ? L"true" : L"false"; + case VariantTypeInteger: + return std::to_wstring(m_data.integer); + case VariantTypeUnsignedInteger: + return std::to_wstring(m_data.unsignedinteger); + case VariantTypeDouble: + return std::to_wstring(m_data.dvalue); + default: + return fallback; + } + + return fallback; +} + +CVariant &CVariant::operator[](const std::string &key) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeObject; + m_data.map = new VariantMap; + } + + if (m_type == VariantTypeObject) + return (*m_data.map)[key]; + else + return ConstNullVariant; +} + +const CVariant &CVariant::operator[](const std::string &key) const +{ + VariantMap::const_iterator it; + if (m_type == VariantTypeObject && (it = m_data.map->find(key)) != m_data.map->end()) + return it->second; + else + return ConstNullVariant; +} + +CVariant &CVariant::operator[](unsigned int position) +{ + if (m_type == VariantTypeArray && size() > position) + return m_data.array->at(position); + else + return ConstNullVariant; +} + +const CVariant &CVariant::operator[](unsigned int position) const +{ + if (m_type == VariantTypeArray && size() > position) + return m_data.array->at(position); + else + return ConstNullVariant; +} + +CVariant &CVariant::operator=(const CVariant &rhs) +{ + if (m_type == VariantTypeConstNull || this == &rhs) + return *this; + + cleanup(); + + m_type = rhs.m_type; + + switch (m_type) + { + case VariantTypeInteger: + m_data.integer = rhs.m_data.integer; + break; + case VariantTypeUnsignedInteger: + m_data.unsignedinteger = rhs.m_data.unsignedinteger; + break; + case VariantTypeBoolean: + m_data.boolean = rhs.m_data.boolean; + break; + case VariantTypeDouble: + m_data.dvalue = rhs.m_data.dvalue; + break; + case VariantTypeString: + m_data.string = new std::string(*rhs.m_data.string); + break; + case VariantTypeWideString: + m_data.wstring = new std::wstring(*rhs.m_data.wstring); + break; + case VariantTypeArray: + m_data.array = new VariantArray(rhs.m_data.array->begin(), rhs.m_data.array->end()); + break; + case VariantTypeObject: + m_data.map = new VariantMap(rhs.m_data.map->begin(), rhs.m_data.map->end()); + break; + default: + break; + } + + return *this; +} + +CVariant& CVariant::operator=(CVariant&& rhs) noexcept +{ + if (m_type == VariantTypeConstNull || this == &rhs) + return *this; + + //Make sure that if we're moved into we don't leak any pointers + if (m_type != VariantTypeNull) + cleanup(); + + m_type = rhs.m_type; + m_data = rhs.m_data; + + //Should be enough to just set m_type here + //but better safe than sorry, could probably lead to coverity warnings + if (rhs.m_type == VariantTypeString) + rhs.m_data.string = nullptr; + else if (rhs.m_type == VariantTypeWideString) + rhs.m_data.wstring = nullptr; + else if (rhs.m_type == VariantTypeArray) + rhs.m_data.array = nullptr; + else if (rhs.m_type == VariantTypeObject) + rhs.m_data.map = nullptr; + + rhs.m_type = VariantTypeNull; + + return *this; +} + +bool CVariant::operator==(const CVariant &rhs) const +{ + if (m_type == rhs.m_type) + { + switch (m_type) + { + case VariantTypeInteger: + return m_data.integer == rhs.m_data.integer; + case VariantTypeUnsignedInteger: + return m_data.unsignedinteger == rhs.m_data.unsignedinteger; + case VariantTypeBoolean: + return m_data.boolean == rhs.m_data.boolean; + case VariantTypeDouble: + return m_data.dvalue == rhs.m_data.dvalue; + case VariantTypeString: + return *m_data.string == *rhs.m_data.string; + case VariantTypeWideString: + return *m_data.wstring == *rhs.m_data.wstring; + case VariantTypeArray: + return *m_data.array == *rhs.m_data.array; + case VariantTypeObject: + return *m_data.map == *rhs.m_data.map; + default: + break; + } + } + + return false; +} + +void CVariant::reserve(size_t length) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + if (m_type == VariantTypeArray) + m_data.array->reserve(length); +} + +void CVariant::push_back(const CVariant &variant) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + + if (m_type == VariantTypeArray) + m_data.array->push_back(variant); +} + +void CVariant::push_back(CVariant &&variant) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + + if (m_type == VariantTypeArray) + m_data.array->push_back(std::move(variant)); +} + +void CVariant::append(const CVariant &variant) +{ + push_back(variant); +} + +void CVariant::append(CVariant&& variant) +{ + push_back(std::move(variant)); +} + +const char *CVariant::c_str() const +{ + if (m_type == VariantTypeString) + return m_data.string->c_str(); + else + return NULL; +} + +void CVariant::swap(CVariant &rhs) +{ + VariantType temp_type = m_type; + VariantUnion temp_data = m_data; + + m_type = rhs.m_type; + m_data = rhs.m_data; + + rhs.m_type = temp_type; + rhs.m_data = temp_data; +} + +CVariant::iterator_array CVariant::begin_array() +{ + if (m_type == VariantTypeArray) + return m_data.array->begin(); + else + return EMPTY_ARRAY.begin(); +} + +CVariant::const_iterator_array CVariant::begin_array() const +{ + if (m_type == VariantTypeArray) + return m_data.array->begin(); + else + return EMPTY_ARRAY.begin(); +} + +CVariant::iterator_array CVariant::end_array() +{ + if (m_type == VariantTypeArray) + return m_data.array->end(); + else + return EMPTY_ARRAY.end(); +} + +CVariant::const_iterator_array CVariant::end_array() const +{ + if (m_type == VariantTypeArray) + return m_data.array->end(); + else + return EMPTY_ARRAY.end(); +} + +CVariant::iterator_map CVariant::begin_map() +{ + if (m_type == VariantTypeObject) + return m_data.map->begin(); + else + return EMPTY_MAP.begin(); +} + +CVariant::const_iterator_map CVariant::begin_map() const +{ + if (m_type == VariantTypeObject) + return m_data.map->begin(); + else + return EMPTY_MAP.begin(); +} + +CVariant::iterator_map CVariant::end_map() +{ + if (m_type == VariantTypeObject) + return m_data.map->end(); + else + return EMPTY_MAP.end(); +} + +CVariant::const_iterator_map CVariant::end_map() const +{ + if (m_type == VariantTypeObject) + return m_data.map->end(); + else + return EMPTY_MAP.end(); +} + +unsigned int CVariant::size() const +{ + if (m_type == VariantTypeObject) + return m_data.map->size(); + else if (m_type == VariantTypeArray) + return m_data.array->size(); + else if (m_type == VariantTypeString) + return m_data.string->size(); + else if (m_type == VariantTypeWideString) + return m_data.wstring->size(); + else + return 0; +} + +bool CVariant::empty() const +{ + if (m_type == VariantTypeObject) + return m_data.map->empty(); + else if (m_type == VariantTypeArray) + return m_data.array->empty(); + else if (m_type == VariantTypeString) + return m_data.string->empty(); + else if (m_type == VariantTypeWideString) + return m_data.wstring->empty(); + else if (m_type == VariantTypeNull) + return true; + + return false; +} + +void CVariant::clear() +{ + if (m_type == VariantTypeObject) + m_data.map->clear(); + else if (m_type == VariantTypeArray) + m_data.array->clear(); + else if (m_type == VariantTypeString) + m_data.string->clear(); + else if (m_type == VariantTypeWideString) + m_data.wstring->clear(); +} + +void CVariant::erase(const std::string &key) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeObject; + m_data.map = new VariantMap; + } + else if (m_type == VariantTypeObject) + m_data.map->erase(key); +} + +void CVariant::erase(unsigned int position) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + + if (m_type == VariantTypeArray && position < size()) + m_data.array->erase(m_data.array->begin() + position); +} + +bool CVariant::isMember(const std::string &key) const +{ + if (m_type == VariantTypeObject) + return m_data.map->find(key) != m_data.map->end(); + + return false; +} |