mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
updated SuperEasyJSON
git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@8085 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
d65adeb2ea
commit
336001abd9
@ -1,3 +1,5 @@
|
||||
#define nullptr 0
|
||||
|
||||
#include "json.h"
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
@ -9,6 +11,7 @@
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <stack>
|
||||
#include <cerrno>
|
||||
|
||||
#ifndef WIN32
|
||||
#define _stricmp strcasecmp
|
||||
@ -108,37 +111,49 @@ Value& Value::operator =(const Value& v)
|
||||
|
||||
Value& Value::operator [](size_t idx)
|
||||
{
|
||||
assert(mValueType == ArrayVal);
|
||||
if (mValueType != ArrayVal)
|
||||
throw std::runtime_error("json mValueType==ArrayVal required");
|
||||
|
||||
return mArrayVal[idx];
|
||||
}
|
||||
|
||||
const Value& Value::operator [](size_t idx) const
|
||||
{
|
||||
assert(mValueType == ArrayVal);
|
||||
if (mValueType != ArrayVal)
|
||||
throw std::runtime_error("json mValueType==ArrayVal required");
|
||||
|
||||
return mArrayVal[idx];
|
||||
}
|
||||
|
||||
Value& Value::operator [](const std::string& key)
|
||||
{
|
||||
assert(mValueType == ObjectVal);
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal[key];
|
||||
}
|
||||
|
||||
Value& Value::operator [](const char* key)
|
||||
{
|
||||
assert(mValueType == ObjectVal);
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal[key];
|
||||
}
|
||||
|
||||
const Value& Value::operator [](const char* key) const
|
||||
{
|
||||
assert(mValueType == ObjectVal);
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal[key];
|
||||
}
|
||||
|
||||
const Value& Value::operator [](const std::string& key) const
|
||||
{
|
||||
assert(mValueType == ObjectVal);
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal[key];
|
||||
}
|
||||
|
||||
@ -157,22 +172,140 @@ size_t Value::size() const
|
||||
|
||||
bool Value::HasKey(const std::string &key) const
|
||||
{
|
||||
assert(mValueType == ObjectVal);
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal.HasKey(key);
|
||||
}
|
||||
|
||||
int Value::HasKeys(const std::vector<std::string> &keys) const
|
||||
{
|
||||
assert(mValueType == ObjectVal);
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal.HasKeys(keys);
|
||||
}
|
||||
|
||||
int Value::HasKeys(const char **keys, int key_count) const
|
||||
{
|
||||
assert(mValueType == ObjectVal);
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal.HasKeys(keys, key_count);
|
||||
}
|
||||
|
||||
int Value::ToInt() const
|
||||
{
|
||||
if (!IsNumeric())
|
||||
throw std::runtime_error("json mValueType==IsNumeric() required");
|
||||
|
||||
return mIntVal;
|
||||
}
|
||||
|
||||
float Value::ToFloat() const
|
||||
{
|
||||
if (!IsNumeric())
|
||||
throw std::runtime_error("json mValueType==IsNumeric() required");
|
||||
|
||||
return mFloatVal;
|
||||
}
|
||||
|
||||
double Value::ToDouble() const
|
||||
{
|
||||
if (!IsNumeric())
|
||||
throw std::runtime_error("json mValueType==IsNumeric() required");
|
||||
|
||||
return mDoubleVal;
|
||||
}
|
||||
|
||||
bool Value::ToBool() const
|
||||
{
|
||||
if (mValueType != BoolVal)
|
||||
throw std::runtime_error("json mValueType==BoolVal required");
|
||||
|
||||
return mBoolVal;
|
||||
}
|
||||
|
||||
const std::string& Value::ToString() const
|
||||
{
|
||||
if (mValueType != StringVal)
|
||||
throw std::runtime_error("json mValueType==StringVal required");
|
||||
|
||||
return mStringVal;
|
||||
}
|
||||
|
||||
Object Value::ToObject() const
|
||||
{
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal;
|
||||
}
|
||||
|
||||
Array Value::ToArray() const
|
||||
{
|
||||
if (mValueType != ArrayVal)
|
||||
throw std::runtime_error("json mValueType==ArrayVal required");
|
||||
|
||||
return mArrayVal;
|
||||
}
|
||||
|
||||
Value::operator int() const
|
||||
{
|
||||
if (!IsNumeric())
|
||||
throw std::runtime_error("json mValueType==IsNumeric() required");
|
||||
|
||||
return mIntVal;
|
||||
}
|
||||
|
||||
Value::operator float() const
|
||||
{
|
||||
if (!IsNumeric())
|
||||
throw std::runtime_error("json mValueType==IsNumeric() required");
|
||||
|
||||
return mFloatVal;
|
||||
}
|
||||
|
||||
Value::operator double() const
|
||||
{
|
||||
if (!IsNumeric())
|
||||
throw std::runtime_error("json mValueType==IsNumeric() required");
|
||||
|
||||
return mDoubleVal;
|
||||
}
|
||||
|
||||
Value::operator bool() const
|
||||
{
|
||||
if (mValueType != BoolVal)
|
||||
throw std::runtime_error("json mValueType==BoolVal required");
|
||||
|
||||
return mBoolVal;
|
||||
}
|
||||
|
||||
Value::operator std::string() const
|
||||
{
|
||||
if (mValueType != StringVal)
|
||||
throw std::runtime_error("json mValueType==StringVal required");
|
||||
|
||||
return mStringVal;
|
||||
}
|
||||
|
||||
Value::operator Object() const
|
||||
{
|
||||
if (mValueType != ObjectVal)
|
||||
throw std::runtime_error("json mValueType==ObjectVal required");
|
||||
|
||||
return mObjectVal;
|
||||
}
|
||||
|
||||
Value::operator Array() const
|
||||
{
|
||||
if (mValueType != ArrayVal)
|
||||
throw std::runtime_error("json mValueType==ArrayVal required");
|
||||
|
||||
return mArrayVal;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Array::Array()
|
||||
@ -420,7 +553,7 @@ std::string json::Serialize(const Value& v)
|
||||
{
|
||||
str = "{";
|
||||
Object obj = v.ToObject();
|
||||
for (Object::ValueMap::const_iterator it = obj.begin(); it != obj.end(); it++)
|
||||
for (Object::ValueMap::const_iterator it = obj.begin(); it != obj.end(); ++it)
|
||||
{
|
||||
if (!first)
|
||||
str += std::string(",");
|
||||
@ -435,7 +568,7 @@ std::string json::Serialize(const Value& v)
|
||||
{
|
||||
str = "[";
|
||||
Array a = v.ToArray();
|
||||
for (Array::ValueVector::const_iterator it = a.begin(); it != a.end(); it++)
|
||||
for (Array::ValueVector::const_iterator it = a.begin(); it != a.end(); ++it)
|
||||
{
|
||||
if (!first)
|
||||
str += std::string(",");
|
||||
@ -447,7 +580,8 @@ std::string json::Serialize(const Value& v)
|
||||
str += "]";
|
||||
|
||||
}
|
||||
//else error
|
||||
// else it's not valid JSON, as a JSON data structure must be an array or an object. We'll return an empty string.
|
||||
|
||||
|
||||
return str;
|
||||
}
|
||||
@ -556,7 +690,7 @@ static std::string UnescapeJSONString(const std::string& str)
|
||||
{
|
||||
std::string s = "";
|
||||
|
||||
for (int i = 0; i < str.length(); i++)
|
||||
for (std::string::size_type i = 0; i < str.length(); i++)
|
||||
{
|
||||
char c = str[i];
|
||||
if ((c == '\\') && (i + 1 < str.length()))
|
||||
@ -577,7 +711,7 @@ static std::string UnescapeJSONString(const std::string& str)
|
||||
case 'f' : s.push_back('\f'); break;
|
||||
case 'u' : skip_ahead = 5;
|
||||
hex_str = str.substr(i + 4, 2);
|
||||
hex = (unsigned int)std::strtoul(hex_str.c_str(), NULL, 16);
|
||||
hex = (unsigned int)std::strtoul(hex_str.c_str(), nullptr, 16);
|
||||
s.push_back((char)hex);
|
||||
break;
|
||||
|
||||
@ -605,6 +739,7 @@ static Value DeserializeValue(std::string& str, bool* had_error, std::stack<Stac
|
||||
|
||||
if (str[0] == '[')
|
||||
{
|
||||
// This value is an array, determine the end of it and then deserialize the array
|
||||
depth_stack.push(InArray);
|
||||
size_t i = GetEndOfArrayOrObj(str, depth_stack);
|
||||
if (i == std::string::npos)
|
||||
@ -619,6 +754,7 @@ static Value DeserializeValue(std::string& str, bool* had_error, std::stack<Stac
|
||||
}
|
||||
else if (str[0] == '{')
|
||||
{
|
||||
// This value is an object, determine the end of it and then deserialize the object
|
||||
depth_stack.push(InObject);
|
||||
size_t i = GetEndOfArrayOrObj(str, depth_stack);
|
||||
|
||||
@ -634,6 +770,7 @@ static Value DeserializeValue(std::string& str, bool* had_error, std::stack<Stac
|
||||
}
|
||||
else if (str[0] == '\"')
|
||||
{
|
||||
// This value is a string
|
||||
size_t end_quote = GetQuotePos(str, 1);
|
||||
if (end_quote == std::string::npos)
|
||||
{
|
||||
@ -646,19 +783,52 @@ static Value DeserializeValue(std::string& str, bool* had_error, std::stack<Stac
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's not an object, string, or array so it's either a boolean or a number or null.
|
||||
// Numbers can contain an exponent indicator ('e') or a decimal point.
|
||||
bool has_dot = false;
|
||||
bool has_e = false;
|
||||
std::string temp_val;
|
||||
size_t i = 0;
|
||||
bool found_digit = false;
|
||||
bool found_first_valid_char = false;
|
||||
|
||||
for (; i < str.length(); i++)
|
||||
{
|
||||
if (str[i] == '.')
|
||||
{
|
||||
if (!found_digit)
|
||||
{
|
||||
// As per JSON standards, there must be a digit preceding a decimal point
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
|
||||
has_dot = true;
|
||||
else if (str[i] == 'e')
|
||||
has_e = true;
|
||||
}
|
||||
else if ((str[i] == 'e') || (str[i] == 'E'))
|
||||
{
|
||||
if ((_stricmp(temp_val.c_str(), "fals") != 0) && (_stricmp(temp_val.c_str(), "tru") != 0))
|
||||
{
|
||||
// it's not a boolean, check for scientific notation validity. This will also trap booleans with extra 'e' characters like falsee/truee
|
||||
if (!found_digit)
|
||||
{
|
||||
// As per JSON standards, a digit must precede the 'e' notation
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
else if (has_e)
|
||||
{
|
||||
// multiple 'e' characters not allowed
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
|
||||
has_e = true;
|
||||
}
|
||||
}
|
||||
else if (str[i] == ']')
|
||||
{
|
||||
if (depth_stack.top() != InArray)
|
||||
if (depth_stack.empty() || (depth_stack.top() != InArray))
|
||||
{
|
||||
*had_error = true;
|
||||
return Value();
|
||||
@ -668,7 +838,7 @@ static Value DeserializeValue(std::string& str, bool* had_error, std::stack<Stac
|
||||
}
|
||||
else if (str[i] == '}')
|
||||
{
|
||||
if (depth_stack.top() != InObject)
|
||||
if (depth_stack.empty() || (depth_stack.top() != InObject))
|
||||
{
|
||||
*had_error = true;
|
||||
return Value();
|
||||
@ -677,10 +847,22 @@ static Value DeserializeValue(std::string& str, bool* had_error, std::stack<Stac
|
||||
depth_stack.pop();
|
||||
}
|
||||
else if (str[i] == ',')
|
||||
break;
|
||||
break;
|
||||
else if ((str[i] == '[') || (str[i] == '{'))
|
||||
{
|
||||
// error, we're supposed to be processing things besides arrays/objects in here
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
|
||||
if (!std::isspace(str[i]))
|
||||
{
|
||||
if (std::isdigit(str[i]))
|
||||
found_digit = true;
|
||||
|
||||
found_first_valid_char = true;
|
||||
temp_val += str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// store all floating point as doubles. This will also set the float and int values as well.
|
||||
@ -689,17 +871,61 @@ static Value DeserializeValue(std::string& str, bool* had_error, std::stack<Stac
|
||||
else if (_stricmp(temp_val.c_str(), "false") == 0)
|
||||
v = Value(false);
|
||||
else if (has_e || has_dot)
|
||||
v = Value(atof(temp_val.c_str()));
|
||||
{
|
||||
char* end_char;
|
||||
errno = 0;
|
||||
double d = strtod(temp_val.c_str(), &end_char);
|
||||
if ((errno != 0) || (*end_char != '\0'))
|
||||
{
|
||||
// invalid conversion or out of range
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
|
||||
v = Value(d);
|
||||
}
|
||||
else if (_stricmp(temp_val.c_str(), "null") == 0)
|
||||
v = Value();
|
||||
else
|
||||
{
|
||||
// Check if the value is beyond the size of an int and if so, store it as a double
|
||||
double tmp_val = atof(temp_val.c_str());
|
||||
if ((tmp_val >= (double)INT_MIN) && (tmp_val <= (double)INT_MAX))
|
||||
v = Value(atoi(temp_val.c_str()));
|
||||
char* end_char;
|
||||
errno = 0;
|
||||
long int ival = strtol(temp_val.c_str(), &end_char, 10);
|
||||
if (*end_char != '\0')
|
||||
{
|
||||
// invalid character sequence, not a number
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
else if ((errno == ERANGE) && ((ival == LONG_MAX) || (ival == LONG_MIN)))
|
||||
{
|
||||
// value is out of range for a long int, should be a double then. See if we can convert it correctly.
|
||||
errno = 0;
|
||||
double dval = strtod(temp_val.c_str(), &end_char);
|
||||
if ((errno != 0) || (*end_char != '\0'))
|
||||
{
|
||||
// error in conversion or it's too big for a double
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
|
||||
v = Value(dval);
|
||||
}
|
||||
else if ((ival >= INT_MIN) && (ival <= INT_MAX))
|
||||
{
|
||||
// valid integer range
|
||||
v = Value((int)ival);
|
||||
}
|
||||
else
|
||||
v = Value(tmp_val);
|
||||
{
|
||||
// probably running on a very old OS since this block implies that long isn't the same size as int.
|
||||
// int is guaranteed to be at least 16 bits and long 32 bits...however nowadays they're almost
|
||||
// always the same 32 bit size. But it's possible someone is running this on a very old architecture
|
||||
// so for correctness, we'll error out here
|
||||
*had_error = true;
|
||||
return Value();
|
||||
}
|
||||
}
|
||||
|
||||
str = str.substr(i, str.length());
|
||||
@ -715,11 +941,13 @@ static Value DeserializeArray(std::string& str, std::stack<StackDepthType>& dept
|
||||
|
||||
str = Trim(str);
|
||||
|
||||
// Arrays begin and end with [], so if we don't find one, it's an error
|
||||
if ((str[0] == '[') && (str[str.length() - 1] == ']'))
|
||||
str = str.substr(1, str.length() - 2);
|
||||
else
|
||||
return Value();
|
||||
|
||||
// extract out all values from the array (remember, a value can also be an array or an object)
|
||||
while (str.length() > 0)
|
||||
{
|
||||
std::string tmp;
|
||||
@ -776,11 +1004,13 @@ static Value DeserializeObj(const std::string& _str, std::stack<StackDepthType>&
|
||||
|
||||
std::string str = Trim(_str);
|
||||
|
||||
// Objects begin and end with {} so if we don't find a pair, it's an error
|
||||
if ((str[0] != '{') && (str[str.length() - 1] != '}'))
|
||||
return Value();
|
||||
else
|
||||
str = str.substr(1, str.length() - 2);
|
||||
|
||||
// Get all key/value pairs in this object...
|
||||
while (str.length() > 0)
|
||||
{
|
||||
// Get the key name
|
||||
@ -797,6 +1027,8 @@ static Value DeserializeObj(const std::string& _str, std::stack<StackDepthType>&
|
||||
|
||||
bool had_error = false;
|
||||
str = str.substr(colon_idx + 1, str.length());
|
||||
|
||||
// We have the key, now extract the value from the string
|
||||
obj[key] = DeserializeValue(str, &had_error, depth_stack);
|
||||
if (had_error)
|
||||
return Value();
|
||||
|
@ -26,6 +26,55 @@
|
||||
|
||||
CHANGELOG:
|
||||
==========
|
||||
|
||||
8/31/2014:
|
||||
---------
|
||||
* Fixed bug from last update that broke false/true boolean usage. Courtesy of Vasi B.
|
||||
* Change postfix increment of iterators in Serialize to prefix, courtesy of Vasi B.
|
||||
* More improvements to validity checking of non string/object/array types. Should
|
||||
catch even more invalid usage types such as -1jE5, falsee, trueeeeeee
|
||||
{"key" : potato} (that should be {"key" : "potato"}), etc.
|
||||
* Switched to strtol and strtod from atof/atoi in Serialize for better error handling.
|
||||
* Fix for GCC order of initialization warnings, courtsey of Vasi B.
|
||||
|
||||
8/17/2014:
|
||||
----------
|
||||
* Better error handling (and bug fixing) for invalid JSON. Previously, something such as:
|
||||
{"def": j[{"a": 100}],"abc": 123}
|
||||
would result in at best, a crash, and at worst, nothing when this was passed to
|
||||
the Deserialize method. Note that the "j" is invalid in this example. This led
|
||||
to further fixes for other invalid syntax:
|
||||
- Use of multiple 'e', for example: 1ee4 is not valid
|
||||
- Use of '.' when not preceded by a digit is invalid. For example: .1 is
|
||||
incorrect, but 0.1 is fine.
|
||||
- Using 'e' when not preceded by a digit. For example, e4 isn't valid but 1e4 is.
|
||||
|
||||
The deserialize method should properly handle these problems and when there's an
|
||||
error, it returns a Value object with the NULLVal type. Check this type to see
|
||||
if there's an error.
|
||||
|
||||
Issue reported by Imre Pechan.
|
||||
|
||||
7/21/2014:
|
||||
----------
|
||||
* All asserts removed and replaced with exceptions, as per request from many users.
|
||||
Instead of asserting, functions will throw a std::runtime_error with
|
||||
appropriate error message.
|
||||
* Added versions of the Value::To* functions that take a default parameter.
|
||||
In the event of an error (like calling Value::ToInt() when it's type is an Object),
|
||||
the default value you specified will be returned. Courtesy of PeterSvP
|
||||
* Fixed type mismatch warning, courtesy of Per Rovegård
|
||||
* Initialized some variables in the various Value constructors to defaults for
|
||||
better support with full blast g++ warnings, courtesy of Mark Odell.
|
||||
* Changed Value::ToString to return a const std::string& instead of std::string
|
||||
to avoid unnecessary copying.
|
||||
* Improved some commenting
|
||||
* Fixed a bug where a capital E for scientific notation numbers wasn't
|
||||
recognized, only lowercase e.
|
||||
* VASTLY OVERHAULED AND IMPROVED THE README FILE, PLEASE CONSULT IT FOR
|
||||
IN DEPTH USAGE AND EXAMPLES.
|
||||
|
||||
|
||||
2/8/2014:
|
||||
---------
|
||||
MAJOR BUG FIXES, all courtesy of Per Rovegård, Ph.D.
|
||||
@ -70,7 +119,7 @@
|
||||
|
||||
1/27/2014
|
||||
----------
|
||||
* Deserialize will now return a NULLType Value instance if there was an
|
||||
* Deserialize will now return a NULLVal Value instance if there was an
|
||||
error instead of asserting. This way you can handle however you want to
|
||||
invalid JSON being passed in. As a top level object must be either an
|
||||
array or an object, a NULL value return indicates an invalid result.
|
||||
@ -187,8 +236,10 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
// PLEASE SEE THE README FOR USAGE INFORMATION AND EXAMPLES. Comments will be kept to a minimum to reduce clutter.
|
||||
namespace json
|
||||
{
|
||||
enum ValueType
|
||||
@ -205,10 +256,15 @@ namespace json
|
||||
|
||||
class Value;
|
||||
|
||||
// Represents a JSON object which is of the form {string:value, string:value, ...} Where string is the "key" name and is
|
||||
// of the form "" or "characters". Value is either of: string, number, object, array, boolean, null
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
|
||||
// This is the type used to store key/value pairs. If you want to get an iterator for this class to iterate over its members,
|
||||
// use this.
|
||||
// For example: Object::ValueMap::iterator my_iterator;
|
||||
typedef std::map<std::string, Value> ValueMap;
|
||||
|
||||
protected:
|
||||
@ -229,6 +285,11 @@ namespace json
|
||||
inline friend bool operator <=(const Object& lhs, const Object& rhs) {return !operator>(lhs, rhs);}
|
||||
inline friend bool operator >=(const Object& lhs, const Object& rhs) {return !operator<(lhs, rhs);}
|
||||
|
||||
// Just like a std::map, you can get the value for a key by using the index operator. You could also
|
||||
// use this to insert a value if it doesn't exist, or overwrite it if it does. Example:
|
||||
// Value my_val = my_object["some key name"];
|
||||
// my_object["some key name"] = "overwriting the value with this new string value";
|
||||
// my_object["new key name"] = "a new key being inserted";
|
||||
Value& operator [](const std::string& key);
|
||||
const Value& operator [](const std::string& key) const;
|
||||
Value& operator [](const char* key);
|
||||
@ -239,11 +300,12 @@ namespace json
|
||||
ValueMap::iterator begin();
|
||||
ValueMap::iterator end();
|
||||
|
||||
// Find will return end() if the key can't be found, just like std::map does.
|
||||
// Find will return end() if the key can't be found, just like std::map does. ->first will be the key (a std::string),
|
||||
// ->second will be the Value.
|
||||
ValueMap::iterator find(const std::string& key);
|
||||
ValueMap::const_iterator find(const std::string& key) const;
|
||||
|
||||
// Convenience wrapper to find to search for a key
|
||||
// Convenience wrapper to search for a key
|
||||
bool HasKey(const std::string& key) const;
|
||||
|
||||
// Checks if the object contains all the keys in the array. If it does, returns -1.
|
||||
@ -258,10 +320,14 @@ namespace json
|
||||
|
||||
};
|
||||
|
||||
// Represents a JSON Array which is of the form [value, value, ...] where value is either of: string, number, object, array, boolean, null
|
||||
class Array
|
||||
{
|
||||
public:
|
||||
|
||||
// This is the type used to store values. If you want to get an iterator for this class to iterate over its members,
|
||||
// use this.
|
||||
// For example: Array::ValueVector::iterator my_array_iterator;
|
||||
typedef std::vector<Value> ValueVector;
|
||||
|
||||
protected:
|
||||
@ -305,6 +371,7 @@ namespace json
|
||||
size_t size() const;
|
||||
};
|
||||
|
||||
// Represents a JSON value which is either of: string, number, object, array, boolean, null
|
||||
class Value
|
||||
{
|
||||
protected:
|
||||
@ -321,18 +388,23 @@ namespace json
|
||||
public:
|
||||
|
||||
Value() : mValueType(NULLVal), mIntVal(0), mFloatVal(0), mDoubleVal(0), mBoolVal(false) {}
|
||||
Value(int v) : mValueType(IntVal), mIntVal(v), mFloatVal((float)v), mDoubleVal((double)v) {}
|
||||
Value(float v) : mValueType(FloatVal), mFloatVal(v), mIntVal((int)v), mDoubleVal((double)v) {}
|
||||
Value(double v) : mValueType(DoubleVal), mDoubleVal(v), mIntVal((int)v), mFloatVal((float)v) {}
|
||||
Value(const std::string& v) : mValueType(StringVal), mStringVal(v) {}
|
||||
Value(const char* v) : mValueType(StringVal), mStringVal(v) {}
|
||||
Value(const Object& v) : mValueType(ObjectVal), mObjectVal(v) {}
|
||||
Value(const Array& v) : mValueType(ArrayVal), mArrayVal(v) {}
|
||||
Value(const bool v) : mValueType(BoolVal), mBoolVal(v) {}
|
||||
Value(int v) : mValueType(IntVal), mIntVal(v), mFloatVal((float)v), mDoubleVal((double)v), mBoolVal(false) {}
|
||||
Value(float v) : mValueType(FloatVal), mIntVal((int)v), mFloatVal(v), mDoubleVal((double)v), mBoolVal(false) {}
|
||||
Value(double v) : mValueType(DoubleVal), mIntVal((int)v), mFloatVal((float)v), mDoubleVal(v), mBoolVal(false) {}
|
||||
Value(const std::string& v) : mValueType(StringVal), mIntVal(), mFloatVal(), mDoubleVal(), mStringVal(v), mBoolVal(false) {}
|
||||
Value(const char* v) : mValueType(StringVal), mIntVal(), mFloatVal(), mDoubleVal(), mStringVal(v), mBoolVal(false) {}
|
||||
Value(const Object& v) : mValueType(ObjectVal), mIntVal(), mFloatVal(), mDoubleVal(), mObjectVal(v), mBoolVal(false) {}
|
||||
Value(const Array& v) : mValueType(ArrayVal), mIntVal(), mFloatVal(), mDoubleVal(), mArrayVal(v), mBoolVal(false) {}
|
||||
Value(bool v) : mValueType(BoolVal), mIntVal(), mFloatVal(), mDoubleVal(), mBoolVal(v) {}
|
||||
Value(const Value& v);
|
||||
|
||||
// Use this to determine the underlying type that this Value class represents. It will be one of the
|
||||
// ValueType enums as defined at the top of this file.
|
||||
ValueType GetType() const {return mValueType;}
|
||||
|
||||
// Convenience method that checks if this type is an int/double/float
|
||||
bool IsNumeric() const {return (mValueType == IntVal) || (mValueType == DoubleVal) || (mValueType == FloatVal);}
|
||||
|
||||
Value& operator =(const Value& v);
|
||||
|
||||
friend bool operator ==(const Value& lhs, const Value& rhs);
|
||||
@ -343,7 +415,9 @@ namespace json
|
||||
inline friend bool operator >=(const Value& lhs, const Value& rhs) {return !operator<(lhs, rhs);}
|
||||
|
||||
|
||||
// For use with Array/ObjectVal types, respectively
|
||||
// If this value represents an object or array, you can use the [] indexing operator
|
||||
// just like you would with the native json::Array or json::Object classes.
|
||||
// THROWS A std::runtime_error IF NOT AN ARRAY OR OBJECT.
|
||||
Value& operator [](size_t idx);
|
||||
const Value& operator [](size_t idx) const;
|
||||
Value& operator [](const std::string& key);
|
||||
@ -351,19 +425,30 @@ namespace json
|
||||
Value& operator [](const char* key);
|
||||
const Value& operator [](const char* key) const;
|
||||
|
||||
// If this value represents an object, these methods let you check if a single key or an array of
|
||||
// keys is contained within it.
|
||||
// THROWS A std::runtime_error IF NOT AN OBJECT.
|
||||
bool HasKey(const std::string& key) const;
|
||||
int HasKeys(const std::vector<std::string>& keys) const;
|
||||
int HasKeys(const char* keys[], int key_count) const;
|
||||
|
||||
|
||||
// non-operator versions
|
||||
int ToInt() const {assert(IsNumeric()); return mIntVal;}
|
||||
float ToFloat() const {assert(IsNumeric()); return mFloatVal;}
|
||||
double ToDouble() const {assert(IsNumeric()); return mDoubleVal;}
|
||||
bool ToBool() const {assert(mValueType == BoolVal); return mBoolVal;}
|
||||
std::string ToString() const {assert(mValueType == StringVal); return mStringVal;}
|
||||
Object ToObject() const {assert(mValueType == ObjectVal); return mObjectVal;}
|
||||
Array ToArray() const {assert(mValueType == ArrayVal); return mArrayVal;}
|
||||
// non-operator versions, **will throw a std::runtime_error if invalid with an appropriate error message**
|
||||
int ToInt() const;
|
||||
float ToFloat() const;
|
||||
double ToDouble() const;
|
||||
bool ToBool() const;
|
||||
const std::string& ToString() const;
|
||||
Object ToObject() const;
|
||||
Array ToArray() const;
|
||||
|
||||
// These versions do the same as above but will return your specified default value in the event there's an error, and thus **don't** throw an exception.
|
||||
int ToInt(int def) const {return IsNumeric() ? mIntVal : def;}
|
||||
float ToFloat(float def) const {return IsNumeric() ? mFloatVal : def;}
|
||||
double ToDouble(double def) const {return IsNumeric() ? mDoubleVal : def;}
|
||||
bool ToBool(bool def) const {return (mValueType == BoolVal) ? mBoolVal : def;}
|
||||
const std::string& ToString(const std::string& def) const {return (mValueType == StringVal) ? mStringVal : def;}
|
||||
|
||||
|
||||
// Please note that as per C++ rules, implicitly casting a Value to a std::string won't work.
|
||||
// This is because it could use the int/float/double/bool operators as well. So to assign a
|
||||
@ -372,15 +457,13 @@ namespace json
|
||||
// Or you can now do:
|
||||
// my_string = my_value.ToString();
|
||||
//
|
||||
operator int() const {assert(IsNumeric()); return mIntVal;}
|
||||
operator float() const {assert(IsNumeric()); return mFloatVal;}
|
||||
operator double() const {assert(IsNumeric()); return mDoubleVal;}
|
||||
operator bool() const {assert(mValueType == BoolVal); return mBoolVal;}
|
||||
operator std::string() const {assert(mValueType == StringVal); return mStringVal;}
|
||||
operator Object() const {assert(mValueType == ObjectVal); return mObjectVal;}
|
||||
operator Array() const {assert(mValueType == ArrayVal); return mArrayVal;}
|
||||
|
||||
bool IsNumeric() const {return (mValueType == IntVal) || (mValueType == DoubleVal) || (mValueType == FloatVal);}
|
||||
operator int() const;
|
||||
operator float() const;
|
||||
operator double() const;
|
||||
operator bool() const;
|
||||
operator std::string() const;
|
||||
operator Object() const;
|
||||
operator Array() const;
|
||||
|
||||
// Returns 1 for anything not an Array/ObjectVal
|
||||
size_t size() const;
|
||||
@ -392,10 +475,16 @@ namespace json
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Converts a JSON Object or Array instance into a JSON string representing it.
|
||||
// Converts a JSON Object or Array instance into a JSON string representing it. RETURNS EMPTY STRING ON ERROR.
|
||||
// As per JSON specification, a JSON data structure must be an array or an object. Thus, you must either pass in a
|
||||
// json::Array, json::Object, or a json::Value that has an Array or Object as its underlying type.
|
||||
std::string Serialize(const Value& obj);
|
||||
|
||||
// If there is an error, Value will be NULLType
|
||||
// If there is an error, Value will be NULLVal. Pass in a valid JSON string (such as one returned from Serialize, or obtained
|
||||
// elsewhere) to receive a Value in return that represents the JSON structure. Check the type of Value by calling GetType().
|
||||
// It will be ObjectVal or ArrayVal (or NULLVal if invalid JSON). The Value class contains the operator [] for indexing in the
|
||||
// case that the underlying type is an object or array. You may, if you prefer, create an object or array from the Value returned
|
||||
// by this method by simply passing it into the constructor.
|
||||
Value Deserialize(const std::string& str);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user