2016-01-18 15:33:29 +00:00
|
|
|
// Copyright (c) 2011-2016 The Cryptonote developers
|
2015-09-18 11:55:31 +00:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
#include "JsonValue.h"
|
|
|
|
#include <iomanip>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
namespace Common {
|
|
|
|
|
|
|
|
JsonValue::JsonValue() : type(NIL) {
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(const JsonValue& other) {
|
|
|
|
switch (other.type) {
|
|
|
|
case ARRAY:
|
|
|
|
new(valueArray)Array(*reinterpret_cast<const Array*>(other.valueArray));
|
|
|
|
break;
|
|
|
|
case BOOL:
|
|
|
|
valueBool = other.valueBool;
|
|
|
|
break;
|
|
|
|
case INTEGER:
|
|
|
|
valueInteger = other.valueInteger;
|
|
|
|
break;
|
|
|
|
case NIL:
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
new(valueObject)Object(*reinterpret_cast<const Object*>(other.valueObject));
|
|
|
|
break;
|
|
|
|
case REAL:
|
|
|
|
valueReal = other.valueReal;
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
new(valueString)String(*reinterpret_cast<const String*>(other.valueString));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = other.type;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(JsonValue&& other) {
|
|
|
|
switch (other.type) {
|
|
|
|
case ARRAY:
|
|
|
|
new(valueArray)Array(std::move(*reinterpret_cast<Array*>(other.valueArray)));
|
|
|
|
reinterpret_cast<Array*>(other.valueArray)->~Array();
|
|
|
|
break;
|
|
|
|
case BOOL:
|
|
|
|
valueBool = other.valueBool;
|
|
|
|
break;
|
|
|
|
case INTEGER:
|
|
|
|
valueInteger = other.valueInteger;
|
|
|
|
break;
|
|
|
|
case NIL:
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
new(valueObject)Object(std::move(*reinterpret_cast<Object*>(other.valueObject)));
|
|
|
|
reinterpret_cast<Object*>(other.valueObject)->~Object();
|
|
|
|
break;
|
|
|
|
case REAL:
|
|
|
|
valueReal = other.valueReal;
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
new(valueString)String(std::move(*reinterpret_cast<String*>(other.valueString)));
|
|
|
|
reinterpret_cast<String*>(other.valueString)->~String();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = other.type;
|
|
|
|
other.type = NIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(Type valueType) {
|
|
|
|
switch (valueType) {
|
|
|
|
case ARRAY:
|
|
|
|
new(valueArray)Array;
|
|
|
|
break;
|
|
|
|
case NIL:
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
new(valueObject)Object;
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
new(valueString)String;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw std::runtime_error("Invalid JsonValue type for constructor");
|
|
|
|
}
|
|
|
|
|
|
|
|
type = valueType;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(const Array& value) {
|
|
|
|
new(valueArray)Array(value);
|
|
|
|
type = ARRAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(Array&& value) {
|
|
|
|
new(valueArray)Array(std::move(value));
|
|
|
|
type = ARRAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(Bool value) : type(BOOL), valueBool(value) {
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(Integer value) : type(INTEGER), valueInteger(value) {
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(Nil) : type(NIL) {
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(const Object& value) {
|
|
|
|
new(valueObject)Object(value);
|
|
|
|
type = OBJECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(Object&& value) {
|
|
|
|
new(valueObject)Object(std::move(value));
|
|
|
|
type = OBJECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(Real value) : type(REAL), valueReal(value) {
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(const String& value) {
|
|
|
|
new(valueString)String(value);
|
|
|
|
type = STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::JsonValue(String&& value) {
|
|
|
|
new(valueString)String(std::move(value));
|
|
|
|
type = STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::~JsonValue() {
|
|
|
|
destructValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(const JsonValue& other) {
|
|
|
|
if (type != other.type) {
|
|
|
|
destructValue();
|
|
|
|
switch (other.type) {
|
|
|
|
case ARRAY:
|
|
|
|
type = NIL;
|
|
|
|
new(valueArray)Array(*reinterpret_cast<const Array*>(other.valueArray));
|
|
|
|
break;
|
|
|
|
case BOOL:
|
|
|
|
valueBool = other.valueBool;
|
|
|
|
break;
|
|
|
|
case INTEGER:
|
|
|
|
valueInteger = other.valueInteger;
|
|
|
|
break;
|
|
|
|
case NIL:
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
type = NIL;
|
|
|
|
new(valueObject)Object(*reinterpret_cast<const Object*>(other.valueObject));
|
|
|
|
break;
|
|
|
|
case REAL:
|
|
|
|
valueReal = other.valueReal;
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
type = NIL;
|
|
|
|
new(valueString)String(*reinterpret_cast<const String*>(other.valueString));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = other.type;
|
|
|
|
} else {
|
|
|
|
switch (type) {
|
|
|
|
case ARRAY:
|
|
|
|
*reinterpret_cast<Array*>(valueArray) = *reinterpret_cast<const Array*>(other.valueArray);
|
|
|
|
break;
|
|
|
|
case BOOL:
|
|
|
|
valueBool = other.valueBool;
|
|
|
|
break;
|
|
|
|
case INTEGER:
|
|
|
|
valueInteger = other.valueInteger;
|
|
|
|
break;
|
|
|
|
case NIL:
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
*reinterpret_cast<Object*>(valueObject) = *reinterpret_cast<const Object*>(other.valueObject);
|
|
|
|
break;
|
|
|
|
case REAL:
|
|
|
|
valueReal = other.valueReal;
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
*reinterpret_cast<String*>(valueString) = *reinterpret_cast<const String*>(other.valueString);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(JsonValue&& other) {
|
|
|
|
if (type != other.type) {
|
|
|
|
destructValue();
|
|
|
|
switch (other.type) {
|
|
|
|
case ARRAY:
|
|
|
|
type = NIL;
|
|
|
|
new(valueArray)Array(std::move(*reinterpret_cast<const Array*>(other.valueArray)));
|
|
|
|
reinterpret_cast<Array*>(other.valueArray)->~Array();
|
|
|
|
break;
|
|
|
|
case BOOL:
|
|
|
|
valueBool = other.valueBool;
|
|
|
|
break;
|
|
|
|
case INTEGER:
|
|
|
|
valueInteger = other.valueInteger;
|
|
|
|
break;
|
|
|
|
case NIL:
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
type = NIL;
|
|
|
|
new(valueObject)Object(std::move(*reinterpret_cast<const Object*>(other.valueObject)));
|
|
|
|
reinterpret_cast<Object*>(other.valueObject)->~Object();
|
|
|
|
break;
|
|
|
|
case REAL:
|
|
|
|
valueReal = other.valueReal;
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
type = NIL;
|
|
|
|
new(valueString)String(std::move(*reinterpret_cast<const String*>(other.valueString)));
|
|
|
|
reinterpret_cast<String*>(other.valueString)->~String();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = other.type;
|
|
|
|
} else {
|
|
|
|
switch (type) {
|
|
|
|
case ARRAY:
|
|
|
|
*reinterpret_cast<Array*>(valueArray) = std::move(*reinterpret_cast<const Array*>(other.valueArray));
|
|
|
|
reinterpret_cast<Array*>(other.valueArray)->~Array();
|
|
|
|
break;
|
|
|
|
case BOOL:
|
|
|
|
valueBool = other.valueBool;
|
|
|
|
break;
|
|
|
|
case INTEGER:
|
|
|
|
valueInteger = other.valueInteger;
|
|
|
|
break;
|
|
|
|
case NIL:
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
*reinterpret_cast<Object*>(valueObject) = std::move(*reinterpret_cast<const Object*>(other.valueObject));
|
|
|
|
reinterpret_cast<Object*>(other.valueObject)->~Object();
|
|
|
|
break;
|
|
|
|
case REAL:
|
|
|
|
valueReal = other.valueReal;
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
*reinterpret_cast<String*>(valueString) = std::move(*reinterpret_cast<const String*>(other.valueString));
|
|
|
|
reinterpret_cast<String*>(other.valueString)->~String();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
other.type = NIL;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(const Array& value) {
|
|
|
|
if (type != ARRAY) {
|
|
|
|
destructValue();
|
|
|
|
type = NIL;
|
|
|
|
new(valueArray)Array(value);
|
|
|
|
type = ARRAY;
|
|
|
|
} else {
|
|
|
|
*reinterpret_cast<Array*>(valueArray) = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(Array&& value) {
|
|
|
|
if (type != ARRAY) {
|
|
|
|
destructValue();
|
|
|
|
type = NIL;
|
|
|
|
new(valueArray)Array(std::move(value));
|
|
|
|
type = ARRAY;
|
|
|
|
} else {
|
|
|
|
*reinterpret_cast<Array*>(valueArray) = std::move(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//JsonValue& JsonValue::operator=(Bool value) {
|
|
|
|
// if (type != BOOL) {
|
|
|
|
// destructValue();
|
|
|
|
// type = BOOL;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// valueBool = value;
|
|
|
|
// return *this;
|
|
|
|
//}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(Integer value) {
|
|
|
|
if (type != INTEGER) {
|
|
|
|
destructValue();
|
|
|
|
type = INTEGER;
|
|
|
|
}
|
|
|
|
|
|
|
|
valueInteger = value;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(Nil) {
|
|
|
|
if (type != NIL) {
|
|
|
|
destructValue();
|
|
|
|
type = NIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(const Object& value) {
|
|
|
|
if (type != OBJECT) {
|
|
|
|
destructValue();
|
|
|
|
type = NIL;
|
|
|
|
new(valueObject)Object(value);
|
|
|
|
type = OBJECT;
|
|
|
|
} else {
|
|
|
|
*reinterpret_cast<Object*>(valueObject) = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(Object&& value) {
|
|
|
|
if (type != OBJECT) {
|
|
|
|
destructValue();
|
|
|
|
type = NIL;
|
|
|
|
new(valueObject)Object(std::move(value));
|
|
|
|
type = OBJECT;
|
|
|
|
} else {
|
|
|
|
*reinterpret_cast<Object*>(valueObject) = std::move(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(Real value) {
|
|
|
|
if (type != REAL) {
|
|
|
|
destructValue();
|
|
|
|
type = REAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
valueReal = value;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(const String& value) {
|
|
|
|
if (type != STRING) {
|
|
|
|
destructValue();
|
|
|
|
type = NIL;
|
|
|
|
new(valueString)String(value);
|
|
|
|
type = STRING;
|
|
|
|
} else {
|
|
|
|
*reinterpret_cast<String*>(valueString) = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator=(String&& value) {
|
|
|
|
if (type != STRING) {
|
|
|
|
destructValue();
|
|
|
|
type = NIL;
|
|
|
|
new(valueString)String(std::move(value));
|
|
|
|
type = STRING;
|
|
|
|
} else {
|
|
|
|
*reinterpret_cast<String*>(valueString) = std::move(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonValue::isArray() const {
|
|
|
|
return type == ARRAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonValue::isBool() const {
|
|
|
|
return type == BOOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonValue::isInteger() const {
|
|
|
|
return type == INTEGER;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonValue::isNil() const {
|
|
|
|
return type == NIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonValue::isObject() const {
|
|
|
|
return type == OBJECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonValue::isReal() const {
|
|
|
|
return type == REAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonValue::isString() const {
|
|
|
|
return type == STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::Type JsonValue::getType() const {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::Array& JsonValue::getArray() {
|
|
|
|
if (type != ARRAY) {
|
|
|
|
throw std::runtime_error("JsonValue type is not ARRAY");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *reinterpret_cast<Array*>(valueArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
const JsonValue::Array& JsonValue::getArray() const {
|
|
|
|
if (type != ARRAY) {
|
|
|
|
throw std::runtime_error("JsonValue type is not ARRAY");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *reinterpret_cast<const Array*>(valueArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::Bool JsonValue::getBool() const {
|
|
|
|
if (type != BOOL) {
|
|
|
|
throw std::runtime_error("JsonValue type is not BOOL");
|
|
|
|
}
|
|
|
|
|
|
|
|
return valueBool;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::Integer JsonValue::getInteger() const {
|
|
|
|
if (type != INTEGER) {
|
|
|
|
throw std::runtime_error("JsonValue type is not INTEGER");
|
|
|
|
}
|
|
|
|
|
|
|
|
return valueInteger;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::Object& JsonValue::getObject() {
|
|
|
|
if (type != OBJECT) {
|
|
|
|
throw std::runtime_error("JsonValue type is not OBJECT");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *reinterpret_cast<Object*>(valueObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
const JsonValue::Object& JsonValue::getObject() const {
|
|
|
|
if (type != OBJECT) {
|
|
|
|
throw std::runtime_error("JsonValue type is not OBJECT");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *reinterpret_cast<const Object*>(valueObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::Real JsonValue::getReal() const {
|
|
|
|
if (type != REAL) {
|
|
|
|
throw std::runtime_error("JsonValue type is not REAL");
|
|
|
|
}
|
|
|
|
|
|
|
|
return valueReal;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue::String& JsonValue::getString() {
|
|
|
|
if (type != STRING) {
|
|
|
|
throw std::runtime_error("JsonValue type is not STRING");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *reinterpret_cast<String*>(valueString);
|
|
|
|
}
|
|
|
|
|
|
|
|
const JsonValue::String& JsonValue::getString() const {
|
|
|
|
if (type != STRING) {
|
|
|
|
throw std::runtime_error("JsonValue type is not STRING");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *reinterpret_cast<const String*>(valueString);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
size_t JsonValue::size() const {
|
2015-05-27 12:08:46 +00:00
|
|
|
switch (type) {
|
|
|
|
case ARRAY:
|
|
|
|
return reinterpret_cast<const Array*>(valueArray)->size();
|
|
|
|
case OBJECT:
|
|
|
|
return reinterpret_cast<const Object*>(valueObject)->size();
|
|
|
|
default:
|
|
|
|
throw std::runtime_error("JsonValue type is not ARRAY or OBJECT");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue& JsonValue::operator[](size_t index) {
|
2015-05-27 12:08:46 +00:00
|
|
|
if (type != ARRAY) {
|
|
|
|
throw std::runtime_error("JsonValue type is not ARRAY");
|
|
|
|
}
|
|
|
|
|
|
|
|
return reinterpret_cast<Array*>(valueArray)->at(index);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
const JsonValue& JsonValue::operator[](size_t index) const {
|
2015-05-27 12:08:46 +00:00
|
|
|
if (type != ARRAY) {
|
|
|
|
throw std::runtime_error("JsonValue type is not ARRAY");
|
|
|
|
}
|
|
|
|
|
|
|
|
return reinterpret_cast<const Array*>(valueArray)->at(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::pushBack(const JsonValue& value) {
|
|
|
|
if (type != ARRAY) {
|
|
|
|
throw std::runtime_error("JsonValue type is not ARRAY");
|
|
|
|
}
|
|
|
|
|
|
|
|
reinterpret_cast<Array*>(valueArray)->emplace_back(value);
|
|
|
|
return reinterpret_cast<Array*>(valueArray)->back();
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::pushBack(JsonValue&& value) {
|
|
|
|
if (type != ARRAY) {
|
|
|
|
throw std::runtime_error("JsonValue type is not ARRAY");
|
|
|
|
}
|
|
|
|
|
|
|
|
reinterpret_cast<Array*>(valueArray)->emplace_back(std::move(value));
|
|
|
|
return reinterpret_cast<Array*>(valueArray)->back();
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::operator()(const Key& key) {
|
2015-07-15 12:23:00 +00:00
|
|
|
return getObject().at(key);
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const JsonValue& JsonValue::operator()(const Key& key) const {
|
2015-07-15 12:23:00 +00:00
|
|
|
return getObject().at(key);
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
bool JsonValue::contains(const Key& key) const {
|
|
|
|
return getObject().count(key) > 0;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::insert(const Key& key, const JsonValue& value) {
|
2015-07-15 12:23:00 +00:00
|
|
|
return getObject().emplace(key, value).first->second;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue& JsonValue::insert(const Key& key, JsonValue&& value) {
|
2015-07-15 12:23:00 +00:00
|
|
|
return getObject().emplace(key, std::move(value)).first->second;
|
|
|
|
}
|
2015-05-27 12:08:46 +00:00
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
JsonValue& JsonValue::set(const Key& key, const JsonValue& value) {
|
|
|
|
getObject()[key] = value;
|
|
|
|
return *this;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
JsonValue& JsonValue::set(const Key& key, JsonValue&& value) {
|
|
|
|
getObject()[key] = std::move(value);
|
|
|
|
return *this;
|
|
|
|
}
|
2015-05-27 12:08:46 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
size_t JsonValue::erase(const Key& key) {
|
2015-07-15 12:23:00 +00:00
|
|
|
return getObject().erase(key);
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JsonValue JsonValue::fromString(const std::string& source) {
|
|
|
|
JsonValue jsonValue;
|
|
|
|
std::istringstream stream(source);
|
|
|
|
stream >> jsonValue;
|
|
|
|
if (stream.fail()) {
|
|
|
|
throw std::runtime_error("Unable to parse JsonValue");
|
|
|
|
}
|
|
|
|
|
|
|
|
return jsonValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string JsonValue::toString() const {
|
|
|
|
std::ostringstream stream;
|
|
|
|
stream << *this;
|
|
|
|
return stream.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& out, const JsonValue& jsonValue) {
|
|
|
|
switch (jsonValue.type) {
|
|
|
|
case JsonValue::ARRAY: {
|
|
|
|
const JsonValue::Array& array = *reinterpret_cast<const JsonValue::Array*>(jsonValue.valueArray);
|
|
|
|
out << '[';
|
|
|
|
if (array.size() > 0) {
|
|
|
|
out << array[0];
|
2015-07-30 15:22:07 +00:00
|
|
|
for (size_t i = 1; i < array.size(); ++i) {
|
2015-05-27 12:08:46 +00:00
|
|
|
out << ',' << array[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out << ']';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case JsonValue::BOOL:
|
|
|
|
out << (jsonValue.valueBool ? "true" : "false");
|
|
|
|
break;
|
|
|
|
case JsonValue::INTEGER:
|
|
|
|
out << jsonValue.valueInteger;
|
|
|
|
break;
|
|
|
|
case JsonValue::NIL:
|
|
|
|
out << "null";
|
|
|
|
break;
|
|
|
|
case JsonValue::OBJECT: {
|
|
|
|
const JsonValue::Object& object = *reinterpret_cast<const JsonValue::Object*>(jsonValue.valueObject);
|
|
|
|
out << '{';
|
|
|
|
auto iter = object.begin();
|
|
|
|
if (iter != object.end()) {
|
|
|
|
out << '"' << iter->first << "\":" << iter->second;
|
|
|
|
++iter;
|
|
|
|
for (; iter != object.end(); ++iter) {
|
|
|
|
out << ",\"" << iter->first << "\":" << iter->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out << '}';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case JsonValue::REAL: {
|
|
|
|
std::ostringstream stream;
|
|
|
|
stream << std::fixed << std::setprecision(11) << jsonValue.valueReal;
|
|
|
|
std::string value = stream.str();
|
|
|
|
while (value.size() > 1 && value[value.size() - 2] != '.' && value[value.size() - 1] == '0') {
|
|
|
|
value.resize(value.size() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
out << value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case JsonValue::STRING:
|
|
|
|
out << '"' << *reinterpret_cast<const JsonValue::String*>(jsonValue.valueString) << '"';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
char readChar(std::istream& in) {
|
|
|
|
char c;
|
|
|
|
|
|
|
|
if (!(in >> c)) {
|
|
|
|
throw std::runtime_error("Unable to parse: unexpected end of stream");
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
char readNonWsChar(std::istream& in) {
|
2015-05-27 12:08:46 +00:00
|
|
|
char c;
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
c = readChar(in);
|
|
|
|
} while (isspace(c));
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string readStringToken(std::istream& in) {
|
|
|
|
char c;
|
|
|
|
std::string value;
|
|
|
|
|
|
|
|
while (in) {
|
|
|
|
c = readChar(in);
|
|
|
|
|
|
|
|
if (c == '"') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\\') {
|
|
|
|
value += c;
|
|
|
|
c = readChar(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
value += c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::istream& operator>>(std::istream& in, JsonValue& jsonValue) {
|
|
|
|
char c = readNonWsChar(in);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
if (c == '[') {
|
|
|
|
jsonValue.readArray(in);
|
|
|
|
} else if (c == 't') {
|
|
|
|
jsonValue.readTrue(in);
|
|
|
|
} else if (c == 'f') {
|
|
|
|
jsonValue.readFalse(in);
|
|
|
|
} else if ((c == '-') || (c >= '0' && c <= '9')) {
|
|
|
|
jsonValue.readNumber(in, c);
|
|
|
|
} else if (c == 'n') {
|
|
|
|
jsonValue.readNull(in);
|
|
|
|
} else if (c == '{') {
|
|
|
|
jsonValue.readObject(in);
|
|
|
|
} else if (c == '"') {
|
|
|
|
jsonValue.readString(in);
|
|
|
|
} else {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::destructValue() {
|
|
|
|
switch (type) {
|
|
|
|
case ARRAY:
|
|
|
|
reinterpret_cast<Array*>(valueArray)->~Array();
|
|
|
|
break;
|
|
|
|
case OBJECT:
|
|
|
|
reinterpret_cast<Object*>(valueObject)->~Object();
|
|
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
reinterpret_cast<String*>(valueString)->~String();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::readArray(std::istream& in) {
|
|
|
|
JsonValue::Array value;
|
2015-07-15 12:23:00 +00:00
|
|
|
char c = readNonWsChar(in);
|
2015-05-27 12:08:46 +00:00
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
if(c != ']') {
|
|
|
|
in.putback(c);
|
2015-05-27 12:08:46 +00:00
|
|
|
for (;;) {
|
|
|
|
value.resize(value.size() + 1);
|
|
|
|
in >> value.back();
|
2015-07-15 12:23:00 +00:00
|
|
|
c = readNonWsChar(in);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
if (c == ']') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != ',') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != JsonValue::ARRAY) {
|
|
|
|
destructValue();
|
|
|
|
type = JsonValue::NIL;
|
|
|
|
new(valueArray)JsonValue::Array;
|
|
|
|
type = JsonValue::ARRAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
reinterpret_cast<JsonValue::Array*>(valueArray)->swap(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::readTrue(std::istream& in) {
|
|
|
|
char data[3];
|
|
|
|
in.read(data, 3);
|
|
|
|
if (data[0] != 'r' || data[1] != 'u' || data[2] != 'e') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != JsonValue::BOOL) {
|
|
|
|
destructValue();
|
|
|
|
type = JsonValue::BOOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
valueBool = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::readFalse(std::istream& in) {
|
|
|
|
char data[4];
|
|
|
|
in.read(data, 4);
|
|
|
|
if (data[0] != 'a' || data[1] != 'l' || data[2] != 's' || data[3] != 'e') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != JsonValue::BOOL) {
|
|
|
|
destructValue();
|
|
|
|
type = JsonValue::BOOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
valueBool = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::readNull(std::istream& in) {
|
|
|
|
char data[3];
|
|
|
|
in.read(data, 3);
|
|
|
|
if (data[0] != 'u' || data[1] != 'l' || data[2] != 'l') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != JsonValue::NIL) {
|
|
|
|
destructValue();
|
|
|
|
type = JsonValue::NIL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::readNumber(std::istream& in, char c) {
|
|
|
|
std::string text;
|
|
|
|
text += c;
|
2015-07-30 15:22:07 +00:00
|
|
|
size_t dots = 0;
|
2015-05-27 12:08:46 +00:00
|
|
|
for (;;) {
|
|
|
|
int i = in.peek();
|
|
|
|
if (i >= '0' && i <= '9') {
|
|
|
|
in.read(&c, 1);
|
|
|
|
text += c;
|
|
|
|
} else if (i == '.') {
|
|
|
|
in.read(&c, 1);
|
|
|
|
text += '.';
|
|
|
|
++dots;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dots > 0) {
|
|
|
|
if (dots > 1) {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
int i = in.peek();
|
|
|
|
if (in.peek() == 'e') {
|
|
|
|
in.read(&c, 1);
|
|
|
|
text += c;
|
|
|
|
i = in.peek();
|
|
|
|
if (i == '+') {
|
|
|
|
in.read(&c, 1);
|
|
|
|
text += c;
|
|
|
|
i = in.peek();
|
|
|
|
} else if (i == '-') {
|
|
|
|
in.read(&c, 1);
|
|
|
|
text += c;
|
|
|
|
i = in.peek();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < '0' || i > '9') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
in.read(&c, 1);
|
|
|
|
text += c;
|
|
|
|
i = in.peek();
|
|
|
|
} while (i >= '0' && i <= '9');
|
|
|
|
}
|
|
|
|
|
|
|
|
Real value;
|
|
|
|
std::istringstream(text) >> value;
|
|
|
|
if (type != REAL) {
|
|
|
|
destructValue();
|
|
|
|
type = REAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
valueReal = value;
|
|
|
|
} else {
|
|
|
|
if (text.size() > 1 && ((text[0] == '0') || (text[0] == '-' && text[1] == '0'))) {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
Integer value;
|
|
|
|
std::istringstream(text) >> value;
|
|
|
|
if (type != INTEGER) {
|
|
|
|
destructValue();
|
|
|
|
type = INTEGER;
|
|
|
|
}
|
|
|
|
|
|
|
|
valueInteger = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::readObject(std::istream& in) {
|
2015-07-15 12:23:00 +00:00
|
|
|
char c = readNonWsChar(in);
|
2015-05-27 12:08:46 +00:00
|
|
|
JsonValue::Object value;
|
|
|
|
|
|
|
|
if (c != '}') {
|
|
|
|
std::string name;
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
for (;;) {
|
|
|
|
if (c != '"') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
name = readStringToken(in);
|
|
|
|
c = readNonWsChar(in);
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
if (c != ':') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
|
|
|
|
|
|
|
in >> value[name];
|
2015-07-15 12:23:00 +00:00
|
|
|
c = readNonWsChar(in);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
if (c == '}') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != ',') {
|
|
|
|
throw std::runtime_error("Unable to parse");
|
|
|
|
}
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
c = readNonWsChar(in);
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != JsonValue::OBJECT) {
|
|
|
|
destructValue();
|
|
|
|
type = JsonValue::NIL;
|
|
|
|
new(valueObject)JsonValue::Object;
|
|
|
|
type = JsonValue::OBJECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
reinterpret_cast<JsonValue::Object*>(valueObject)->swap(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonValue::readString(std::istream& in) {
|
2015-07-15 12:23:00 +00:00
|
|
|
String value = readStringToken(in);
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
if (type != JsonValue::STRING) {
|
|
|
|
destructValue();
|
|
|
|
type = JsonValue::NIL;
|
|
|
|
new(valueString)String;
|
|
|
|
type = JsonValue::STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
reinterpret_cast<String*>(valueString)->swap(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|