123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- #include "json.h"
- #include <cstdlib>
- #include <string>
- #include <algorithm>
- #include <cstdlib>
- #include <cstdio>
- #include <climits>
- #include <cstring>
- #include <functional>
- #include <cctype>
- #include <stack>
-
- #ifndef WIN32
- # define _stricmp strcasecmp
- #endif
-
- #ifdef _MSC_VER
- # define snprintf sprintf_s
- #endif
-
- using namespace json;
-
- namespace json {
- enum StackDepthType
- {
- InObject,
- InArray
- };
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Helper functions
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- static std::string Trim(const std::string& str)
- {
- std::string s = str;
-
- // remove white space in front
- s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
-
- // remove trailing white space
- s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
-
- return s;
- }
-
- // Finds the position of the first " character that is NOT preceeded immediately by a \ character.
- // In JSON, \" is valid and has a different meaning than the escaped " character.
- static size_t GetQuotePos(const std::string& str, const size_t start_pos = 0)
- {
- bool found_slash = false;
- for (size_t i = start_pos; i < str.length(); ++i)
- {
- const char c = str[i];
- if ((c == '\\') && !found_slash)
- {
- found_slash = true;
- continue;
- }
- if ((c == '\"') && !found_slash) { return i; }
-
- found_slash = false;
- }
-
- return std::string::npos;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- Value::Value(const Value& v) : mValueType(v.mValueType)
- {
- switch (mValueType)
- {
- case StringVal: mStringVal = v.mStringVal;
- break;
- case IntVal: mIntVal = v.mIntVal;
- mFloatVal = float(v.mIntVal);
- mDoubleVal = double(v.mIntVal);
- break;
- case FloatVal: mFloatVal = v.mFloatVal;
- mIntVal = int(v.mFloatVal);
- mDoubleVal = double(v.mDoubleVal);
- break;
- case DoubleVal: mDoubleVal = v.mDoubleVal;
- mIntVal = int(v.mDoubleVal);
- mFloatVal = float(v.mDoubleVal);
- break;
- case BoolVal: mBoolVal = v.mBoolVal;
- break;
- case ObjectVal: mObjectVal = v.mObjectVal;
- break;
- case ArrayVal: mArrayVal = v.mArrayVal;
- break;
- default: break;
- }
- }
-
- Value& Value::operator =(const Value& v)
- {
- if (&v == this) { return *this; }
-
- mValueType = v.mValueType;
-
- switch (mValueType)
- {
- case StringVal: mStringVal = v.mStringVal;
- break;
- case IntVal: mIntVal = v.mIntVal;
- mFloatVal = float(v.mIntVal);
- mDoubleVal = double(v.mIntVal);
- break;
- case FloatVal: mFloatVal = v.mFloatVal;
- mIntVal = int(v.mFloatVal);
- mDoubleVal = double(v.mDoubleVal);
- break;
- case DoubleVal: mDoubleVal = v.mDoubleVal;
- mIntVal = int(v.mDoubleVal);
- mFloatVal = float(v.mDoubleVal);
- break;
- case BoolVal: mBoolVal = v.mBoolVal;
- break;
- case ObjectVal: mObjectVal = v.mObjectVal;
- break;
- case ArrayVal: mArrayVal = v.mArrayVal;
- break;
- default: break;
- }
-
- return *this;
- }
-
- Value& Value::operator [](const size_t idx)
- {
- assert(mValueType == ArrayVal);
- return mArrayVal[idx];
- }
-
- const Value& Value::operator [](const size_t idx) const
- {
- assert(mValueType == ArrayVal);
- return mArrayVal[idx];
- }
-
- Value& Value::operator [](const std::string& key)
- {
- assert(mValueType == ObjectVal);
- return mObjectVal[key];
- }
-
- Value& Value::operator [](const char* key)
- {
- assert(mValueType == ObjectVal);
- return mObjectVal[key];
- }
-
- const Value& Value::operator [](const char* key) const
- {
- assert(mValueType == ObjectVal);
- return mObjectVal[key];
- }
-
- const Value& Value::operator [](const std::string& key) const
- {
- assert(mValueType == ObjectVal);
- return mObjectVal[key];
- }
-
- size_t Value::size() const
- {
- if ((mValueType != ObjectVal) && (mValueType != ArrayVal)) { return 1; }
- return mValueType == ObjectVal ? mObjectVal.size() : mArrayVal.size();
- }
-
- bool Value::HasKey(const std::string& key) const
- {
- assert(mValueType == ObjectVal);
- return mObjectVal.HasKey(key);
- }
-
- int Value::HasKeys(const std::vector<std::string>& keys) const
- {
- assert(mValueType == ObjectVal);
- return mObjectVal.HasKeys(keys);
- }
-
- int Value::HasKeys(const char** keys, const int key_count) const
- {
- assert(mValueType == ObjectVal);
- return mObjectVal.HasKeys(keys, key_count);
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- Array& Array::operator =(const Array& a)
- {
- if (&a == this) { return *this; }
-
- Clear();
- mValues = a.mValues;
-
- return *this;
- }
-
- Value& Array::operator [](const size_t i) { return mValues[i]; }
- const Value& Array::operator [](const size_t i) const { return mValues[i]; }
- Array::ValueVector::const_iterator Array::begin() const { return mValues.begin(); }
- Array::ValueVector::const_iterator Array::end() const { return mValues.end(); }
- Array::ValueVector::iterator Array::begin() { return mValues.begin(); }
- Array::ValueVector::iterator Array::end() { return mValues.end(); }
- void Array::push_back(const Value& v) { mValues.push_back(v); }
- void Array::insert(const size_t index, const Value& v) { mValues.insert(mValues.begin() + index, v); }
- Array::ValueVector::iterator Array::find(const Value& v) { return std::find(mValues.begin(), mValues.end(), v); }
- Array::ValueVector::const_iterator Array::find(const Value& v) const { return std::find(mValues.begin(), mValues.end(), v); }
- bool Array::HasValue(const Value& v) const { return find(v) != end(); }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- Object& Object::operator =(const Object& obj)
- {
- if (&obj == this) { return *this; }
-
- Clear();
- mValues = obj.mValues;
-
- return *this;
- }
-
- Value& Object::operator [](const std::string& key) { return mValues[key]; }
- const Value& Object::operator [](const std::string& key) const { return mValues.find(key)->second; }
- Value& Object::operator [](const char* key) { return mValues[key]; }
- const Value& Object::operator [](const char* key) const { return mValues.find(key)->second; }
- Object::ValueMap::const_iterator Object::begin() const { return mValues.begin(); }
- Object::ValueMap::const_iterator Object::end() const { return mValues.end(); }
- Object::ValueMap::iterator Object::begin() { return mValues.begin(); }
- Object::ValueMap::iterator Object::end() { return mValues.end(); }
- Object::ValueMap::iterator Object::find(const std::string& key) { return mValues.find(key); }
- Object::ValueMap::const_iterator Object::find(const std::string& key) const { return mValues.find(key); }
- bool Object::HasKey(const std::string& key) const { return find(key) != end(); }
-
- int Object::HasKeys(const std::vector<std::string>& keys) const
- {
- for (size_t i = 0; i < keys.size(); ++i) { if (!HasKey(keys[i])) { return int(i); } }
-
- return -1;
- }
-
- int Object::HasKeys(const char** keys, const int key_count) const
- {
- for (int i = 0; i < key_count; ++i) { if (!HasKey(keys[i])) { return i; } }
-
- return -1;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- std::string SerializeArray(const Array& a);
-
- std::string SerializeValue(const Value& v)
- {
- std::string str;
-
- static const int BUFF_SZ = 500;
- char buff[BUFF_SZ];
- switch (v.GetType())
- {
- case IntVal: snprintf(buff, BUFF_SZ, "%d", int(v));
- str = buff;
- break;
- case FloatVal: snprintf(buff, BUFF_SZ, "%f", float(v));
- str = buff;
- break;
- case DoubleVal: snprintf(buff, BUFF_SZ, "%f", double(v));
- str = buff;
- break;
- case BoolVal: str = v ? "true" : "false";
- break;
- case nullptrVal: str = "null";
- break;
- case ObjectVal: str = Serialize(v);
- break;
- case ArrayVal: str = SerializeArray(v);
- break;
- case StringVal: str = std::string("\"") + v.ToString() + std::string("\"");
- break;
- }
-
- return str;
- }
-
- std::string SerializeArray(const Array& a)
- {
- std::string str = "[";
-
- bool first = true;
- for (const auto& v : a)
- {
- if (!first) { str += std::string(","); }
- str += SerializeValue(v);
- first = false;
- }
-
- str += "]";
- return str;
- }
-
- std::string json::Serialize(const Value& v)
- {
- std::string str;
-
- bool first = true;
-
- if (v.GetType() == ObjectVal)
- {
- str = "{";
- Object obj = v.ToObject();
- for (auto it = obj.begin(); it != obj.end(); ++it)
- {
- if (!first) { str += std::string(","); }
- str += std::string("\"") + it->first + std::string("\":") + SerializeValue(it->second);
- first = false;
- }
-
- str += "}";
- }
- else if (v.GetType() == ArrayVal)
- {
- str = "[";
- Array a = v.ToArray();
- for (auto it = a.begin(); it != a.end(); ++it)
- {
- if (!first) { str += std::string(","); }
- str += SerializeValue(*it);
- first = false;
- }
-
- str += "]";
- }
- //else error
-
- return str;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- static Value DeserializeArray(std::string& str, std::stack<StackDepthType>& depth_stack);
- static Value DeserializeObj(const std::string& _str, std::stack<StackDepthType>& depth_stack);
-
- static Value DeserializeInternal(const std::string& _str, std::stack<StackDepthType>& depth_stack)
- {
- Value v;
-
- if (_str.length() == 0) { return v; }
-
- std::string str = Trim(_str);
- if (str[0] == '{')
- {
- // Error: Began with a { but doesn't end with one
- if (str[str.length() - 1] != '}') { return Value(); }
-
- depth_stack.push(InObject);
- v = DeserializeObj(str, depth_stack);
- if ((v.GetType() == nullptrVal) || (depth_stack.top() != InObject)) { return v; }
-
- depth_stack.pop();
- }
- else if (str[0] == '[')
- {
- // Error: Began with a [ but doesn't end with one
- if (str[str.length() - 1] != ']') { return Value(); }
-
- depth_stack.push(InArray);
- v = DeserializeArray(str, depth_stack);
- if ((v.GetType() == nullptrVal) || (depth_stack.top() != InArray)) { return v; }
-
- depth_stack.pop();
- }
- else { return Value(); } // Will never get here unless _str is not valid JSON
-
- return v;
- }
-
- static size_t GetEndOfArrayOrObj(const std::string& str, std::stack<StackDepthType>& depth_stack)
- {
- size_t i = 1;
- bool in_quote = false;
- const size_t original_count = depth_stack.size();
-
- for (; i < str.length(); ++i)
- {
- if (str[i] == '\"') { if (str[i - 1] != '\\') { in_quote = !in_quote; } }
- else if (!in_quote)
- {
- if (str[i] == '[') { depth_stack.push(InArray); }
- else if (str[i] == '{') { depth_stack.push(InObject); }
- else if (str[i] == ']')
- {
- const StackDepthType t = depth_stack.top();
- // expected to be closing an array but instead we're inside an object block.
- // Example problem: {]}
- if (t != InArray) { return std::string::npos; }
-
- const size_t count = depth_stack.size();
- depth_stack.pop();
- if (count == original_count) { break; }
- }
- else if (str[i] == '}')
- {
- const StackDepthType t = depth_stack.top();
- // expected to be closing an object but instead we're inside an array.
- // Example problem: [}]
- if (t != InObject) { return std::string::npos; }
-
- const size_t count = depth_stack.size();
- depth_stack.pop();
- if (count == original_count) { break; }
- }
- }
- }
-
- return i;
- }
-
- static std::string UnescapeJSONString(const std::string& str)
- {
- std::string s;
-
- for (size_t i = 0; i < str.length(); ++i)
- {
- const char c = str[i];
- if ((c == '\\') && (i + 1 < str.length()))
- {
- int skip_ahead = 1;
- unsigned int hex;
- std::string hex_str;
-
- switch (str[i + 1])
- {
- case '"': s.push_back('\"');
- break;
- case '\\': s.push_back('\\');
- break;
- case '/': s.push_back('/');
- break;
- case 't': s.push_back('\t');
- break;
- case 'n': s.push_back('\n');
- break;
- case 'r': s.push_back('\r');
- break;
- case 'b': s.push_back('\b');
- break;
- case 'f': s.push_back('\f');
- break;
- case 'u': skip_ahead = 5;
- hex_str = str.substr(i + 4, 2);
- hex = static_cast<unsigned int>(std::strtoul(hex_str.c_str(), nullptr, 16));
- s.push_back(char(hex));
- break;
-
- default: break;
- }
-
- i += skip_ahead;
- }
- else { s.push_back(c); }
- }
-
- return Trim(s);
- }
-
- static Value DeserializeValue(std::string& str, bool* had_error, std::stack<StackDepthType>& depth_stack)
- {
- Value v;
-
- *had_error = false;
- str = Trim(str);
-
- if (str.length() == 0) { return v; }
-
- if (str[0] == '[')
- {
- depth_stack.push(InArray);
- size_t i = GetEndOfArrayOrObj(str, depth_stack);
- if (i == std::string::npos)
- {
- *had_error = true;
- return Value();
- }
-
- std::string array_str = str.substr(0, i + 1);
- v = Value(DeserializeArray(array_str, depth_stack));
- str = str.substr(i + 1, str.length());
- }
- else if (str[0] == '{')
- {
- depth_stack.push(InObject);
- size_t i = GetEndOfArrayOrObj(str, depth_stack);
-
- if (i == std::string::npos)
- {
- *had_error = true;
- return Value();
- }
-
- std::string obj_str = str.substr(0, i + 1);
- v = Value(DeserializeInternal(obj_str, depth_stack));
- str = str.substr(i + 1, str.length());
- }
- else if (str[0] == '\"')
- {
- size_t end_quote = GetQuotePos(str, 1);
- if (end_quote == std::string::npos)
- {
- *had_error = true;
- return Value();
- }
-
- v = Value(UnescapeJSONString(str.substr(1, end_quote - 1)));
- str = str.substr(end_quote + 1, str.length());
- }
- else
- {
- bool has_dot = false;
- bool has_e = false;
- std::string temp_val;
- size_t i = 0;
- for (; i < str.length(); ++i)
- {
- if (str[i] == '.') { has_dot = true; }
- else if (str[i] == 'e') { has_e = true; }
- else if (str[i] == ']')
- {
- if (depth_stack.top() != InArray)
- {
- *had_error = true;
- return Value();
- }
-
- depth_stack.pop();
- }
- else if (str[i] == '}')
- {
- if (depth_stack.top() != InObject)
- {
- *had_error = true;
- return Value();
- }
- depth_stack.pop();
- }
- else if (str[i] == ',') { break; }
- if (std::isspace(str[i]) == 0) { temp_val += str[i]; }
- }
-
- // store all floating point as doubles. This will also set the float and int values as well.
- if (_stricmp(temp_val.c_str(), "true") == 0) { v = Value(true); }
- else if (_stricmp(temp_val.c_str(), "false") == 0) { v = Value(false); }
- else if (has_e || has_dot) { v = Value(strtod(temp_val.c_str(), nullptr)); }
- 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 = strtod(temp_val.c_str(), nullptr);
- if ((tmp_val >= double(INT_MIN)) && (tmp_val <= double(INT_MAX))) { v = Value(int(strtol(temp_val.c_str(), nullptr, 10))); }
- else { v = Value(tmp_val); }
- }
-
- str = str.substr(i, str.length());
- }
-
- return v;
- }
-
- static Value DeserializeArray(std::string& str, std::stack<StackDepthType>& depth_stack)
- {
- Array a;
- bool had_error = false;
-
- str = Trim(str);
-
- if ((str[0] == '[') && (str[str.length() - 1] == ']')) { str = str.substr(1, str.length() - 2); }
- else { return Value(); }
-
- while (str.length() > 0)
- {
- std::string tmp;
-
- size_t i = 0;
- for (; i < str.length(); ++i)
- {
- // If we get to an object or array, parse it:
- if ((str[i] == '{') || (str[i] == '['))
- {
- Value v = DeserializeValue(str, &had_error, depth_stack);
- if (had_error) { return Value(); }
- if (v.GetType() != nullptrVal) { a.push_back(v); }
- break;
- }
-
- bool terminate_parsing = false;
-
- if ((str[i] == ',') || (str[i] == ']'))
- {
- terminate_parsing = true; // hit the end of a value, parse it in the next block
- }
- else
- {
- // keep grabbing chars to build up the value
- tmp += str[i];
- if (i == str.length() - 1) { terminate_parsing = true; } // end of string, finish parsing
- }
- if (terminate_parsing)
- {
- Value v = DeserializeValue(tmp, &had_error, depth_stack);
- if (had_error) { return Value(); }
-
- if (v.GetType() != nullptrVal) { a.push_back(v); }
-
- str = str.substr(i + 1, str.length());
- break;
- }
- }
- }
-
- return a;
- }
-
- static Value DeserializeObj(const std::string& _str, std::stack<StackDepthType>& depth_stack)
- {
- Object obj;
-
- std::string str = Trim(_str);
-
- if ((str[0] != '{') && (str[str.length() - 1] != '}')) { return Value(); }
- str = str.substr(1, str.length() - 2);
-
- while (str.length() > 0)
- {
- // Get the key name
- const size_t start_quote_idx = GetQuotePos(str);
- const size_t end_quote_idx = GetQuotePos(str, start_quote_idx + 1);
- const size_t colon_idx = str.find(':', end_quote_idx);
-
- if ((start_quote_idx == std::string::npos) || (end_quote_idx == std::string::npos) || (colon_idx == std::string::npos))
- {
- return Value(); // can't find key name
- }
-
- std::string key = str.substr(start_quote_idx + 1, end_quote_idx - start_quote_idx - 1);
- if (key.length() == 0) { return Value(); }
-
- bool had_error = false;
- str = str.substr(colon_idx + 1, str.length());
- obj[key] = DeserializeValue(str, &had_error, depth_stack);
- if (had_error) { return Value(); }
- }
-
- return obj;
- }
-
- Value json::Deserialize(const std::string& str)
- {
- std::stack<StackDepthType> depth_stack;
- return DeserializeInternal(str, depth_stack);
- }
|