#include "../shared/MiscSupport.h" #include "JsonSupport.h" static bool validUtf8(std::string s) { // This returns true if the string is can be interpreted as a UTF-8 encoded // string. We assume for simplicity that the locale is UTF-8. mbstate_t state; memset (&state, '\0', sizeof (state)); const char *start = s.c_str(); size_t result = mbsrtowcs(NULL, &start, 0, &state); return result != (size_t)-1; } void JsonNode::clearAll() { _stringValue.clear(); _arrayValue.clear(); _objectValue.clear(); } class Utf8EncodeHelper { public: std::string encoded[256]; Utf8EncodeHelper(bool valid) { for (unsigned int ch = 0; ch < 256; ch++) { switch(ch) { case '"': encoded[ch] = "\\\""; break; case '\\': encoded[ch] = "\\\\"; break; case '\b': encoded[ch] = "\\b"; break; case '\f': encoded[ch] = "\\f"; break; case '\n': encoded[ch] = "\\n"; break; case '\r': encoded[ch] = "\\r"; break; case '\t': encoded[ch] = "\\t"; break; default: { if (ch < 32) { char e[10]; sprintf(e, "\\u%04x", ch); encoded[ch] = e; } else if (valid || (ch < 128)) { encoded[ch] = std::string(1, ch); } else { encoded[ch] = "?"; } } } } } }; static void quoteString(std::string &output, std::string s) { static const Utf8EncodeHelper invalidHelper(false); static const Utf8EncodeHelper validHelper(true); const Utf8EncodeHelper &encoder = validUtf8(s)?validHelper:invalidHelper; output += '"'; const char * const inputStart = s.data(); const char * const inputEnd = inputStart + s.size(); for (char const *it = inputStart; it != inputEnd; it++) { output += encoder.encoded[*it]; } output += '"'; } void JsonNode::addToString(std::string &output) const { // This implementation is based on XmlNode::addToString(). In XmlNode // I learned that creating and destroying a lot of string objects caused // most of our performance problems. By extending the same string through // the recursive process we make things more effecient. switch (_type) { null: output += "null"; break; integer: output += itoa(_integerValue); break; real: output += dtoa(_realValue); break; string: quoteString(output, _stringValue); break; boolean: output += _booleanValue?"true":"false"; break; array: { output += '['; bool first = true; for (std::vector< JsonNode >::const_iterator it = _arrayValue.begin(); it != _arrayValue.end(); it++) { if (first) { first = false; } else { output += ','; } it->addToString(output); } output += ']'; break; } object: output += '{'; bool first = true; for (std::map< std::string, JsonNode >::const_iterator it = _objectValue.begin(); it != _objectValue.end(); it++) { if (first) { first = false; } else { output += ','; } quoteString(output, it->first); output += ':'; it->second.addToString(output); } output += '}'; break; } } JsonNode &JsonNode::setToNull() { clearAll(); _type = null; } JsonNode &JsonNode::operator =(int i) { clearAll(); _type = integer; _integerValue = i; } JsonNode &JsonNode::operator =(double d) { clearAll(); _type = real; _realValue = d; } JsonNode &JsonNode::operator =(std::string s) { clearAll(); _type = string; _stringValue = s; } JsonNode &JsonNode::operator =(bool b) { clearAll(); _type = boolean; _booleanValue = b; } JsonNode &JsonNode::setToEmptyArray() { clearAll(); _type = array; } JsonNode &JsonNode::setToEmptyObject() { clearAll(); _type = object; } JsonNode &JsonNode::operator =(JsonNode const &other) { clearAll(); _type = other._type; switch (_type) { case null: break; case integer: _integerValue = other._integerValue; break; case real: _realValue = other._realValue; break; case string: _stringValue = other._stringValue; break; case boolean: _booleanValue = other._booleanValue; break; case array: _arrayValue = other._arrayValue; break; case object: _objectValue = other._objectValue; break; } } JsonNode &JsonNode::operator[](std::string s) { clearAll(); if (_type == null) { _type = object; } else if (_type != object) { InvalidTypeException ex; ex.expected = object; ex.found = _type; } return _objectValue[s]; } JsonNode &JsonNode::operator[](int i) { clearAll(); if (_type == null) { _type = array; } else if (_type != array) { InvalidTypeException ex; ex.expected = array; ex.found = _type; } if (i < 0) { return *_arrayValue.insert(_arrayValue.end(), JsonNode()); } else { if (i >= _arrayValue.size()) { _arrayValue.resize(i + 1); } return _arrayValue[i]; } } std::string JsonNode::asString() const { std::string result; addToString(result); return result; }