diff options
Diffstat (limited to 'lib/jsoncpp/jsoncpp.cpp')
-rw-r--r-- | lib/jsoncpp/jsoncpp.cpp | 266 |
1 files changed, 134 insertions, 132 deletions
diff --git a/lib/jsoncpp/jsoncpp.cpp b/lib/jsoncpp/jsoncpp.cpp index a85e280ed..507a1c6ad 100644 --- a/lib/jsoncpp/jsoncpp.cpp +++ b/lib/jsoncpp/jsoncpp.cpp @@ -1,4 +1,4 @@ -/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). /// It is intended to be used with #include "json/json.h" // ////////////////////////////////////////////////////////////////////// @@ -147,9 +147,6 @@ static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { return result; } -/// Returns true if ch is a control character (in range [1,31]). -static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } - enum { /// Constant that specify the size of the buffer that must be passed to /// uintToString. @@ -160,7 +157,7 @@ enum { typedef char UIntToStringBuffer[uintToStringBufferSize]; /** Converts an unsigned integer to string. - * @param value Unsigned interger to convert to string + * @param value Unsigned integer to convert to string * @param current Input/Output string buffer. * Must have at least uintToStringBufferSize chars free. */ @@ -1454,7 +1451,7 @@ bool OurReader::readToken(Token& token) { token.type_ = tokenString; ok = readStringSingleQuote(); break; - } // else continue + } // else fall through case '/': token.type_ = tokenComment; ok = readComment(); @@ -2269,10 +2266,6 @@ JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { JSONCPP_STRING errs; bool ok = parseFromStream(b, sin, &root, &errs); if (!ok) { - fprintf(stderr, - "Error from reader: %s", - errs.c_str()); - throwRuntimeError(errs); } return sin; @@ -3438,7 +3431,7 @@ bool Value::empty() const { return false; } -bool Value::operator!() const { return isNull(); } +Value::operator bool() const { return ! isNull(); } void Value::clear() { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || @@ -3624,7 +3617,7 @@ Value const& Value::operator[](CppTL::ConstString const& key) const Value& Value::append(const Value& value) { return (*this)[size()] = value; } #if JSON_HAS_RVALUE_REFERENCES - Value& Value::append(Value&& value) { return (*this)[size()] = value; } + Value& Value::append(Value&& value) { return (*this)[size()] = std::move(value); } #endif Value Value::get(char const* key, char const* cend, Value const& defaultValue) const @@ -3663,20 +3656,19 @@ bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } -Value Value::removeMember(const char* key) +void Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) - return nullSingleton(); + return; - Value removed; // null - removeMember(key, key + strlen(key), &removed); - return removed; // still null if removeMember() did nothing + CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); + value_.map_->erase(actualKey); } -Value Value::removeMember(const JSONCPP_STRING& key) +void Value::removeMember(const JSONCPP_STRING& key) { - return removeMember(key.c_str()); + removeMember(key.c_str()); } bool Value::removeIndex(ArrayIndex index, Value* removed) { @@ -4233,24 +4225,6 @@ typedef std::unique_ptr<StreamWriter> StreamWriterPtr; typedef std::auto_ptr<StreamWriter> StreamWriterPtr; #endif -static bool containsControlCharacter(const char* str) { - while (*str) { - if (isControlCharacter(*(str++))) - return true; - } - return false; -} - -static bool containsControlCharacter0(const char* str, unsigned len) { - char const* end = str + len; - while (end != str) { - if (isControlCharacter(*str) || 0==*str) - return true; - ++str; - } - return false; -} - JSONCPP_STRING valueToString(LargestInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); @@ -4295,10 +4269,10 @@ JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int p int len = -1; char formatString[15]; - snprintf(formatString, sizeof(formatString), "%%.%dg", precision); + snprintf(formatString, sizeof(formatString), "%%.%ug", precision); // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distingish the + // that always has a decimal point because JSON doesn't distinguish the // concepts of reals and integers. if (isfinite(value)) { len = snprintf(buffer, sizeof(buffer), formatString, value); @@ -4328,89 +4302,103 @@ JSONCPP_STRING valueToString(double value) { return valueToString(value, false, JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } -JSONCPP_STRING valueToQuotedString(const char* value) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && - !containsControlCharacter(value)) - return JSONCPP_STRING("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to JSONCPP_STRING is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - JSONCPP_STRING::size_type maxsize = - strlen(value) * 2 + 3; // allescaped+quotes+NULL - JSONCPP_STRING result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c = value; *c != 0; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - 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; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid </ - // sequence. - // Should add a flag to allow this compatibility mode and prevent this - // sequence from occurring. - default: - if (isControlCharacter(*c)) { - JSONCPP_OSTRINGSTREAM oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') - << std::setw(4) << static_cast<int>(*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp -static char const* strnpbrk(char const* s, char const* accept, size_t n) { - assert((s || !n) && accept); +static bool isAnyCharRequiredQuoting(char const* s, size_t n) { + assert(s || !n); char const* const end = s + n; for (char const* cur = s; cur < end; ++cur) { - int const c = *cur; - for (char const* a = accept; *a; ++a) { - if (*a == c) { - return cur; - } - } + if (*cur == '\\' || *cur == '\"' || *cur < ' ' + || static_cast<unsigned char>(*cur) < 0x80) + return true; } - return NULL; + return false; } + +static unsigned int utf8ToCodepoint(const char*& s, const char* e) { + const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; + + unsigned int firstByte = static_cast<unsigned char>(*s); + + if (firstByte < 0x80) + return firstByte; + + if (firstByte < 0xE0) { + if (e - s < 2) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x1F) << 6) + | (static_cast<unsigned int>(s[1]) & 0x3F); + s += 1; + // oversized encoded characters are invalid + return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF0) { + if (e - s < 3) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x0F) << 12) + | ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) + | (static_cast<unsigned int>(s[2]) & 0x3F); + s += 2; + // surrogates aren't valid codepoints itself + // shouldn't be UTF-8 encoded + if (calculated >= 0xD800 && calculated <= 0xDFFF) + return REPLACEMENT_CHARACTER; + // oversized encoded characters are invalid + return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF8) { + if (e - s < 4) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x07) << 24) + | ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) + | ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) + | (static_cast<unsigned int>(s[3]) & 0x3F); + s += 3; + // oversized encoded characters are invalid + return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; + } + + return REPLACEMENT_CHARACTER; +} + +static const char hex2[] = + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + +static JSONCPP_STRING toHex16Bit(unsigned int x) { + const unsigned int hi = (x >> 8) & 0xff; + const unsigned int lo = x & 0xff; + JSONCPP_STRING result(4, ' '); + result[0] = hex2[2 * hi]; + result[1] = hex2[2 * hi + 1]; + result[2] = hex2[2 * lo]; + result[3] = hex2[2 * lo + 1]; + return result; +} + static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { if (value == NULL) return ""; - // Not sure how to handle unicode... - if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && - !containsControlCharacter0(value, length)) + + if (!isAnyCharRequiredQuoting(value, length)) return JSONCPP_STRING("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to JSONCPP_STRING is not efficient, but this should be rare. @@ -4452,14 +4440,24 @@ static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { // sequence. // Should add a flag to allow this compatibility mode and prevent this // sequence from occurring. - default: - if ((isControlCharacter(*c)) || (*c == 0)) { - JSONCPP_OSTRINGSTREAM oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') - << std::setw(4) << static_cast<int>(*c); - result += oss.str(); - } else { - result += *c; + default: { + unsigned int cp = utf8ToCodepoint(c, end); + // don't escape non-control characters + // (short escape sequence are applied above) + if (cp < 0x80 && cp >= 0x20) + result += static_cast<char>(cp); + else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane + result += "\\u"; + result += toHex16Bit(cp); + } + else { // codepoint is not in Basic Multilingual Plane + // convert to surrogate pair first + cp -= 0x10000; + result += "\\u"; + result += toHex16Bit((cp >> 10) + 0xD800); + result += "\\u"; + result += toHex16Bit((cp & 0x3FF) + 0xDC00); + } } break; } @@ -4468,6 +4466,10 @@ static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { return result; } +JSONCPP_STRING valueToQuotedString(const char* value) { + return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value))); +} + // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() {} @@ -4476,10 +4478,10 @@ Writer::~Writer() {} // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), omitEndingLineFeed_(false) {} -void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } +void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } @@ -4539,7 +4541,7 @@ void FastWriter::writeValue(const Value& value) { if (it != members.begin()) document_ += ','; document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); - document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + document_ += yamlCompatibilityEnabled_ ? ": " : ":"; writeValue(value[name]); } document_ += '}'; @@ -4628,7 +4630,7 @@ void StyledWriter::writeArrayValue(const Value& value) { if (size == 0) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); @@ -4666,7 +4668,7 @@ void StyledWriter::writeArrayValue(const Value& value) { } } -bool StyledWriter::isMultineArray(const Value& value) { +bool StyledWriter::isMultilineArray(const Value& value) { ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); @@ -4845,7 +4847,7 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { if (size == 0) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); @@ -4885,7 +4887,7 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { } } -bool StyledStreamWriter::isMultineArray(const Value& value) { +bool StyledStreamWriter::isMultilineArray(const Value& value) { ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); @@ -5002,7 +5004,7 @@ struct BuiltStyledStreamWriter : public StreamWriter private: void writeValue(Value const& value); void writeArrayValue(Value const& value); - bool isMultineArray(Value const& value); + bool isMultilineArray(Value const& value); void pushValue(JSONCPP_STRING const& value); void writeIndent(); void writeWithIndent(JSONCPP_STRING const& value); @@ -5126,7 +5128,7 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { if (size == 0) pushValue("[]"); else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); if (isMultiLine) { writeWithIndent("["); indent(); @@ -5168,7 +5170,7 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { } } -bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { +bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); |