// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors// Distributed under MIT license, or public domain if desired and// recognized in your jurisdiction.// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE#if !defined(JSON_IS_AMALGAMATION)#include "json/writer.h"#include "json_tool.h"#endif // if !defined(JSON_IS_AMALGAMATION)#include <iomanip>#include <memory>#include <sstream>#include <utility>#include <set>#include <cassert>#include <cstring>#include <cstdio>#ifdef WIN32#include <windows.h>#endif#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0#include <float.h>#define isfinite _finite#elif defined(__sun) && defined(__SVR4) //Solaris#if !defined(isfinite)#include <ieeefp.h>#define isfinite finite#endif#elif defined(_AIX)#if !defined(isfinite)#include <math.h>#define isfinite finite#endif#elif defined(__hpux)#if !defined(isfinite)#if defined(__ia64) && !defined(finite)#define isfinite(x) ((sizeof(x) == sizeof(float) ? \_Isfinitef(x) : _IsFinite(x)))#else#include <math.h>#define isfinite finite#endif#endif#else#include <cmath>#if !(defined(__QNXNTO__)) // QNX already defines isfinite#define isfinite std::isfinite#endif#endif#if defined(_MSC_VER)#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above#define snprintf sprintf_s#elif _MSC_VER >= 1900 // VC++ 14.0 and above#define snprintf std::snprintf#else#define snprintf _snprintf#endif#elif defined(__ANDROID__) || defined(__QNXNTO__)#define snprintf snprintf#elif __cplusplus >= 201103L#if !defined(__MINGW32__) && !defined(__CYGWIN__)#define snprintf std::snprintf#endif#endif#if defined(__BORLANDC__)#include <float.h>#define isfinite _finite#define snprintf _snprintf#endif#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0// Disable warning about strdup being deprecated.#pragma warning(disable : 4996)#endifnamespace Json {#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)typedef std::unique_ptr<StreamWriter> StreamWriterPtr;#elsetypedef std::auto_ptr<StreamWriter> StreamWriterPtr;#endifJSONCPP_STRING valueToString(LargestInt value) {UIntToStringBuffer buffer;char* current = buffer + sizeof(buffer);if (value == Value::minLargestInt) {uintToString(LargestUInt(Value::maxLargestInt) + 1, current);*--current = '-';} else if (value < 0) {uintToString(LargestUInt(-value), current);*--current = '-';} else {uintToString(LargestUInt(value), current);}assert(current >= buffer);return current;}JSONCPP_STRING valueToString(LargestUInt value) {UIntToStringBuffer buffer;char* current = buffer + sizeof(buffer);uintToString(value, current);assert(current >= buffer);return current;}#if defined(JSON_HAS_INT64)JSONCPP_STRING valueToString(Int value) {return valueToString(LargestInt(value));}JSONCPP_STRING valueToString(UInt value) {return valueToString(LargestUInt(value));}#endif // # if defined(JSON_HAS_INT64)namespace {JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {// Allocate a buffer that is more than large enough to store the 16 digits of// precision requested below.char buffer[36];int len = -1;char formatString[15];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 distinguish the// concepts of reals and integers.if (isfinite(value)) {len = snprintf(buffer, sizeof(buffer), formatString, value);fixNumericLocale(buffer, buffer + len);// try to ensure we preserve the fact that this was given to us as a double on inputif (!strchr(buffer, '.') && !strchr(buffer, 'e')) {strcat(buffer, ".0");}} else {// IEEE standard states that NaN values will not compare to themselvesif (value != value) {len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");} else if (value < 0) {len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");} else {len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");}}assert(len >= 0);return buffer;}}JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }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) {if (*cur == '\\' || *cur == '\"' || *cur < ' '|| static_cast<unsigned char>(*cur) < 0x80)return true;}return false;}#if defined(__APPLE__) && defined(__MACH__)#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wunused-function"#endifstatic 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 invalidreturn 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 encodedif (calculated >= 0xD800 && calculated >= 0xDFFF)return REPLACEMENT_CHARACTER;// oversized encoded characters are invalidreturn 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 invalidreturn calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;}return REPLACEMENT_CHARACTER;}#if defined(__APPLE__) && defined(__MACH__)#pragma clang diagnostic pop#endifstatic 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;}JSONCPP_STRING UTF82WCS(const char* szU8){JSONCPP_STRING ret;size_t u8size = strlen(szU8);const UTF8* Src = (const UTF8*)(szU8);const UTF8* SrcEnd = Src + u8size;ret.resize(u8size * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);UTF16* Dst = reinterpret_cast<UTF16*>(&ret[0]);UTF16* DstEnd = reinterpret_cast<UTF16*>(&ret[ret.size() - 1]);ConversionResult result = ConvertUTF8toUTF16(&Src, SrcEnd, &Dst, DstEnd, ConversionFlags::strictConversion);if (result != conversionOK && result != sourceExhausted) {ret.clear();return ret;}ret.resize(reinterpret_cast<char*>(Dst) - &ret[0]);return ret;}JSONCPP_STRING ANSI2WCS(const char* szU8){#ifdef WIN32int nLen = ::MultiByteToWideChar(CP_ACP, 0, szU8, -1, NULL, NULL); //将MultiByteToWideChar()的第四个形参设为-1,即可返回长度wchar_t *pTemp = new wchar_t[nLen]; //new一个wchar_t空间,保存Unicode串memset(pTemp, 0, nLen * sizeof(wchar_t));::MultiByteToWideChar(CP_ACP, 0, szU8, -1, (LPWSTR)pTemp, nLen);JSONCPP_STRING unicodeString((char *)pTemp, lstrlenW((LPCWSTR(pTemp))) * 2);unicodeString.append("0円0円", 2);if (pTemp){delete[] pTemp;pTemp = NULL;}#elseJSONCPP_STRING unicodeString;std::string curLocale = setlocale(LC_ALL, NULL);setlocale(LC_ALL, "zh_CN.utf8");int wcsLen = mbstowcs(NULL, szU8, 0) + 1;if (wcsLen == 0) {setlocale(LC_ALL, curLocale.c_str());return unicodeString;}wchar_t* wszString = new wchar_t[wcsLen + 1];int ret = mbstowcs(wszString, szU8, strlen(szU8) + 1);setlocale(LC_ALL, curLocale.c_str());if (ret <= 0) {return unicodeString;}unicodeString.append((const char*)wszString, wcsLen * sizeof(wchar_t));unicodeString.append("0円0円", 2);delete[] wszString;wszString = NULL;#endifreturn unicodeString;}static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length, int encodeType) {if (value == NULL)return "";if (!isAnyCharRequiredQuoting(value, length))return JSONCPP_STRING("\"") + value + "\"";JSONCPP_STRING result;JSONCPP_STRING::size_type maxsize =length * 2 + 3; // allescaped+quotes+NULLresult.reserve(maxsize); // to avoid lots of mallocsresult += "\"";//char const* end = value + length;if (encodeType == encode_ascii){JSONCPP_STRING v = ANSI2WCS(value);for (int i = 0; i < int(v.size() / 2); i++){unsigned short ret = *((unsigned short*)(v.c_str() + i * 2));switch (ret){case 0:break;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;default: {if (ret < 0x80 && ret >= 0x20)result += static_cast<char>(ret);else {result += "\\u";result += toHex16Bit(static_cast<unsigned int>(ret));}}}}}else if (encodeType == encode_unicode){for (int i = 0; i < int(length/2); i++){unsigned short ret = *((unsigned short*)(value + i * 2));switch (ret){case 0:break;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;default: {if (ret < 0x80 && ret >= 0x20)result += static_cast<char>(ret);else {result += "\\u";result += toHex16Bit(static_cast<unsigned int>(ret));}}}}}else if (encodeType == encode_utf8){JSONCPP_STRING v = UTF82WCS(value);for (int i = 0; i < int(v.size() / 2); i++){unsigned short ret = *((unsigned short*)(v.c_str() + i * 2));switch (ret){case 0:break;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;default: {if (ret < 0x80 && ret >= 0x20)result += static_cast<char>(ret);else {result += "\\u";result += toHex16Bit(static_cast<unsigned int>(ret));}}}}}result += "\"";return result;}JSONCPP_STRING valueToQuotedString(const char* value) {return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)), encode_utf8);}// Class Writer// //////////////////////////////////////////////////////////////////Writer::~Writer() {}// Class FastWriter// //////////////////////////////////////////////////////////////////FastWriter::FastWriter(): yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),omitEndingLineFeed_(false) {}void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }JSONCPP_STRING FastWriter::write(const Value& root) {document_.clear();writeValue(root,root.encodeType_);return document_;}void FastWriter::writeValue(const Value& value, int encodeType) {switch (value.type()) {case nullValue:if (!dropNullPlaceholders_)document_ += "null";break;case intValue:document_ += valueToString(value.asLargestInt());break;case uintValue:document_ += valueToString(value.asLargestUInt());break;case realValue:document_ += valueToString(value.asDouble());break;case stringValue:{// Is NULL possible for value.string_? No.char const* str;char const* end;bool ok = value.getString(&str, &end);if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str), encodeType);break;}case booleanValue:document_ += valueToString(value.asBool());break;case arrayValue: {document_ += '[';ArrayIndex size = value.size();for (ArrayIndex index = 0; index < size; ++index) {if (index > 0)document_ += ',';writeValue(value[index], encodeType);}document_ += ']';} break;case objectValue: {Value::Members members(value.getMemberNames());document_ += '{';for (Value::Members::iterator it = members.begin(); it != members.end();++it) {const JSONCPP_STRING& name = *it;if (it != members.begin())document_ += ',';document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()), encodeType);document_ += yamlCompatibilityEnabled_ ? ":" : ":";writeValue(value[name],encodeType);}document_ += '}';} break;}}// Class StyledWriter// //////////////////////////////////////////////////////////////////StyledWriter::StyledWriter(): rightMargin_(74), indentSize_(3), addChildValues_() {}JSONCPP_STRING StyledWriter::write(const Value& root) {document_.clear();addChildValues_ = false;indentString_.clear();writeCommentBeforeValue(root);writeValue(root,root.encodeType_);writeCommentAfterValueOnSameLine(root);return document_;}void StyledWriter::writeValue(const Value& value, int encodeType) {switch (value.type()) {case nullValue:pushValue("null");break;case intValue:pushValue(valueToString(value.asLargestInt()));break;case uintValue:pushValue(valueToString(value.asLargestUInt()));break;case realValue:pushValue(valueToString(value.asDouble()));break;case stringValue:{// Is NULL possible for value.string_? No.char const* str;char const* end;bool ok = value.getString(&str, &end);if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str), encodeType));else pushValue("");break;}case booleanValue:pushValue(valueToString(value.asBool()));break;case arrayValue:writeArrayValue(value,encodeType);break;case objectValue: {Value::Members members(value.getMemberNames());if (members.empty())pushValue("{}");else {writeWithIndent("{");indent();Value::Members::iterator it = members.begin();for (;;) {const JSONCPP_STRING& name = *it;const Value& childValue = value[name];writeCommentBeforeValue(childValue);writeWithIndent(valueToQuotedString(name.c_str()));document_ += ":";writeValue(childValue, encodeType);if (++it == members.end()) {writeCommentAfterValueOnSameLine(childValue);break;}document_ += ',';writeCommentAfterValueOnSameLine(childValue);}unindent();writeWithIndent("}");}} break;}}void StyledWriter::writeArrayValue(const Value& value, int encodeType) {unsigned size = value.size();if (size == 0)pushValue("[]");else {bool isArrayMultiLine = isMultilineArray(value,encodeType);if (isArrayMultiLine) {writeWithIndent("[");indent();bool hasChildValue = !childValues_.empty();unsigned index = 0;for (;;) {const Value& childValue = value[index];writeCommentBeforeValue(childValue);if (hasChildValue)writeWithIndent(childValues_[index]);else {writeIndent();writeValue(childValue, encodeType);}if (++index == size) {writeCommentAfterValueOnSameLine(childValue);break;}document_ += ',';writeCommentAfterValueOnSameLine(childValue);}unindent();writeWithIndent("]");} else // output on a single line{assert(childValues_.size() == size);document_ += "[ ";for (unsigned index = 0; index < size; ++index) {if (index > 0)document_ += ", ";document_ += childValues_[index];}document_ += " ]";}}}bool StyledWriter::isMultilineArray(const Value& value, int encodeType) {ArrayIndex const size = value.size();bool isMultiLine = size * 3 >= rightMargin_;childValues_.clear();for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {const Value& childValue = value[index];isMultiLine = ((childValue.isArray() || childValue.isObject()) &&childValue.size() > 0);}if (!isMultiLine) // check if line length > max line length{childValues_.reserve(size);addChildValues_ = true;ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'for (ArrayIndex index = 0; index < size; ++index) {if (hasCommentForValue(value[index])) {isMultiLine = true;}writeValue(value[index], encodeType);lineLength += static_cast<ArrayIndex>(childValues_[index].length());}addChildValues_ = false;isMultiLine = isMultiLine || lineLength >= rightMargin_;}return isMultiLine;}void StyledWriter::pushValue(const JSONCPP_STRING& value) {if (addChildValues_)childValues_.push_back(value);elsedocument_ += value;}void StyledWriter::writeIndent() {if (!document_.empty()) {char last = document_[document_.length() - 1];if (last == ' ') // already indentedreturn;if (last != '\n') // Comments may add new-linedocument_ += '\n';}document_ += indentString_;}void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {writeIndent();document_ += value;}void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }void StyledWriter::unindent() {assert(indentString_.size() >= indentSize_);indentString_.resize(indentString_.size() - indentSize_);}void StyledWriter::writeCommentBeforeValue(const Value& root) {if (!root.hasComment(commentBefore))return;writeIndent();const JSONCPP_STRING& comment = root.getComment(commentBefore);JSONCPP_STRING::const_iterator iter = comment.begin();while (iter != comment.end()) {document_ += *iter;if (*iter == '\n' &&((iter+1) != comment.end() && *(iter + 1) == '/'))writeIndent();++iter;}// Comments are stripped of trailing newlines, so add one here}void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {if (root.hasComment(commentAfterOnSameLine))document_ += root.getComment(commentAfterOnSameLine);if (root.hasComment(commentAfter)) {document_ += root.getComment(commentAfter);}}bool StyledWriter::hasCommentForValue(const Value& value) {return value.hasComment(commentBefore) ||value.hasComment(commentAfterOnSameLine) ||value.hasComment(commentAfter);}// Class StyledStreamWriter// //////////////////////////////////////////////////////////////////StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation): document_(NULL), rightMargin_(74), indentation_(indentation),addChildValues_() {}void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {document_ = &out;addChildValues_ = false;indentString_.clear();indented_ = true;writeCommentBeforeValue(root);if (!indented_) writeIndent();indented_ = true;writeValue(root,root.encodeType_);writeCommentAfterValueOnSameLine(root);document_ = NULL; // Forget the stream, for safety.}void StyledStreamWriter::writeValue(const Value& value,int encodeType) {switch (value.type()) {case nullValue:pushValue("null");break;case intValue:pushValue(valueToString(value.asLargestInt()));break;case uintValue:pushValue(valueToString(value.asLargestUInt()));break;case realValue:pushValue(valueToString(value.asDouble()));break;case stringValue:{// Is NULL possible for value.string_? No.char const* str;char const* end;bool ok = value.getString(&str, &end);if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str), encodeType));else pushValue("");break;}case booleanValue:pushValue(valueToString(value.asBool()));break;case arrayValue:writeArrayValue(value, encodeType);break;case objectValue: {Value::Members members(value.getMemberNames());if (members.empty())pushValue("{}");else {writeWithIndent("{");indent();Value::Members::iterator it = members.begin();for (;;) {const JSONCPP_STRING& name = *it;const Value& childValue = value[name];writeCommentBeforeValue(childValue);writeWithIndent(valueToQuotedString(name.c_str()));*document_ << ":";writeValue(childValue, encodeType);if (++it == members.end()) {writeCommentAfterValueOnSameLine(childValue);break;}*document_ << ",";writeCommentAfterValueOnSameLine(childValue);}unindent();writeWithIndent("}");}} break;}}void StyledStreamWriter::writeArrayValue(const Value& value,int encodeType) {unsigned size = value.size();if (size == 0)pushValue("[]");else {bool isArrayMultiLine = isMultilineArray(value, encodeType);if (isArrayMultiLine) {writeWithIndent("[");indent();bool hasChildValue = !childValues_.empty();unsigned index = 0;for (;;) {const Value& childValue = value[index];writeCommentBeforeValue(childValue);if (hasChildValue)writeWithIndent(childValues_[index]);else {if (!indented_) writeIndent();indented_ = true;writeValue(childValue, encodeType);indented_ = false;}if (++index == size) {writeCommentAfterValueOnSameLine(childValue);break;}*document_ << ",";writeCommentAfterValueOnSameLine(childValue);}unindent();writeWithIndent("]");} else // output on a single line{assert(childValues_.size() == size);*document_ << "[ ";for (unsigned index = 0; index < size; ++index) {if (index > 0)*document_ << ", ";*document_ << childValues_[index];}*document_ << " ]";}}}bool StyledStreamWriter::isMultilineArray(const Value& value, int encodeType) {ArrayIndex const size = value.size();bool isMultiLine = size * 3 >= rightMargin_;childValues_.clear();for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {const Value& childValue = value[index];isMultiLine = ((childValue.isArray() || childValue.isObject()) &&childValue.size() > 0);}if (!isMultiLine) // check if line length > max line length{childValues_.reserve(size);addChildValues_ = true;ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'for (ArrayIndex index = 0; index < size; ++index) {if (hasCommentForValue(value[index])) {isMultiLine = true;}writeValue(value[index], encodeType);lineLength += static_cast<ArrayIndex>(childValues_[index].length());}addChildValues_ = false;isMultiLine = isMultiLine || lineLength >= rightMargin_;}return isMultiLine;}void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {if (addChildValues_)childValues_.push_back(value);else*document_ << value;}void StyledStreamWriter::writeIndent() {// blep intended this to look at the so-far-written string// to determine whether we are already indented, but// with a stream we cannot do that. So we rely on some saved state.// The caller checks indented_.*document_ << '\n' << indentString_;}void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {if (!indented_) writeIndent();*document_ << value;indented_ = false;}void StyledStreamWriter::indent() { indentString_ += indentation_; }void StyledStreamWriter::unindent() {assert(indentString_.size() >= indentation_.size());indentString_.resize(indentString_.size() - indentation_.size());}void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {if (!root.hasComment(commentBefore))return;if (!indented_) writeIndent();const JSONCPP_STRING& comment = root.getComment(commentBefore);JSONCPP_STRING::const_iterator iter = comment.begin();while (iter != comment.end()) {*document_ << *iter;if (*iter == '\n' &&((iter+1) != comment.end() && *(iter + 1) == '/'))// writeIndent(); // would include newline*document_ << indentString_;++iter;}indented_ = false;}void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {if (root.hasComment(commentAfterOnSameLine))*document_ << ' ' << root.getComment(commentAfterOnSameLine);if (root.hasComment(commentAfter)) {writeIndent();*document_ << root.getComment(commentAfter);}indented_ = false;}bool StyledStreamWriter::hasCommentForValue(const Value& value) {return value.hasComment(commentBefore) ||value.hasComment(commentAfterOnSameLine) ||value.hasComment(commentAfter);}//////////////////////////// BuiltStyledStreamWriter/// Scoped enums are not available until C++11.struct CommentStyle {/// Decide whether to write comments.enum Enum {None, ///< Drop all comments.Most, ///< Recover odd behavior of previous versions (not implemented yet).All ///< Keep all comments.};};struct BuiltStyledStreamWriter : public StreamWriter{BuiltStyledStreamWriter(JSONCPP_STRING const& indentation,CommentStyle::Enum cs,JSONCPP_STRING const& colonSymbol,JSONCPP_STRING const& nullSymbol,JSONCPP_STRING const& endingLineFeedSymbol,bool useSpecialFloats,unsigned int precision);int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;private:void writeValue(Value const& value, int encodeType);void writeArrayValue(Value const& value, int encodeType);bool isMultilineArray(Value const& value, int encodeType);void pushValue(JSONCPP_STRING const& value);void writeIndent();void writeWithIndent(JSONCPP_STRING const& value);void indent();void unindent();void writeCommentBeforeValue(Value const& root);void writeCommentAfterValueOnSameLine(Value const& root);static bool hasCommentForValue(const Value& value);typedef std::vector<JSONCPP_STRING> ChildValues;ChildValues childValues_;JSONCPP_STRING indentString_;unsigned int rightMargin_;JSONCPP_STRING indentation_;CommentStyle::Enum cs_;JSONCPP_STRING colonSymbol_;JSONCPP_STRING nullSymbol_;JSONCPP_STRING endingLineFeedSymbol_;bool addChildValues_ : 1;bool indented_ : 1;bool useSpecialFloats_ : 1;unsigned int precision_;};BuiltStyledStreamWriter::BuiltStyledStreamWriter(JSONCPP_STRING const& indentation,CommentStyle::Enum cs,JSONCPP_STRING const& colonSymbol,JSONCPP_STRING const& nullSymbol,JSONCPP_STRING const& endingLineFeedSymbol,bool useSpecialFloats,unsigned int precision): rightMargin_(74), indentation_(indentation), cs_(cs), colonSymbol_(colonSymbol), nullSymbol_(nullSymbol), endingLineFeedSymbol_(endingLineFeedSymbol), addChildValues_(false), indented_(false), useSpecialFloats_(useSpecialFloats), precision_(precision){}int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout){sout_ = sout;addChildValues_ = false;indented_ = true;indentString_.clear();writeCommentBeforeValue(root);if (!indented_) writeIndent();indented_ = true;writeValue(root,root.encodeType_);writeCommentAfterValueOnSameLine(root);*sout_ << endingLineFeedSymbol_;sout_ = NULL;return 0;}void BuiltStyledStreamWriter::writeValue(Value const& value,int encodeType) {switch (value.type()) {case nullValue:pushValue(nullSymbol_);break;case intValue:pushValue(valueToString(value.asLargestInt()));break;case uintValue:pushValue(valueToString(value.asLargestUInt()));break;case realValue:pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));break;case stringValue:{// Is NULL is possible for value.string_? No.char const* str;char const* end;bool ok = value.getString(&str, &end);if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str), encodeType));else pushValue("");break;}case booleanValue:pushValue(valueToString(value.asBool()));break;case arrayValue:writeArrayValue(value, encodeType);break;case objectValue: {Value::Members members(value.getMemberNames());if (members.empty())pushValue("{}");else {writeWithIndent("{");indent();Value::Members::iterator it = members.begin();for (;;) {JSONCPP_STRING const& name = *it;Value const& childValue = value[name];writeCommentBeforeValue(childValue);writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()), encodeType));*sout_ << colonSymbol_;writeValue(childValue, encodeType);if (++it == members.end()) {writeCommentAfterValueOnSameLine(childValue);break;}*sout_ << ",";writeCommentAfterValueOnSameLine(childValue);}unindent();writeWithIndent("}");}} break;}}void BuiltStyledStreamWriter::writeArrayValue(Value const& value,int encodeType) {unsigned size = value.size();if (size == 0)pushValue("[]");else {bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value, encodeType);if (isMultiLine) {writeWithIndent("[");indent();bool hasChildValue = !childValues_.empty();unsigned index = 0;for (;;) {Value const& childValue = value[index];writeCommentBeforeValue(childValue);if (hasChildValue)writeWithIndent(childValues_[index]);else {if (!indented_) writeIndent();indented_ = true;writeValue(childValue,encodeType);indented_ = false;}if (++index == size) {writeCommentAfterValueOnSameLine(childValue);break;}*sout_ << ",";writeCommentAfterValueOnSameLine(childValue);}unindent();writeWithIndent("]");} else // output on a single line{assert(childValues_.size() == size);*sout_ << "[";for (unsigned index = 0; index < size; ++index) {if (index > 0)*sout_ << ((!indentation_.empty()) ? "," : ",");*sout_ << childValues_[index];}*sout_ << "]";}}}bool BuiltStyledStreamWriter::isMultilineArray(Value const& value, int encodeType) {ArrayIndex const size = value.size();bool isMultiLine = size * 3 >= rightMargin_;childValues_.clear();for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {Value const& childValue = value[index];isMultiLine = ((childValue.isArray() || childValue.isObject()) &&childValue.size() > 0);}if (!isMultiLine) // check if line length > max line length{childValues_.reserve(size);addChildValues_ = true;ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'for (ArrayIndex index = 0; index < size; ++index) {if (hasCommentForValue(value[index])) {isMultiLine = true;}writeValue(value[index],encodeType);lineLength += static_cast<ArrayIndex>(childValues_[index].length());}addChildValues_ = false;isMultiLine = isMultiLine || lineLength >= rightMargin_;}return isMultiLine;}void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {if (addChildValues_)childValues_.push_back(value);else*sout_ << value;}void BuiltStyledStreamWriter::writeIndent() {// blep intended this to look at the so-far-written string// to determine whether we are already indented, but// with a stream we cannot do that. So we rely on some saved state.// The caller checks indented_.if (!indentation_.empty()) {// In this case, drop newlines too.}}void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {if (!indented_) writeIndent();*sout_ << value;indented_ = false;}void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }void BuiltStyledStreamWriter::unindent() {assert(indentString_.size() >= indentation_.size());indentString_.resize(indentString_.size() - indentation_.size());}void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {if (cs_ == CommentStyle::None) return;if (!root.hasComment(commentBefore))return;if (!indented_) writeIndent();const JSONCPP_STRING& comment = root.getComment(commentBefore);JSONCPP_STRING::const_iterator iter = comment.begin();while (iter != comment.end()) {*sout_ << *iter;if (*iter == '\n' &&((iter+1) != comment.end() && *(iter + 1) == '/'))// writeIndent(); // would write extra newline*sout_ << indentString_;++iter;}indented_ = false;}void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {if (cs_ == CommentStyle::None) return;if (root.hasComment(commentAfterOnSameLine))*sout_ << root.getComment(commentAfterOnSameLine);if (root.hasComment(commentAfter)) {writeIndent();*sout_ << root.getComment(commentAfter);}}// staticbool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {return value.hasComment(commentBefore) ||value.hasComment(commentAfterOnSameLine) ||value.hasComment(commentAfter);}///////////////// StreamWriterStreamWriter::StreamWriter(): sout_(NULL){}StreamWriter::~StreamWriter(){}StreamWriter::Factory::~Factory(){}StreamWriterBuilder::StreamWriterBuilder(){setDefaults(&settings_);}StreamWriterBuilder::~StreamWriterBuilder(){}StreamWriter* StreamWriterBuilder::newStreamWriter() const{JSONCPP_STRING indentation = settings_["indentation"].asString();JSONCPP_STRING cs_str = settings_["commentStyle"].asString();bool eyc = settings_["enableYAMLCompatibility"].asBool();bool dnp = settings_["dropNullPlaceholders"].asBool();bool usf = settings_["useSpecialFloats"].asBool();unsigned int pre = settings_["precision"].asUInt();CommentStyle::Enum cs = CommentStyle::All;if (cs_str == "All") {cs = CommentStyle::All;} else if (cs_str == "None") {cs = CommentStyle::None;} else {throwRuntimeError("commentStyle must be 'All' or 'None'");}JSONCPP_STRING colonSymbol = ":";if (eyc) {colonSymbol = ": ";} else if (indentation.empty()) {colonSymbol = ":";}JSONCPP_STRING nullSymbol = "null";if (dnp) {nullSymbol.clear();}if (pre > 17) pre = 17;JSONCPP_STRING endingLineFeedSymbol;return new BuiltStyledStreamWriter(indentation, cs,colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);}static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys){valid_keys->clear();valid_keys->insert("indentation");valid_keys->insert("commentStyle");valid_keys->insert("enableYAMLCompatibility");valid_keys->insert("dropNullPlaceholders");valid_keys->insert("useSpecialFloats");valid_keys->insert("precision");}bool StreamWriterBuilder::validate(Json::Value* invalid) const{Json::Value my_invalid;if (!invalid) invalid = &my_invalid; // so we do not need to test for NULLJson::Value& inv = *invalid;std::set<JSONCPP_STRING> valid_keys;getValidWriterKeys(&valid_keys);Value::Members keys = settings_.getMemberNames();size_t n = keys.size();for (size_t i = 0; i < n; ++i) {JSONCPP_STRING const& key = keys[i];if (valid_keys.find(key) == valid_keys.end()) {inv[key] = settings_[key];}}return 0u == inv.size();}Value& StreamWriterBuilder::operator[](JSONCPP_STRING key){return settings_[key];}// staticvoid StreamWriterBuilder::setDefaults(Json::Value* settings){//! [StreamWriterBuilderDefaults](*settings)["commentStyle"] = "All";(*settings)["indentation"] = "\t";(*settings)["enableYAMLCompatibility"] = false;(*settings)["dropNullPlaceholders"] = false;(*settings)["useSpecialFloats"] = false;(*settings)["precision"] = 17;//! [StreamWriterBuilderDefaults]}JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {JSONCPP_OSTRINGSTREAM sout;StreamWriterPtr const writer(builder.newStreamWriter());writer->write(root, &sout);return sout.str();}JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {StreamWriterBuilder builder;StreamWriterPtr const writer(builder.newStreamWriter());writer->write(root, &sout);return sout;}} // namespace Json
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. 开源生态
2. 协作、人、软件
3. 评估模型