// // Var.cpp // // $Id: //poco/svn/Foundation/src/Var.cpp#3 $ // // Library: Foundation // Package: Core // Module: Var // // Copyright (c) 2007, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #include "Poco/Dynamic/Var.h" #include "Poco/Dynamic/Struct.h" #include #include #include #include #include namespace Poco { namespace Dynamic { Var::Var() #ifdef POCO_NO_SOO : _pHolder(0) #endif { } Var::Var(const char* pVal) #ifdef POCO_NO_SOO : _pHolder(new VarHolderImpl(pVal)) { } #else { construct(std::string(pVal)); } #endif Var::Var(const Var& other) #ifdef POCO_NO_SOO : _pHolder(other._pHolder ? other._pHolder->clone() : 0) { } #else { if ((this != &other) && !other.isEmpty()) construct(other); } #endif Var::~Var() { destruct(); } Var& Var::operator = (const Var& rhs) { #ifdef POCO_NO_SOO Var tmp(rhs); swap(tmp); #else if ((this != &rhs) && !rhs.isEmpty()) construct(rhs); else if ((this != &rhs) && rhs.isEmpty()) _placeholder.erase(); #endif return *this; } const Var Var::operator + (const Var& other) const { if (isInteger()) { if (isSigned()) return add(other); else return add(other); } else if (isNumeric()) return add(other); else if (isString()) return add(other); else throw InvalidArgumentException("Invalid operation for this data type."); } Var& Var::operator += (const Var& other) { if (isInteger()) { if (isSigned()) return *this = add(other); else return *this = add(other); } else if (isNumeric()) return *this = add(other); else if (isString()) return *this = add(other); else throw InvalidArgumentException("Invalid operation for this data type."); } const Var Var::operator - (const Var& other) const { if (isInteger()) { if (isSigned()) return subtract(other); else return subtract(other); } else if (isNumeric()) return subtract(other); else throw InvalidArgumentException("Invalid operation for this data type."); } Var& Var::operator -= (const Var& other) { if (isInteger()) { if (isSigned()) return *this = subtract(other); else return *this = subtract(other); } else if (isNumeric()) return *this = subtract(other); else throw InvalidArgumentException("Invalid operation for this data type."); } const Var Var::operator * (const Var& other) const { if (isInteger()) { if (isSigned()) return multiply(other); else return multiply(other); } else if (isNumeric()) return multiply(other); else throw InvalidArgumentException("Invalid operation for this data type."); } Var& Var::operator *= (const Var& other) { if (isInteger()) { if (isSigned()) return *this = multiply(other); else return *this = multiply(other); } else if (isNumeric()) return *this = multiply(other); else throw InvalidArgumentException("Invalid operation for this data type."); } const Var Var::operator / (const Var& other) const { if (isInteger()) { if (isSigned()) return divide(other); else return divide(other); } else if (isNumeric()) return divide(other); else throw InvalidArgumentException("Invalid operation for this data type."); } Var& Var::operator /= (const Var& other) { if (isInteger()) { if (isSigned()) return *this = divide(other); else return *this = divide(other); } else if (isNumeric()) return *this = divide(other); else throw InvalidArgumentException("Invalid operation for this data type."); } Var& Var::operator ++ () { if (!isInteger()) throw InvalidArgumentException("Invalid operation for this data type."); return *this = *this + 1; } const Var Var::operator ++ (int) { if (!isInteger()) throw InvalidArgumentException("Invalid operation for this data type."); Var tmp(*this); *this += 1; return tmp; } Var& Var::operator -- () { if (!isInteger()) throw InvalidArgumentException("Invalid operation for this data type."); return *this = *this - 1; } const Var Var::operator -- (int) { if (!isInteger()) throw InvalidArgumentException("Invalid operation for this data type."); Var tmp(*this); *this -= 1; return tmp; } bool Var::operator == (const Var& other) const { if (isEmpty() != other.isEmpty()) return false; if (isEmpty() && other.isEmpty()) return true; return convert() == other.convert(); } bool Var::operator == (const char* other) const { if (isEmpty()) return false; return convert() == other; } bool Var::operator != (const Var& other) const { if (isEmpty() && other.isEmpty()) return false; else if (isEmpty() || other.isEmpty()) return true; return convert() != other.convert(); } bool Var::operator != (const char* other) const { if (isEmpty()) return true; return convert() != other; } bool Var::operator < (const Var& other) const { if (isEmpty() || other.isEmpty()) return false; return convert() < other.convert(); } bool Var::operator <= (const Var& other) const { if (isEmpty() || other.isEmpty()) return false; return convert() <= other.convert(); } bool Var::operator > (const Var& other) const { if (isEmpty() || other.isEmpty()) return false; return convert() > other.convert(); } bool Var::operator >= (const Var& other) const { if (isEmpty() || other.isEmpty()) return false; return convert() >= other.convert(); } bool Var::operator || (const Var& other) const { if (isEmpty() || other.isEmpty()) return false; return convert() || other.convert(); } bool Var::operator && (const Var& other) const { if (isEmpty() || other.isEmpty()) return false; return convert() && other.convert(); } void Var::empty() { #ifdef POCO_NO_SOO delete _pHolder; _pHolder = 0; #else if (_placeholder.isLocal()) this->~Var(); else delete content(); _placeholder.erase(); #endif } Var& Var::getAt(std::size_t n) { if (isVector()) return holderImpl, InvalidAccessException>("Not a vector.")->operator[](n); else if (isList()) return holderImpl, InvalidAccessException>("Not a list.")->operator[](n); else if (isDeque()) return holderImpl, InvalidAccessException>("Not a deque.")->operator[](n); else if (isStruct()) return structIndexOperator(holderImpl, InvalidAccessException>("Not a struct."), static_cast(n)); else if (!isString() && !isEmpty() && (n == 0)) return *this; throw RangeException("Index out of bounds."); } char& Var::at(std::size_t n) { if (isString()) { return holderImpl("Not a string.")->operator[](n); } throw InvalidAccessException("Not a string."); } Var& Var::getAt(const std::string& name) { return holderImpl("Not a struct.")->operator[](name); } Var Var::parse(const std::string& val) { std::string::size_type t = 0; return parse(val, t); } Var Var::parse(const std::string& val, std::string::size_type& pos) { // { -> an Object==DynamicStruct // [ -> an array // '/" -> a string (strip '/") // other: also treat as string skipWhiteSpace(val, pos); if (pos < val.size()) { switch (val[pos]) { case '{': return parseObject(val, pos); case '[': return parseArray(val, pos); case '"': return parseJSONString(val, pos); default: return parseString(val, pos); } } std::string empty; return empty; } Var Var::parseObject(const std::string& val, std::string::size_type& pos) { poco_assert_dbg (val[pos] == '{'); ++pos; skipWhiteSpace(val, pos); DynamicStruct aStruct; while (val[pos] != '}' && pos < val.size()) { std::string key = parseString(val, pos); skipWhiteSpace(val, pos); if (val[pos] != ':') throw DataFormatException("Incorrect object, must contain: key : value pairs"); ++pos; // skip past : Var value = parse(val, pos); aStruct.insert(key, value); skipWhiteSpace(val, pos); if (val[pos] == ',') { ++pos; skipWhiteSpace(val, pos); } } if (val[pos] != '}') throw DataFormatException("Unterminated object"); ++pos; return aStruct; } Var Var::parseArray(const std::string& val, std::string::size_type& pos) { poco_assert_dbg (val[pos] == '['); ++pos; skipWhiteSpace(val, pos); std::vector result; while (val[pos] != ']' && pos < val.size()) { result.push_back(parse(val, pos)); skipWhiteSpace(val, pos); if (val[pos] == ',') { ++pos; skipWhiteSpace(val, pos); } } if (val[pos] != ']') throw DataFormatException("Unterminated array"); ++pos; return result; } std::string Var::parseString(const std::string& val, std::string::size_type& pos) { if (val[pos] == '"') { return parseJSONString(val, pos); } else { std::string result; while (pos < val.size() && !Poco::Ascii::isSpace(val[pos]) && val[pos] != ',' && val[pos] != ']' && val[pos] != '}') { result += val[pos++]; } return result; } } std::string Var::parseJSONString(const std::string& val, std::string::size_type& pos) { poco_assert_dbg (val[pos] == '"'); ++pos; std::string result; bool done = false; while (pos < val.size() && !done) { switch (val[pos]) { case '"': done = true; ++pos; break; case '\\': if (pos < val.size()) { ++pos; switch (val[pos]) { case 'b': result += '\b'; break; case 'f': result += '\f'; break; case 'n': result += '\n'; break; case 'r': result += '\r'; break; case 't': result += '\t'; break; default: result += val[pos]; break; } break; } else { result += val[pos]; } ++pos; break; default: result += val[pos++]; break; } } if (!done) throw Poco::DataFormatException("unterminated JSON string"); return result; } void Var::skipWhiteSpace(const std::string& val, std::string::size_type& pos) { while (std::isspace(val[pos])) ++pos; } std::string Var::toString(const Var& any) { std::string res; Impl::appendJSONValue(res, any); return res; } Var& Var::structIndexOperator(VarHolderImpl >* pStr, int n) const { return pStr->operator[](n); } } } // namespace Poco::Dynamic