json test

Committer:
tgw
Date:
Fri Jan 26 06:05:31 2018 +0000
Revision:
0:2ee762ea11b3
json

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tgw 0:2ee762ea11b3 1 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
tgw 0:2ee762ea11b3 2 // Distributed under MIT license, or public domain if desired and
tgw 0:2ee762ea11b3 3 // recognized in your jurisdiction.
tgw 0:2ee762ea11b3 4 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
tgw 0:2ee762ea11b3 5
tgw 0:2ee762ea11b3 6 #if !defined(JSON_IS_AMALGAMATION)
tgw 0:2ee762ea11b3 7 #include <json/writer.h>
tgw 0:2ee762ea11b3 8 #include "json_tool.h"
tgw 0:2ee762ea11b3 9 #endif // if !defined(JSON_IS_AMALGAMATION)
tgw 0:2ee762ea11b3 10 #include <iomanip>
tgw 0:2ee762ea11b3 11 #include <memory>
tgw 0:2ee762ea11b3 12 #include <sstream>
tgw 0:2ee762ea11b3 13 #include <utility>
tgw 0:2ee762ea11b3 14 #include <set>
tgw 0:2ee762ea11b3 15 #include <cassert>
tgw 0:2ee762ea11b3 16 #include <cstring>
tgw 0:2ee762ea11b3 17 #include <cstdio>
tgw 0:2ee762ea11b3 18
tgw 0:2ee762ea11b3 19 #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
tgw 0:2ee762ea11b3 20 #include <float.h>
tgw 0:2ee762ea11b3 21 #define isfinite _finite
tgw 0:2ee762ea11b3 22 #elif defined(__sun) && defined(__SVR4) //Solaris
tgw 0:2ee762ea11b3 23 #if !defined(isfinite)
tgw 0:2ee762ea11b3 24 #include <ieeefp.h>
tgw 0:2ee762ea11b3 25 #define isfinite finite
tgw 0:2ee762ea11b3 26 #endif
tgw 0:2ee762ea11b3 27 #elif defined(_AIX)
tgw 0:2ee762ea11b3 28 #if !defined(isfinite)
tgw 0:2ee762ea11b3 29 #include <math.h>
tgw 0:2ee762ea11b3 30 #define isfinite finite
tgw 0:2ee762ea11b3 31 #endif
tgw 0:2ee762ea11b3 32 #elif defined(__hpux)
tgw 0:2ee762ea11b3 33 #if !defined(isfinite)
tgw 0:2ee762ea11b3 34 #if defined(__ia64) && !defined(finite)
tgw 0:2ee762ea11b3 35 #define isfinite(x) ((sizeof(x) == sizeof(float) ? \
tgw 0:2ee762ea11b3 36 _Isfinitef(x) : _IsFinite(x)))
tgw 0:2ee762ea11b3 37 #else
tgw 0:2ee762ea11b3 38 #include <math.h>
tgw 0:2ee762ea11b3 39 #define isfinite finite
tgw 0:2ee762ea11b3 40 #endif
tgw 0:2ee762ea11b3 41 #endif
tgw 0:2ee762ea11b3 42 #else
tgw 0:2ee762ea11b3 43 #include <cmath>
tgw 0:2ee762ea11b3 44 #if !(defined(__QNXNTO__)) // QNX already defines isfinite
tgw 0:2ee762ea11b3 45 #define isfinite std::isfinite
tgw 0:2ee762ea11b3 46 #endif
tgw 0:2ee762ea11b3 47 #endif
tgw 0:2ee762ea11b3 48
tgw 0:2ee762ea11b3 49 #if defined(_MSC_VER)
tgw 0:2ee762ea11b3 50 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
tgw 0:2ee762ea11b3 51 #define snprintf sprintf_s
tgw 0:2ee762ea11b3 52 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
tgw 0:2ee762ea11b3 53 #define snprintf std::snprintf
tgw 0:2ee762ea11b3 54 #else
tgw 0:2ee762ea11b3 55 #define snprintf _snprintf
tgw 0:2ee762ea11b3 56 #endif
tgw 0:2ee762ea11b3 57 #elif defined(__ANDROID__) || defined(__QNXNTO__)
tgw 0:2ee762ea11b3 58 #define snprintf snprintf
tgw 0:2ee762ea11b3 59 #elif __cplusplus >= 201103L
tgw 0:2ee762ea11b3 60 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
tgw 0:2ee762ea11b3 61 #define snprintf std::snprintf
tgw 0:2ee762ea11b3 62 #endif
tgw 0:2ee762ea11b3 63 #endif
tgw 0:2ee762ea11b3 64
tgw 0:2ee762ea11b3 65 #if defined(__BORLANDC__)
tgw 0:2ee762ea11b3 66 #include <float.h>
tgw 0:2ee762ea11b3 67 #define isfinite _finite
tgw 0:2ee762ea11b3 68 #define snprintf _snprintf
tgw 0:2ee762ea11b3 69 #endif
tgw 0:2ee762ea11b3 70
tgw 0:2ee762ea11b3 71 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
tgw 0:2ee762ea11b3 72 // Disable warning about strdup being deprecated.
tgw 0:2ee762ea11b3 73 #pragma warning(disable : 4996)
tgw 0:2ee762ea11b3 74 #endif
tgw 0:2ee762ea11b3 75 using namespace std;
tgw 0:2ee762ea11b3 76 namespace Json {
tgw 0:2ee762ea11b3 77
tgw 0:2ee762ea11b3 78 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
tgw 0:2ee762ea11b3 79 typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
tgw 0:2ee762ea11b3 80 #else
tgw 0:2ee762ea11b3 81 typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
tgw 0:2ee762ea11b3 82 #endif
tgw 0:2ee762ea11b3 83
tgw 0:2ee762ea11b3 84 JSONCPP_STRING valueToString(LargestInt value) {
tgw 0:2ee762ea11b3 85 UIntToStringBuffer buffer;
tgw 0:2ee762ea11b3 86 char* current = buffer + sizeof(buffer);
tgw 0:2ee762ea11b3 87 if (value == Value::minLargestInt) {
tgw 0:2ee762ea11b3 88 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
tgw 0:2ee762ea11b3 89 *--current = '-';
tgw 0:2ee762ea11b3 90 } else if (value < 0) {
tgw 0:2ee762ea11b3 91 uintToString(LargestUInt(-value), current);
tgw 0:2ee762ea11b3 92 *--current = '-';
tgw 0:2ee762ea11b3 93 } else {
tgw 0:2ee762ea11b3 94 uintToString(LargestUInt(value), current);
tgw 0:2ee762ea11b3 95 }
tgw 0:2ee762ea11b3 96 assert(current >= buffer);
tgw 0:2ee762ea11b3 97 return current;
tgw 0:2ee762ea11b3 98 }
tgw 0:2ee762ea11b3 99
tgw 0:2ee762ea11b3 100 JSONCPP_STRING valueToString(LargestUInt value) {
tgw 0:2ee762ea11b3 101 UIntToStringBuffer buffer;
tgw 0:2ee762ea11b3 102 char* current = buffer + sizeof(buffer);
tgw 0:2ee762ea11b3 103 uintToString(value, current);
tgw 0:2ee762ea11b3 104 assert(current >= buffer);
tgw 0:2ee762ea11b3 105 return current;
tgw 0:2ee762ea11b3 106 }
tgw 0:2ee762ea11b3 107
tgw 0:2ee762ea11b3 108 #if defined(JSON_HAS_INT64)
tgw 0:2ee762ea11b3 109
tgw 0:2ee762ea11b3 110 JSONCPP_STRING valueToString(Int value) {
tgw 0:2ee762ea11b3 111 return valueToString(LargestInt(value));
tgw 0:2ee762ea11b3 112 }
tgw 0:2ee762ea11b3 113
tgw 0:2ee762ea11b3 114 JSONCPP_STRING valueToString(UInt value) {
tgw 0:2ee762ea11b3 115 return valueToString(LargestUInt(value));
tgw 0:2ee762ea11b3 116 }
tgw 0:2ee762ea11b3 117
tgw 0:2ee762ea11b3 118 #endif // # if defined(JSON_HAS_INT64)
tgw 0:2ee762ea11b3 119
tgw 0:2ee762ea11b3 120 namespace {
tgw 0:2ee762ea11b3 121 JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
tgw 0:2ee762ea11b3 122 // Allocate a buffer that is more than large enough to store the 16 digits of
tgw 0:2ee762ea11b3 123 // precision requested below.
tgw 0:2ee762ea11b3 124 char buffer[36];
tgw 0:2ee762ea11b3 125 int len = -1;
tgw 0:2ee762ea11b3 126
tgw 0:2ee762ea11b3 127 char formatString[15];
tgw 0:2ee762ea11b3 128 snprintf(formatString, sizeof(formatString), "%%.%ug", precision);
tgw 0:2ee762ea11b3 129
tgw 0:2ee762ea11b3 130 // Print into the buffer. We need not request the alternative representation
tgw 0:2ee762ea11b3 131 // that always has a decimal point because JSON doesn't distinguish the
tgw 0:2ee762ea11b3 132 // concepts of reals and integers.
tgw 0:2ee762ea11b3 133 if (isfinite(value)) {
tgw 0:2ee762ea11b3 134 len = snprintf(buffer, sizeof(buffer), formatString, value);
tgw 0:2ee762ea11b3 135 fixNumericLocale(buffer, buffer + len);
tgw 0:2ee762ea11b3 136
tgw 0:2ee762ea11b3 137 // try to ensure we preserve the fact that this was given to us as a double on input
tgw 0:2ee762ea11b3 138 if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
tgw 0:2ee762ea11b3 139 strcat(buffer, ".0");
tgw 0:2ee762ea11b3 140 }
tgw 0:2ee762ea11b3 141
tgw 0:2ee762ea11b3 142 } else {
tgw 0:2ee762ea11b3 143 // IEEE standard states that NaN values will not compare to themselves
tgw 0:2ee762ea11b3 144 if (value != value) {
tgw 0:2ee762ea11b3 145 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
tgw 0:2ee762ea11b3 146 } else if (value < 0) {
tgw 0:2ee762ea11b3 147 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
tgw 0:2ee762ea11b3 148 } else {
tgw 0:2ee762ea11b3 149 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
tgw 0:2ee762ea11b3 150 }
tgw 0:2ee762ea11b3 151 }
tgw 0:2ee762ea11b3 152 assert(len >= 0);
tgw 0:2ee762ea11b3 153 return buffer;
tgw 0:2ee762ea11b3 154 }
tgw 0:2ee762ea11b3 155 }
tgw 0:2ee762ea11b3 156
tgw 0:2ee762ea11b3 157 JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
tgw 0:2ee762ea11b3 158
tgw 0:2ee762ea11b3 159 JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
tgw 0:2ee762ea11b3 160
tgw 0:2ee762ea11b3 161 static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
tgw 0:2ee762ea11b3 162 assert(s || !n);
tgw 0:2ee762ea11b3 163
tgw 0:2ee762ea11b3 164 char const* const end = s + n;
tgw 0:2ee762ea11b3 165 for (char const* cur = s; cur < end; ++cur) {
tgw 0:2ee762ea11b3 166 if (*cur == '\\' || *cur == '\"' || *cur < ' '
tgw 0:2ee762ea11b3 167 || static_cast<unsigned char>(*cur) < 0x80)
tgw 0:2ee762ea11b3 168 return true;
tgw 0:2ee762ea11b3 169 }
tgw 0:2ee762ea11b3 170 return false;
tgw 0:2ee762ea11b3 171 }
tgw 0:2ee762ea11b3 172
tgw 0:2ee762ea11b3 173 static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
tgw 0:2ee762ea11b3 174 const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
tgw 0:2ee762ea11b3 175
tgw 0:2ee762ea11b3 176 unsigned int firstByte = static_cast<unsigned char>(*s);
tgw 0:2ee762ea11b3 177
tgw 0:2ee762ea11b3 178 if (firstByte < 0x80)
tgw 0:2ee762ea11b3 179 return firstByte;
tgw 0:2ee762ea11b3 180
tgw 0:2ee762ea11b3 181 if (firstByte < 0xE0) {
tgw 0:2ee762ea11b3 182 if (e - s < 2)
tgw 0:2ee762ea11b3 183 return REPLACEMENT_CHARACTER;
tgw 0:2ee762ea11b3 184
tgw 0:2ee762ea11b3 185 unsigned int calculated = ((firstByte & 0x1F) << 6)
tgw 0:2ee762ea11b3 186 | (static_cast<unsigned int>(s[1]) & 0x3F);
tgw 0:2ee762ea11b3 187 s += 1;
tgw 0:2ee762ea11b3 188 // oversized encoded characters are invalid
tgw 0:2ee762ea11b3 189 return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
tgw 0:2ee762ea11b3 190 }
tgw 0:2ee762ea11b3 191
tgw 0:2ee762ea11b3 192 if (firstByte < 0xF0) {
tgw 0:2ee762ea11b3 193 if (e - s < 3)
tgw 0:2ee762ea11b3 194 return REPLACEMENT_CHARACTER;
tgw 0:2ee762ea11b3 195
tgw 0:2ee762ea11b3 196 unsigned int calculated = ((firstByte & 0x0F) << 12)
tgw 0:2ee762ea11b3 197 | ((static_cast<unsigned int>(s[1]) & 0x3F) << 6)
tgw 0:2ee762ea11b3 198 | (static_cast<unsigned int>(s[2]) & 0x3F);
tgw 0:2ee762ea11b3 199 s += 2;
tgw 0:2ee762ea11b3 200 // surrogates aren't valid codepoints itself
tgw 0:2ee762ea11b3 201 // shouldn't be UTF-8 encoded
tgw 0:2ee762ea11b3 202 if (calculated >= 0xD800 && calculated <= 0xDFFF)
tgw 0:2ee762ea11b3 203 return REPLACEMENT_CHARACTER;
tgw 0:2ee762ea11b3 204 // oversized encoded characters are invalid
tgw 0:2ee762ea11b3 205 return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
tgw 0:2ee762ea11b3 206 }
tgw 0:2ee762ea11b3 207
tgw 0:2ee762ea11b3 208 if (firstByte < 0xF8) {
tgw 0:2ee762ea11b3 209 if (e - s < 4)
tgw 0:2ee762ea11b3 210 return REPLACEMENT_CHARACTER;
tgw 0:2ee762ea11b3 211
tgw 0:2ee762ea11b3 212 unsigned int calculated = ((firstByte & 0x07) << 24)
tgw 0:2ee762ea11b3 213 | ((static_cast<unsigned int>(s[1]) & 0x3F) << 12)
tgw 0:2ee762ea11b3 214 | ((static_cast<unsigned int>(s[2]) & 0x3F) << 6)
tgw 0:2ee762ea11b3 215 | (static_cast<unsigned int>(s[3]) & 0x3F);
tgw 0:2ee762ea11b3 216 s += 3;
tgw 0:2ee762ea11b3 217 // oversized encoded characters are invalid
tgw 0:2ee762ea11b3 218 return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
tgw 0:2ee762ea11b3 219 }
tgw 0:2ee762ea11b3 220
tgw 0:2ee762ea11b3 221 return REPLACEMENT_CHARACTER;
tgw 0:2ee762ea11b3 222 }
tgw 0:2ee762ea11b3 223
tgw 0:2ee762ea11b3 224 static const char hex2[] =
tgw 0:2ee762ea11b3 225 "000102030405060708090a0b0c0d0e0f"
tgw 0:2ee762ea11b3 226 "101112131415161718191a1b1c1d1e1f"
tgw 0:2ee762ea11b3 227 "202122232425262728292a2b2c2d2e2f"
tgw 0:2ee762ea11b3 228 "303132333435363738393a3b3c3d3e3f"
tgw 0:2ee762ea11b3 229 "404142434445464748494a4b4c4d4e4f"
tgw 0:2ee762ea11b3 230 "505152535455565758595a5b5c5d5e5f"
tgw 0:2ee762ea11b3 231 "606162636465666768696a6b6c6d6e6f"
tgw 0:2ee762ea11b3 232 "707172737475767778797a7b7c7d7e7f"
tgw 0:2ee762ea11b3 233 "808182838485868788898a8b8c8d8e8f"
tgw 0:2ee762ea11b3 234 "909192939495969798999a9b9c9d9e9f"
tgw 0:2ee762ea11b3 235 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
tgw 0:2ee762ea11b3 236 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
tgw 0:2ee762ea11b3 237 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
tgw 0:2ee762ea11b3 238 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
tgw 0:2ee762ea11b3 239 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
tgw 0:2ee762ea11b3 240 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
tgw 0:2ee762ea11b3 241
tgw 0:2ee762ea11b3 242 static JSONCPP_STRING toHex16Bit(unsigned int x) {
tgw 0:2ee762ea11b3 243 const unsigned int hi = (x >> 8) & 0xff;
tgw 0:2ee762ea11b3 244 const unsigned int lo = x & 0xff;
tgw 0:2ee762ea11b3 245 JSONCPP_STRING result(4, ' ');
tgw 0:2ee762ea11b3 246 result[0] = hex2[2 * hi];
tgw 0:2ee762ea11b3 247 result[1] = hex2[2 * hi + 1];
tgw 0:2ee762ea11b3 248 result[2] = hex2[2 * lo];
tgw 0:2ee762ea11b3 249 result[3] = hex2[2 * lo + 1];
tgw 0:2ee762ea11b3 250 return result;
tgw 0:2ee762ea11b3 251 }
tgw 0:2ee762ea11b3 252
tgw 0:2ee762ea11b3 253 static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
tgw 0:2ee762ea11b3 254 if (value == NULL)
tgw 0:2ee762ea11b3 255 return "";
tgw 0:2ee762ea11b3 256
tgw 0:2ee762ea11b3 257 if (!isAnyCharRequiredQuoting(value, length))
tgw 0:2ee762ea11b3 258 return JSONCPP_STRING("\"") + value + "\"";
tgw 0:2ee762ea11b3 259 // We have to walk value and escape any special characters.
tgw 0:2ee762ea11b3 260 // Appending to JSONCPP_STRING is not efficient, but this should be rare.
tgw 0:2ee762ea11b3 261 // (Note: forward slashes are *not* rare, but I am not escaping them.)
tgw 0:2ee762ea11b3 262 JSONCPP_STRING::size_type maxsize =
tgw 0:2ee762ea11b3 263 length * 2 + 3; // allescaped+quotes+NULL
tgw 0:2ee762ea11b3 264 JSONCPP_STRING result;
tgw 0:2ee762ea11b3 265 result.reserve(maxsize); // to avoid lots of mallocs
tgw 0:2ee762ea11b3 266 result += "\"";
tgw 0:2ee762ea11b3 267 char const* end = value + length;
tgw 0:2ee762ea11b3 268 for (const char* c = value; c != end; ++c) {
tgw 0:2ee762ea11b3 269 switch (*c) {
tgw 0:2ee762ea11b3 270 case '\"':
tgw 0:2ee762ea11b3 271 result += "\\\"";
tgw 0:2ee762ea11b3 272 break;
tgw 0:2ee762ea11b3 273 case '\\':
tgw 0:2ee762ea11b3 274 result += "\\\\";
tgw 0:2ee762ea11b3 275 break;
tgw 0:2ee762ea11b3 276 case '\b':
tgw 0:2ee762ea11b3 277 result += "\\b";
tgw 0:2ee762ea11b3 278 break;
tgw 0:2ee762ea11b3 279 case '\f':
tgw 0:2ee762ea11b3 280 result += "\\f";
tgw 0:2ee762ea11b3 281 break;
tgw 0:2ee762ea11b3 282 case '\n':
tgw 0:2ee762ea11b3 283 result += "\\n";
tgw 0:2ee762ea11b3 284 break;
tgw 0:2ee762ea11b3 285 case '\r':
tgw 0:2ee762ea11b3 286 result += "\\r";
tgw 0:2ee762ea11b3 287 break;
tgw 0:2ee762ea11b3 288 case '\t':
tgw 0:2ee762ea11b3 289 result += "\\t";
tgw 0:2ee762ea11b3 290 break;
tgw 0:2ee762ea11b3 291 // case '/':
tgw 0:2ee762ea11b3 292 // Even though \/ is considered a legal escape in JSON, a bare
tgw 0:2ee762ea11b3 293 // slash is also legal, so I see no reason to escape it.
tgw 0:2ee762ea11b3 294 // (I hope I am not misunderstanding something.)
tgw 0:2ee762ea11b3 295 // blep notes: actually escaping \/ may be useful in javascript to avoid </
tgw 0:2ee762ea11b3 296 // sequence.
tgw 0:2ee762ea11b3 297 // Should add a flag to allow this compatibility mode and prevent this
tgw 0:2ee762ea11b3 298 // sequence from occurring.
tgw 0:2ee762ea11b3 299 default: {
tgw 0:2ee762ea11b3 300 unsigned int cp = utf8ToCodepoint(c, end);
tgw 0:2ee762ea11b3 301 // don't escape non-control characters
tgw 0:2ee762ea11b3 302 // (short escape sequence are applied above)
tgw 0:2ee762ea11b3 303 if (cp < 0x80 && cp >= 0x20)
tgw 0:2ee762ea11b3 304 result += static_cast<char>(cp);
tgw 0:2ee762ea11b3 305 else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane
tgw 0:2ee762ea11b3 306 result += "\\u";
tgw 0:2ee762ea11b3 307 result += toHex16Bit(cp);
tgw 0:2ee762ea11b3 308 }
tgw 0:2ee762ea11b3 309 else { // codepoint is not in Basic Multilingual Plane
tgw 0:2ee762ea11b3 310 // convert to surrogate pair first
tgw 0:2ee762ea11b3 311 cp -= 0x10000;
tgw 0:2ee762ea11b3 312 result += "\\u";
tgw 0:2ee762ea11b3 313 result += toHex16Bit((cp >> 10) + 0xD800);
tgw 0:2ee762ea11b3 314 result += "\\u";
tgw 0:2ee762ea11b3 315 result += toHex16Bit((cp & 0x3FF) + 0xDC00);
tgw 0:2ee762ea11b3 316 }
tgw 0:2ee762ea11b3 317 }
tgw 0:2ee762ea11b3 318 break;
tgw 0:2ee762ea11b3 319 }
tgw 0:2ee762ea11b3 320 }
tgw 0:2ee762ea11b3 321 result += "\"";
tgw 0:2ee762ea11b3 322 return result;
tgw 0:2ee762ea11b3 323 }
tgw 0:2ee762ea11b3 324
tgw 0:2ee762ea11b3 325 JSONCPP_STRING valueToQuotedString(const char* value) {
tgw 0:2ee762ea11b3 326 return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
tgw 0:2ee762ea11b3 327 }
tgw 0:2ee762ea11b3 328
tgw 0:2ee762ea11b3 329 // Class Writer
tgw 0:2ee762ea11b3 330 // //////////////////////////////////////////////////////////////////
tgw 0:2ee762ea11b3 331 Writer::~Writer() {}
tgw 0:2ee762ea11b3 332
tgw 0:2ee762ea11b3 333 // Class FastWriter
tgw 0:2ee762ea11b3 334 // //////////////////////////////////////////////////////////////////
tgw 0:2ee762ea11b3 335
tgw 0:2ee762ea11b3 336 FastWriter::FastWriter()
tgw 0:2ee762ea11b3 337 : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),
tgw 0:2ee762ea11b3 338 omitEndingLineFeed_(false) {}
tgw 0:2ee762ea11b3 339
tgw 0:2ee762ea11b3 340 void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
tgw 0:2ee762ea11b3 341
tgw 0:2ee762ea11b3 342 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
tgw 0:2ee762ea11b3 343
tgw 0:2ee762ea11b3 344 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
tgw 0:2ee762ea11b3 345
tgw 0:2ee762ea11b3 346 JSONCPP_STRING FastWriter::write(const Value& root) {
tgw 0:2ee762ea11b3 347 document_.clear();
tgw 0:2ee762ea11b3 348 writeValue(root);
tgw 0:2ee762ea11b3 349 if (!omitEndingLineFeed_)
tgw 0:2ee762ea11b3 350 document_ += "\n";
tgw 0:2ee762ea11b3 351 return document_;
tgw 0:2ee762ea11b3 352 }
tgw 0:2ee762ea11b3 353
tgw 0:2ee762ea11b3 354 void FastWriter::writeValue(const Value& value) {
tgw 0:2ee762ea11b3 355 switch (value.type()) {
tgw 0:2ee762ea11b3 356 case nullValue:
tgw 0:2ee762ea11b3 357 if (!dropNullPlaceholders_)
tgw 0:2ee762ea11b3 358 document_ += "null";
tgw 0:2ee762ea11b3 359 break;
tgw 0:2ee762ea11b3 360 case intValue:
tgw 0:2ee762ea11b3 361 document_ += valueToString(value.asLargestInt());
tgw 0:2ee762ea11b3 362 break;
tgw 0:2ee762ea11b3 363 case uintValue:
tgw 0:2ee762ea11b3 364 document_ += valueToString(value.asLargestUInt());
tgw 0:2ee762ea11b3 365 break;
tgw 0:2ee762ea11b3 366 case realValue:
tgw 0:2ee762ea11b3 367 document_ += valueToString(value.asDouble());
tgw 0:2ee762ea11b3 368 break;
tgw 0:2ee762ea11b3 369 case stringValue:
tgw 0:2ee762ea11b3 370 {
tgw 0:2ee762ea11b3 371 // Is NULL possible for value.string_? No.
tgw 0:2ee762ea11b3 372 char const* str;
tgw 0:2ee762ea11b3 373 char const* end;
tgw 0:2ee762ea11b3 374 bool ok = value.getString(&str, &end);
tgw 0:2ee762ea11b3 375 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
tgw 0:2ee762ea11b3 376 break;
tgw 0:2ee762ea11b3 377 }
tgw 0:2ee762ea11b3 378 case booleanValue:
tgw 0:2ee762ea11b3 379 document_ += valueToString(value.asBool());
tgw 0:2ee762ea11b3 380 break;
tgw 0:2ee762ea11b3 381 case arrayValue: {
tgw 0:2ee762ea11b3 382 document_ += '[';
tgw 0:2ee762ea11b3 383 ArrayIndex size = value.size();
tgw 0:2ee762ea11b3 384 for (ArrayIndex index = 0; index < size; ++index) {
tgw 0:2ee762ea11b3 385 if (index > 0)
tgw 0:2ee762ea11b3 386 document_ += ',';
tgw 0:2ee762ea11b3 387 writeValue(value[index]);
tgw 0:2ee762ea11b3 388 }
tgw 0:2ee762ea11b3 389 document_ += ']';
tgw 0:2ee762ea11b3 390 } break;
tgw 0:2ee762ea11b3 391 case objectValue: {
tgw 0:2ee762ea11b3 392 Value::Members members(value.getMemberNames());
tgw 0:2ee762ea11b3 393 document_ += '{';
tgw 0:2ee762ea11b3 394 for (Value::Members::iterator it = members.begin(); it != members.end();
tgw 0:2ee762ea11b3 395 ++it) {
tgw 0:2ee762ea11b3 396 const JSONCPP_STRING& name = *it;
tgw 0:2ee762ea11b3 397 if (it != members.begin())
tgw 0:2ee762ea11b3 398 document_ += ',';
tgw 0:2ee762ea11b3 399 document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
tgw 0:2ee762ea11b3 400 document_ += yamlCompatibilityEnabled_ ? ": " : ":";
tgw 0:2ee762ea11b3 401 writeValue(value[name]);
tgw 0:2ee762ea11b3 402 }
tgw 0:2ee762ea11b3 403 document_ += '}';
tgw 0:2ee762ea11b3 404 } break;
tgw 0:2ee762ea11b3 405 }
tgw 0:2ee762ea11b3 406 }
tgw 0:2ee762ea11b3 407
tgw 0:2ee762ea11b3 408 // Class StyledWriter
tgw 0:2ee762ea11b3 409 // //////////////////////////////////////////////////////////////////
tgw 0:2ee762ea11b3 410
tgw 0:2ee762ea11b3 411 StyledWriter::StyledWriter()
tgw 0:2ee762ea11b3 412 : rightMargin_(74), indentSize_(3), addChildValues_() {}
tgw 0:2ee762ea11b3 413
tgw 0:2ee762ea11b3 414 JSONCPP_STRING StyledWriter::write(const Value& root) {
tgw 0:2ee762ea11b3 415 document_.clear();
tgw 0:2ee762ea11b3 416 addChildValues_ = false;
tgw 0:2ee762ea11b3 417 indentString_.clear();
tgw 0:2ee762ea11b3 418 writeCommentBeforeValue(root);
tgw 0:2ee762ea11b3 419 writeValue(root);
tgw 0:2ee762ea11b3 420 writeCommentAfterValueOnSameLine(root);
tgw 0:2ee762ea11b3 421 document_ += "\n";
tgw 0:2ee762ea11b3 422 return document_;
tgw 0:2ee762ea11b3 423 }
tgw 0:2ee762ea11b3 424
tgw 0:2ee762ea11b3 425 void StyledWriter::writeValue(const Value& value) {
tgw 0:2ee762ea11b3 426 switch (value.type()) {
tgw 0:2ee762ea11b3 427 case nullValue:
tgw 0:2ee762ea11b3 428 pushValue("null");
tgw 0:2ee762ea11b3 429 break;
tgw 0:2ee762ea11b3 430 case intValue:
tgw 0:2ee762ea11b3 431 pushValue(valueToString(value.asLargestInt()));
tgw 0:2ee762ea11b3 432 break;
tgw 0:2ee762ea11b3 433 case uintValue:
tgw 0:2ee762ea11b3 434 pushValue(valueToString(value.asLargestUInt()));
tgw 0:2ee762ea11b3 435 break;
tgw 0:2ee762ea11b3 436 case realValue:
tgw 0:2ee762ea11b3 437 pushValue(valueToString(value.asDouble()));
tgw 0:2ee762ea11b3 438 break;
tgw 0:2ee762ea11b3 439 case stringValue:
tgw 0:2ee762ea11b3 440 {
tgw 0:2ee762ea11b3 441 // Is NULL possible for value.string_? No.
tgw 0:2ee762ea11b3 442 char const* str;
tgw 0:2ee762ea11b3 443 char const* end;
tgw 0:2ee762ea11b3 444 bool ok = value.getString(&str, &end);
tgw 0:2ee762ea11b3 445 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
tgw 0:2ee762ea11b3 446 else pushValue("");
tgw 0:2ee762ea11b3 447 break;
tgw 0:2ee762ea11b3 448 }
tgw 0:2ee762ea11b3 449 case booleanValue:
tgw 0:2ee762ea11b3 450 pushValue(valueToString(value.asBool()));
tgw 0:2ee762ea11b3 451 break;
tgw 0:2ee762ea11b3 452 case arrayValue:
tgw 0:2ee762ea11b3 453 writeArrayValue(value);
tgw 0:2ee762ea11b3 454 break;
tgw 0:2ee762ea11b3 455 case objectValue: {
tgw 0:2ee762ea11b3 456 Value::Members members(value.getMemberNames());
tgw 0:2ee762ea11b3 457 if (members.empty())
tgw 0:2ee762ea11b3 458 pushValue("{}");
tgw 0:2ee762ea11b3 459 else {
tgw 0:2ee762ea11b3 460 writeWithIndent("{");
tgw 0:2ee762ea11b3 461 indent();
tgw 0:2ee762ea11b3 462 Value::Members::iterator it = members.begin();
tgw 0:2ee762ea11b3 463 for (;;) {
tgw 0:2ee762ea11b3 464 const JSONCPP_STRING& name = *it;
tgw 0:2ee762ea11b3 465 const Value& childValue = value[name];
tgw 0:2ee762ea11b3 466 writeCommentBeforeValue(childValue);
tgw 0:2ee762ea11b3 467 writeWithIndent(valueToQuotedString(name.c_str()));
tgw 0:2ee762ea11b3 468 document_ += " : ";
tgw 0:2ee762ea11b3 469 writeValue(childValue);
tgw 0:2ee762ea11b3 470 if (++it == members.end()) {
tgw 0:2ee762ea11b3 471 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 472 break;
tgw 0:2ee762ea11b3 473 }
tgw 0:2ee762ea11b3 474 document_ += ',';
tgw 0:2ee762ea11b3 475 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 476 }
tgw 0:2ee762ea11b3 477 unindent();
tgw 0:2ee762ea11b3 478 writeWithIndent("}");
tgw 0:2ee762ea11b3 479 }
tgw 0:2ee762ea11b3 480 } break;
tgw 0:2ee762ea11b3 481 }
tgw 0:2ee762ea11b3 482 }
tgw 0:2ee762ea11b3 483
tgw 0:2ee762ea11b3 484 void StyledWriter::writeArrayValue(const Value& value) {
tgw 0:2ee762ea11b3 485 unsigned size = value.size();
tgw 0:2ee762ea11b3 486 if (size == 0)
tgw 0:2ee762ea11b3 487 pushValue("[]");
tgw 0:2ee762ea11b3 488 else {
tgw 0:2ee762ea11b3 489 bool isArrayMultiLine = isMultilineArray(value);
tgw 0:2ee762ea11b3 490 if (isArrayMultiLine) {
tgw 0:2ee762ea11b3 491 writeWithIndent("[");
tgw 0:2ee762ea11b3 492 indent();
tgw 0:2ee762ea11b3 493 bool hasChildValue = !childValues_.empty();
tgw 0:2ee762ea11b3 494 unsigned index = 0;
tgw 0:2ee762ea11b3 495 for (;;) {
tgw 0:2ee762ea11b3 496 const Value& childValue = value[index];
tgw 0:2ee762ea11b3 497 writeCommentBeforeValue(childValue);
tgw 0:2ee762ea11b3 498 if (hasChildValue)
tgw 0:2ee762ea11b3 499 writeWithIndent(childValues_[index]);
tgw 0:2ee762ea11b3 500 else {
tgw 0:2ee762ea11b3 501 writeIndent();
tgw 0:2ee762ea11b3 502 writeValue(childValue);
tgw 0:2ee762ea11b3 503 }
tgw 0:2ee762ea11b3 504 if (++index == size) {
tgw 0:2ee762ea11b3 505 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 506 break;
tgw 0:2ee762ea11b3 507 }
tgw 0:2ee762ea11b3 508 document_ += ',';
tgw 0:2ee762ea11b3 509 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 510 }
tgw 0:2ee762ea11b3 511 unindent();
tgw 0:2ee762ea11b3 512 writeWithIndent("]");
tgw 0:2ee762ea11b3 513 } else // output on a single line
tgw 0:2ee762ea11b3 514 {
tgw 0:2ee762ea11b3 515 assert(childValues_.size() == size);
tgw 0:2ee762ea11b3 516 document_ += "[ ";
tgw 0:2ee762ea11b3 517 for (unsigned index = 0; index < size; ++index) {
tgw 0:2ee762ea11b3 518 if (index > 0)
tgw 0:2ee762ea11b3 519 document_ += ", ";
tgw 0:2ee762ea11b3 520 document_ += childValues_[index];
tgw 0:2ee762ea11b3 521 }
tgw 0:2ee762ea11b3 522 document_ += " ]";
tgw 0:2ee762ea11b3 523 }
tgw 0:2ee762ea11b3 524 }
tgw 0:2ee762ea11b3 525 }
tgw 0:2ee762ea11b3 526
tgw 0:2ee762ea11b3 527 bool StyledWriter::isMultilineArray(const Value& value) {
tgw 0:2ee762ea11b3 528 ArrayIndex const size = value.size();
tgw 0:2ee762ea11b3 529 bool isMultiLine = size * 3 >= rightMargin_;
tgw 0:2ee762ea11b3 530 childValues_.clear();
tgw 0:2ee762ea11b3 531 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
tgw 0:2ee762ea11b3 532 const Value& childValue = value[index];
tgw 0:2ee762ea11b3 533 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
tgw 0:2ee762ea11b3 534 childValue.size() > 0);
tgw 0:2ee762ea11b3 535 }
tgw 0:2ee762ea11b3 536 if (!isMultiLine) // check if line length > max line length
tgw 0:2ee762ea11b3 537 {
tgw 0:2ee762ea11b3 538 childValues_.reserve(size);
tgw 0:2ee762ea11b3 539 addChildValues_ = true;
tgw 0:2ee762ea11b3 540 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
tgw 0:2ee762ea11b3 541 for (ArrayIndex index = 0; index < size; ++index) {
tgw 0:2ee762ea11b3 542 if (hasCommentForValue(value[index])) {
tgw 0:2ee762ea11b3 543 isMultiLine = true;
tgw 0:2ee762ea11b3 544 }
tgw 0:2ee762ea11b3 545 writeValue(value[index]);
tgw 0:2ee762ea11b3 546 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
tgw 0:2ee762ea11b3 547 }
tgw 0:2ee762ea11b3 548 addChildValues_ = false;
tgw 0:2ee762ea11b3 549 isMultiLine = isMultiLine || lineLength >= rightMargin_;
tgw 0:2ee762ea11b3 550 }
tgw 0:2ee762ea11b3 551 return isMultiLine;
tgw 0:2ee762ea11b3 552 }
tgw 0:2ee762ea11b3 553
tgw 0:2ee762ea11b3 554 void StyledWriter::pushValue(const JSONCPP_STRING& value) {
tgw 0:2ee762ea11b3 555 if (addChildValues_)
tgw 0:2ee762ea11b3 556 childValues_.push_back(value);
tgw 0:2ee762ea11b3 557 else
tgw 0:2ee762ea11b3 558 document_ += value;
tgw 0:2ee762ea11b3 559 }
tgw 0:2ee762ea11b3 560
tgw 0:2ee762ea11b3 561 void StyledWriter::writeIndent() {
tgw 0:2ee762ea11b3 562 if (!document_.empty()) {
tgw 0:2ee762ea11b3 563 char last = document_[document_.length() - 1];
tgw 0:2ee762ea11b3 564 if (last == ' ') // already indented
tgw 0:2ee762ea11b3 565 return;
tgw 0:2ee762ea11b3 566 if (last != '\n') // Comments may add new-line
tgw 0:2ee762ea11b3 567 document_ += '\n';
tgw 0:2ee762ea11b3 568 }
tgw 0:2ee762ea11b3 569 document_ += indentString_;
tgw 0:2ee762ea11b3 570 }
tgw 0:2ee762ea11b3 571
tgw 0:2ee762ea11b3 572 void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {
tgw 0:2ee762ea11b3 573 writeIndent();
tgw 0:2ee762ea11b3 574 document_ += value;
tgw 0:2ee762ea11b3 575 }
tgw 0:2ee762ea11b3 576
tgw 0:2ee762ea11b3 577 void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
tgw 0:2ee762ea11b3 578
tgw 0:2ee762ea11b3 579 void StyledWriter::unindent() {
tgw 0:2ee762ea11b3 580 assert(indentString_.size() >= indentSize_);
tgw 0:2ee762ea11b3 581 indentString_.resize(indentString_.size() - indentSize_);
tgw 0:2ee762ea11b3 582 }
tgw 0:2ee762ea11b3 583
tgw 0:2ee762ea11b3 584 void StyledWriter::writeCommentBeforeValue(const Value& root) {
tgw 0:2ee762ea11b3 585 if (!root.hasComment(commentBefore))
tgw 0:2ee762ea11b3 586 return;
tgw 0:2ee762ea11b3 587
tgw 0:2ee762ea11b3 588 document_ += "\n";
tgw 0:2ee762ea11b3 589 writeIndent();
tgw 0:2ee762ea11b3 590 const JSONCPP_STRING& comment = root.getComment(commentBefore);
tgw 0:2ee762ea11b3 591 JSONCPP_STRING::const_iterator iter = comment.begin();
tgw 0:2ee762ea11b3 592 while (iter != comment.end()) {
tgw 0:2ee762ea11b3 593 document_ += *iter;
tgw 0:2ee762ea11b3 594 if (*iter == '\n' &&
tgw 0:2ee762ea11b3 595 ((iter+1) != comment.end() && *(iter + 1) == '/'))
tgw 0:2ee762ea11b3 596 writeIndent();
tgw 0:2ee762ea11b3 597 ++iter;
tgw 0:2ee762ea11b3 598 }
tgw 0:2ee762ea11b3 599
tgw 0:2ee762ea11b3 600 // Comments are stripped of trailing newlines, so add one here
tgw 0:2ee762ea11b3 601 document_ += "\n";
tgw 0:2ee762ea11b3 602 }
tgw 0:2ee762ea11b3 603
tgw 0:2ee762ea11b3 604 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
tgw 0:2ee762ea11b3 605 if (root.hasComment(commentAfterOnSameLine))
tgw 0:2ee762ea11b3 606 document_ += " " + root.getComment(commentAfterOnSameLine);
tgw 0:2ee762ea11b3 607
tgw 0:2ee762ea11b3 608 if (root.hasComment(commentAfter)) {
tgw 0:2ee762ea11b3 609 document_ += "\n";
tgw 0:2ee762ea11b3 610 document_ += root.getComment(commentAfter);
tgw 0:2ee762ea11b3 611 document_ += "\n";
tgw 0:2ee762ea11b3 612 }
tgw 0:2ee762ea11b3 613 }
tgw 0:2ee762ea11b3 614
tgw 0:2ee762ea11b3 615 bool StyledWriter::hasCommentForValue(const Value& value) {
tgw 0:2ee762ea11b3 616 return value.hasComment(commentBefore) ||
tgw 0:2ee762ea11b3 617 value.hasComment(commentAfterOnSameLine) ||
tgw 0:2ee762ea11b3 618 value.hasComment(commentAfter);
tgw 0:2ee762ea11b3 619 }
tgw 0:2ee762ea11b3 620
tgw 0:2ee762ea11b3 621 // Class StyledStreamWriter
tgw 0:2ee762ea11b3 622 // //////////////////////////////////////////////////////////////////
tgw 0:2ee762ea11b3 623
tgw 0:2ee762ea11b3 624 StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
tgw 0:2ee762ea11b3 625 : document_(NULL), rightMargin_(74), indentation_(indentation),
tgw 0:2ee762ea11b3 626 addChildValues_() {}
tgw 0:2ee762ea11b3 627
tgw 0:2ee762ea11b3 628 void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {
tgw 0:2ee762ea11b3 629 document_ = &out;
tgw 0:2ee762ea11b3 630 addChildValues_ = false;
tgw 0:2ee762ea11b3 631 indentString_.clear();
tgw 0:2ee762ea11b3 632 indented_ = true;
tgw 0:2ee762ea11b3 633 writeCommentBeforeValue(root);
tgw 0:2ee762ea11b3 634 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 635 indented_ = true;
tgw 0:2ee762ea11b3 636 writeValue(root);
tgw 0:2ee762ea11b3 637 writeCommentAfterValueOnSameLine(root);
tgw 0:2ee762ea11b3 638 *document_ << "\n";
tgw 0:2ee762ea11b3 639 document_ = NULL; // Forget the stream, for safety.
tgw 0:2ee762ea11b3 640 }
tgw 0:2ee762ea11b3 641
tgw 0:2ee762ea11b3 642 void StyledStreamWriter::writeValue(const Value& value) {
tgw 0:2ee762ea11b3 643 switch (value.type()) {
tgw 0:2ee762ea11b3 644 case nullValue:
tgw 0:2ee762ea11b3 645 pushValue("null");
tgw 0:2ee762ea11b3 646 break;
tgw 0:2ee762ea11b3 647 case intValue:
tgw 0:2ee762ea11b3 648 pushValue(valueToString(value.asLargestInt()));
tgw 0:2ee762ea11b3 649 break;
tgw 0:2ee762ea11b3 650 case uintValue:
tgw 0:2ee762ea11b3 651 pushValue(valueToString(value.asLargestUInt()));
tgw 0:2ee762ea11b3 652 break;
tgw 0:2ee762ea11b3 653 case realValue:
tgw 0:2ee762ea11b3 654 pushValue(valueToString(value.asDouble()));
tgw 0:2ee762ea11b3 655 break;
tgw 0:2ee762ea11b3 656 case stringValue:
tgw 0:2ee762ea11b3 657 {
tgw 0:2ee762ea11b3 658 // Is NULL possible for value.string_? No.
tgw 0:2ee762ea11b3 659 char const* str;
tgw 0:2ee762ea11b3 660 char const* end;
tgw 0:2ee762ea11b3 661 bool ok = value.getString(&str, &end);
tgw 0:2ee762ea11b3 662 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
tgw 0:2ee762ea11b3 663 else pushValue("");
tgw 0:2ee762ea11b3 664 break;
tgw 0:2ee762ea11b3 665 }
tgw 0:2ee762ea11b3 666 case booleanValue:
tgw 0:2ee762ea11b3 667 pushValue(valueToString(value.asBool()));
tgw 0:2ee762ea11b3 668 break;
tgw 0:2ee762ea11b3 669 case arrayValue:
tgw 0:2ee762ea11b3 670 writeArrayValue(value);
tgw 0:2ee762ea11b3 671 break;
tgw 0:2ee762ea11b3 672 case objectValue: {
tgw 0:2ee762ea11b3 673 Value::Members members(value.getMemberNames());
tgw 0:2ee762ea11b3 674 if (members.empty())
tgw 0:2ee762ea11b3 675 pushValue("{}");
tgw 0:2ee762ea11b3 676 else {
tgw 0:2ee762ea11b3 677 writeWithIndent("{");
tgw 0:2ee762ea11b3 678 indent();
tgw 0:2ee762ea11b3 679 Value::Members::iterator it = members.begin();
tgw 0:2ee762ea11b3 680 for (;;) {
tgw 0:2ee762ea11b3 681 const JSONCPP_STRING& name = *it;
tgw 0:2ee762ea11b3 682 const Value& childValue = value[name];
tgw 0:2ee762ea11b3 683 writeCommentBeforeValue(childValue);
tgw 0:2ee762ea11b3 684 writeWithIndent(valueToQuotedString(name.c_str()));
tgw 0:2ee762ea11b3 685 *document_ << " : ";
tgw 0:2ee762ea11b3 686 writeValue(childValue);
tgw 0:2ee762ea11b3 687 if (++it == members.end()) {
tgw 0:2ee762ea11b3 688 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 689 break;
tgw 0:2ee762ea11b3 690 }
tgw 0:2ee762ea11b3 691 *document_ << ",";
tgw 0:2ee762ea11b3 692 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 693 }
tgw 0:2ee762ea11b3 694 unindent();
tgw 0:2ee762ea11b3 695 writeWithIndent("}");
tgw 0:2ee762ea11b3 696 }
tgw 0:2ee762ea11b3 697 } break;
tgw 0:2ee762ea11b3 698 }
tgw 0:2ee762ea11b3 699 }
tgw 0:2ee762ea11b3 700
tgw 0:2ee762ea11b3 701 void StyledStreamWriter::writeArrayValue(const Value& value) {
tgw 0:2ee762ea11b3 702 unsigned size = value.size();
tgw 0:2ee762ea11b3 703 if (size == 0)
tgw 0:2ee762ea11b3 704 pushValue("[]");
tgw 0:2ee762ea11b3 705 else {
tgw 0:2ee762ea11b3 706 bool isArrayMultiLine = isMultilineArray(value);
tgw 0:2ee762ea11b3 707 if (isArrayMultiLine) {
tgw 0:2ee762ea11b3 708 writeWithIndent("[");
tgw 0:2ee762ea11b3 709 indent();
tgw 0:2ee762ea11b3 710 bool hasChildValue = !childValues_.empty();
tgw 0:2ee762ea11b3 711 unsigned index = 0;
tgw 0:2ee762ea11b3 712 for (;;) {
tgw 0:2ee762ea11b3 713 const Value& childValue = value[index];
tgw 0:2ee762ea11b3 714 writeCommentBeforeValue(childValue);
tgw 0:2ee762ea11b3 715 if (hasChildValue)
tgw 0:2ee762ea11b3 716 writeWithIndent(childValues_[index]);
tgw 0:2ee762ea11b3 717 else {
tgw 0:2ee762ea11b3 718 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 719 indented_ = true;
tgw 0:2ee762ea11b3 720 writeValue(childValue);
tgw 0:2ee762ea11b3 721 indented_ = false;
tgw 0:2ee762ea11b3 722 }
tgw 0:2ee762ea11b3 723 if (++index == size) {
tgw 0:2ee762ea11b3 724 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 725 break;
tgw 0:2ee762ea11b3 726 }
tgw 0:2ee762ea11b3 727 *document_ << ",";
tgw 0:2ee762ea11b3 728 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 729 }
tgw 0:2ee762ea11b3 730 unindent();
tgw 0:2ee762ea11b3 731 writeWithIndent("]");
tgw 0:2ee762ea11b3 732 } else // output on a single line
tgw 0:2ee762ea11b3 733 {
tgw 0:2ee762ea11b3 734 assert(childValues_.size() == size);
tgw 0:2ee762ea11b3 735 *document_ << "[ ";
tgw 0:2ee762ea11b3 736 for (unsigned index = 0; index < size; ++index) {
tgw 0:2ee762ea11b3 737 if (index > 0)
tgw 0:2ee762ea11b3 738 *document_ << ", ";
tgw 0:2ee762ea11b3 739 *document_ << childValues_[index];
tgw 0:2ee762ea11b3 740 }
tgw 0:2ee762ea11b3 741 *document_ << " ]";
tgw 0:2ee762ea11b3 742 }
tgw 0:2ee762ea11b3 743 }
tgw 0:2ee762ea11b3 744 }
tgw 0:2ee762ea11b3 745
tgw 0:2ee762ea11b3 746 bool StyledStreamWriter::isMultilineArray(const Value& value) {
tgw 0:2ee762ea11b3 747 ArrayIndex const size = value.size();
tgw 0:2ee762ea11b3 748 bool isMultiLine = size * 3 >= rightMargin_;
tgw 0:2ee762ea11b3 749 childValues_.clear();
tgw 0:2ee762ea11b3 750 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
tgw 0:2ee762ea11b3 751 const Value& childValue = value[index];
tgw 0:2ee762ea11b3 752 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
tgw 0:2ee762ea11b3 753 childValue.size() > 0);
tgw 0:2ee762ea11b3 754 }
tgw 0:2ee762ea11b3 755 if (!isMultiLine) // check if line length > max line length
tgw 0:2ee762ea11b3 756 {
tgw 0:2ee762ea11b3 757 childValues_.reserve(size);
tgw 0:2ee762ea11b3 758 addChildValues_ = true;
tgw 0:2ee762ea11b3 759 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
tgw 0:2ee762ea11b3 760 for (ArrayIndex index = 0; index < size; ++index) {
tgw 0:2ee762ea11b3 761 if (hasCommentForValue(value[index])) {
tgw 0:2ee762ea11b3 762 isMultiLine = true;
tgw 0:2ee762ea11b3 763 }
tgw 0:2ee762ea11b3 764 writeValue(value[index]);
tgw 0:2ee762ea11b3 765 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
tgw 0:2ee762ea11b3 766 }
tgw 0:2ee762ea11b3 767 addChildValues_ = false;
tgw 0:2ee762ea11b3 768 isMultiLine = isMultiLine || lineLength >= rightMargin_;
tgw 0:2ee762ea11b3 769 }
tgw 0:2ee762ea11b3 770 return isMultiLine;
tgw 0:2ee762ea11b3 771 }
tgw 0:2ee762ea11b3 772
tgw 0:2ee762ea11b3 773 void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {
tgw 0:2ee762ea11b3 774 if (addChildValues_)
tgw 0:2ee762ea11b3 775 childValues_.push_back(value);
tgw 0:2ee762ea11b3 776 else
tgw 0:2ee762ea11b3 777 *document_ << value;
tgw 0:2ee762ea11b3 778 }
tgw 0:2ee762ea11b3 779
tgw 0:2ee762ea11b3 780 void StyledStreamWriter::writeIndent() {
tgw 0:2ee762ea11b3 781 // blep intended this to look at the so-far-written string
tgw 0:2ee762ea11b3 782 // to determine whether we are already indented, but
tgw 0:2ee762ea11b3 783 // with a stream we cannot do that. So we rely on some saved state.
tgw 0:2ee762ea11b3 784 // The caller checks indented_.
tgw 0:2ee762ea11b3 785 *document_ << '\n' << indentString_;
tgw 0:2ee762ea11b3 786 }
tgw 0:2ee762ea11b3 787
tgw 0:2ee762ea11b3 788 void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {
tgw 0:2ee762ea11b3 789 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 790 *document_ << value;
tgw 0:2ee762ea11b3 791 indented_ = false;
tgw 0:2ee762ea11b3 792 }
tgw 0:2ee762ea11b3 793
tgw 0:2ee762ea11b3 794 void StyledStreamWriter::indent() { indentString_ += indentation_; }
tgw 0:2ee762ea11b3 795
tgw 0:2ee762ea11b3 796 void StyledStreamWriter::unindent() {
tgw 0:2ee762ea11b3 797 assert(indentString_.size() >= indentation_.size());
tgw 0:2ee762ea11b3 798 indentString_.resize(indentString_.size() - indentation_.size());
tgw 0:2ee762ea11b3 799 }
tgw 0:2ee762ea11b3 800
tgw 0:2ee762ea11b3 801 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
tgw 0:2ee762ea11b3 802 if (!root.hasComment(commentBefore))
tgw 0:2ee762ea11b3 803 return;
tgw 0:2ee762ea11b3 804
tgw 0:2ee762ea11b3 805 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 806 const JSONCPP_STRING& comment = root.getComment(commentBefore);
tgw 0:2ee762ea11b3 807 JSONCPP_STRING::const_iterator iter = comment.begin();
tgw 0:2ee762ea11b3 808 while (iter != comment.end()) {
tgw 0:2ee762ea11b3 809 *document_ << *iter;
tgw 0:2ee762ea11b3 810 if (*iter == '\n' &&
tgw 0:2ee762ea11b3 811 ((iter+1) != comment.end() && *(iter + 1) == '/'))
tgw 0:2ee762ea11b3 812 // writeIndent(); // would include newline
tgw 0:2ee762ea11b3 813 *document_ << indentString_;
tgw 0:2ee762ea11b3 814 ++iter;
tgw 0:2ee762ea11b3 815 }
tgw 0:2ee762ea11b3 816 indented_ = false;
tgw 0:2ee762ea11b3 817 }
tgw 0:2ee762ea11b3 818
tgw 0:2ee762ea11b3 819 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
tgw 0:2ee762ea11b3 820 if (root.hasComment(commentAfterOnSameLine))
tgw 0:2ee762ea11b3 821 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
tgw 0:2ee762ea11b3 822
tgw 0:2ee762ea11b3 823 if (root.hasComment(commentAfter)) {
tgw 0:2ee762ea11b3 824 writeIndent();
tgw 0:2ee762ea11b3 825 *document_ << root.getComment(commentAfter);
tgw 0:2ee762ea11b3 826 }
tgw 0:2ee762ea11b3 827 indented_ = false;
tgw 0:2ee762ea11b3 828 }
tgw 0:2ee762ea11b3 829
tgw 0:2ee762ea11b3 830 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
tgw 0:2ee762ea11b3 831 return value.hasComment(commentBefore) ||
tgw 0:2ee762ea11b3 832 value.hasComment(commentAfterOnSameLine) ||
tgw 0:2ee762ea11b3 833 value.hasComment(commentAfter);
tgw 0:2ee762ea11b3 834 }
tgw 0:2ee762ea11b3 835
tgw 0:2ee762ea11b3 836 //////////////////////////
tgw 0:2ee762ea11b3 837 // BuiltStyledStreamWriter
tgw 0:2ee762ea11b3 838
tgw 0:2ee762ea11b3 839 /// Scoped enums are not available until C++11.
tgw 0:2ee762ea11b3 840 struct CommentStyle {
tgw 0:2ee762ea11b3 841 /// Decide whether to write comments.
tgw 0:2ee762ea11b3 842 enum Enum {
tgw 0:2ee762ea11b3 843 None, ///< Drop all comments.
tgw 0:2ee762ea11b3 844 Most, ///< Recover odd behavior of previous versions (not implemented yet).
tgw 0:2ee762ea11b3 845 All ///< Keep all comments.
tgw 0:2ee762ea11b3 846 };
tgw 0:2ee762ea11b3 847 };
tgw 0:2ee762ea11b3 848
tgw 0:2ee762ea11b3 849 struct BuiltStyledStreamWriter : public StreamWriter
tgw 0:2ee762ea11b3 850 {
tgw 0:2ee762ea11b3 851 BuiltStyledStreamWriter(
tgw 0:2ee762ea11b3 852 JSONCPP_STRING const& indentation,
tgw 0:2ee762ea11b3 853 CommentStyle::Enum cs,
tgw 0:2ee762ea11b3 854 JSONCPP_STRING const& colonSymbol,
tgw 0:2ee762ea11b3 855 JSONCPP_STRING const& nullSymbol,
tgw 0:2ee762ea11b3 856 JSONCPP_STRING const& endingLineFeedSymbol,
tgw 0:2ee762ea11b3 857 bool useSpecialFloats,
tgw 0:2ee762ea11b3 858 unsigned int precision);
tgw 0:2ee762ea11b3 859 int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
tgw 0:2ee762ea11b3 860 private:
tgw 0:2ee762ea11b3 861 void writeValue(Value const& value);
tgw 0:2ee762ea11b3 862 void writeArrayValue(Value const& value);
tgw 0:2ee762ea11b3 863 bool isMultilineArray(Value const& value);
tgw 0:2ee762ea11b3 864 void pushValue(JSONCPP_STRING const& value);
tgw 0:2ee762ea11b3 865 void writeIndent();
tgw 0:2ee762ea11b3 866 void writeWithIndent(JSONCPP_STRING const& value);
tgw 0:2ee762ea11b3 867 void indent();
tgw 0:2ee762ea11b3 868 void unindent();
tgw 0:2ee762ea11b3 869 void writeCommentBeforeValue(Value const& root);
tgw 0:2ee762ea11b3 870 void writeCommentAfterValueOnSameLine(Value const& root);
tgw 0:2ee762ea11b3 871 static bool hasCommentForValue(const Value& value);
tgw 0:2ee762ea11b3 872
tgw 0:2ee762ea11b3 873 typedef std::vector<JSONCPP_STRING> ChildValues;
tgw 0:2ee762ea11b3 874
tgw 0:2ee762ea11b3 875 ChildValues childValues_;
tgw 0:2ee762ea11b3 876 JSONCPP_STRING indentString_;
tgw 0:2ee762ea11b3 877 unsigned int rightMargin_;
tgw 0:2ee762ea11b3 878 JSONCPP_STRING indentation_;
tgw 0:2ee762ea11b3 879 CommentStyle::Enum cs_;
tgw 0:2ee762ea11b3 880 JSONCPP_STRING colonSymbol_;
tgw 0:2ee762ea11b3 881 JSONCPP_STRING nullSymbol_;
tgw 0:2ee762ea11b3 882 JSONCPP_STRING endingLineFeedSymbol_;
tgw 0:2ee762ea11b3 883 bool addChildValues_ : 1;
tgw 0:2ee762ea11b3 884 bool indented_ : 1;
tgw 0:2ee762ea11b3 885 bool useSpecialFloats_ : 1;
tgw 0:2ee762ea11b3 886 unsigned int precision_;
tgw 0:2ee762ea11b3 887 };
tgw 0:2ee762ea11b3 888 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
tgw 0:2ee762ea11b3 889 JSONCPP_STRING const& indentation,
tgw 0:2ee762ea11b3 890 CommentStyle::Enum cs,
tgw 0:2ee762ea11b3 891 JSONCPP_STRING const& colonSymbol,
tgw 0:2ee762ea11b3 892 JSONCPP_STRING const& nullSymbol,
tgw 0:2ee762ea11b3 893 JSONCPP_STRING const& endingLineFeedSymbol,
tgw 0:2ee762ea11b3 894 bool useSpecialFloats,
tgw 0:2ee762ea11b3 895 unsigned int precision)
tgw 0:2ee762ea11b3 896 : rightMargin_(74)
tgw 0:2ee762ea11b3 897 , indentation_(indentation)
tgw 0:2ee762ea11b3 898 , cs_(cs)
tgw 0:2ee762ea11b3 899 , colonSymbol_(colonSymbol)
tgw 0:2ee762ea11b3 900 , nullSymbol_(nullSymbol)
tgw 0:2ee762ea11b3 901 , endingLineFeedSymbol_(endingLineFeedSymbol)
tgw 0:2ee762ea11b3 902 , addChildValues_(false)
tgw 0:2ee762ea11b3 903 , indented_(false)
tgw 0:2ee762ea11b3 904 , useSpecialFloats_(useSpecialFloats)
tgw 0:2ee762ea11b3 905 , precision_(precision)
tgw 0:2ee762ea11b3 906 {
tgw 0:2ee762ea11b3 907 }
tgw 0:2ee762ea11b3 908 int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
tgw 0:2ee762ea11b3 909 {
tgw 0:2ee762ea11b3 910 sout_ = sout;
tgw 0:2ee762ea11b3 911 addChildValues_ = false;
tgw 0:2ee762ea11b3 912 indented_ = true;
tgw 0:2ee762ea11b3 913 indentString_.clear();
tgw 0:2ee762ea11b3 914 writeCommentBeforeValue(root);
tgw 0:2ee762ea11b3 915 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 916 indented_ = true;
tgw 0:2ee762ea11b3 917 writeValue(root);
tgw 0:2ee762ea11b3 918 writeCommentAfterValueOnSameLine(root);
tgw 0:2ee762ea11b3 919 *sout_ << endingLineFeedSymbol_;
tgw 0:2ee762ea11b3 920 sout_ = NULL;
tgw 0:2ee762ea11b3 921 return 0;
tgw 0:2ee762ea11b3 922 }
tgw 0:2ee762ea11b3 923 void BuiltStyledStreamWriter::writeValue(Value const& value) {
tgw 0:2ee762ea11b3 924 switch (value.type()) {
tgw 0:2ee762ea11b3 925 case nullValue:
tgw 0:2ee762ea11b3 926 pushValue(nullSymbol_);
tgw 0:2ee762ea11b3 927 break;
tgw 0:2ee762ea11b3 928 case intValue:
tgw 0:2ee762ea11b3 929 pushValue(valueToString(value.asLargestInt()));
tgw 0:2ee762ea11b3 930 break;
tgw 0:2ee762ea11b3 931 case uintValue:
tgw 0:2ee762ea11b3 932 pushValue(valueToString(value.asLargestUInt()));
tgw 0:2ee762ea11b3 933 break;
tgw 0:2ee762ea11b3 934 case realValue:
tgw 0:2ee762ea11b3 935 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
tgw 0:2ee762ea11b3 936 break;
tgw 0:2ee762ea11b3 937 case stringValue:
tgw 0:2ee762ea11b3 938 {
tgw 0:2ee762ea11b3 939 // Is NULL is possible for value.string_? No.
tgw 0:2ee762ea11b3 940 char const* str;
tgw 0:2ee762ea11b3 941 char const* end;
tgw 0:2ee762ea11b3 942 bool ok = value.getString(&str, &end);
tgw 0:2ee762ea11b3 943 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
tgw 0:2ee762ea11b3 944 else pushValue("");
tgw 0:2ee762ea11b3 945 break;
tgw 0:2ee762ea11b3 946 }
tgw 0:2ee762ea11b3 947 case booleanValue:
tgw 0:2ee762ea11b3 948 pushValue(valueToString(value.asBool()));
tgw 0:2ee762ea11b3 949 break;
tgw 0:2ee762ea11b3 950 case arrayValue:
tgw 0:2ee762ea11b3 951 writeArrayValue(value);
tgw 0:2ee762ea11b3 952 break;
tgw 0:2ee762ea11b3 953 case objectValue: {
tgw 0:2ee762ea11b3 954 Value::Members members(value.getMemberNames());
tgw 0:2ee762ea11b3 955 if (members.empty())
tgw 0:2ee762ea11b3 956 pushValue("{}");
tgw 0:2ee762ea11b3 957 else {
tgw 0:2ee762ea11b3 958 writeWithIndent("{");
tgw 0:2ee762ea11b3 959 indent();
tgw 0:2ee762ea11b3 960 Value::Members::iterator it = members.begin();
tgw 0:2ee762ea11b3 961 for (;;) {
tgw 0:2ee762ea11b3 962 JSONCPP_STRING const& name = *it;
tgw 0:2ee762ea11b3 963 Value const& childValue = value[name];
tgw 0:2ee762ea11b3 964 writeCommentBeforeValue(childValue);
tgw 0:2ee762ea11b3 965 writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
tgw 0:2ee762ea11b3 966 *sout_ << colonSymbol_;
tgw 0:2ee762ea11b3 967 writeValue(childValue);
tgw 0:2ee762ea11b3 968 if (++it == members.end()) {
tgw 0:2ee762ea11b3 969 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 970 break;
tgw 0:2ee762ea11b3 971 }
tgw 0:2ee762ea11b3 972 *sout_ << ",";
tgw 0:2ee762ea11b3 973 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 974 }
tgw 0:2ee762ea11b3 975 unindent();
tgw 0:2ee762ea11b3 976 writeWithIndent("}");
tgw 0:2ee762ea11b3 977 }
tgw 0:2ee762ea11b3 978 } break;
tgw 0:2ee762ea11b3 979 }
tgw 0:2ee762ea11b3 980 }
tgw 0:2ee762ea11b3 981
tgw 0:2ee762ea11b3 982 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
tgw 0:2ee762ea11b3 983 unsigned size = value.size();
tgw 0:2ee762ea11b3 984 if (size == 0)
tgw 0:2ee762ea11b3 985 pushValue("[]");
tgw 0:2ee762ea11b3 986 else {
tgw 0:2ee762ea11b3 987 bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
tgw 0:2ee762ea11b3 988 if (isMultiLine) {
tgw 0:2ee762ea11b3 989 writeWithIndent("[");
tgw 0:2ee762ea11b3 990 indent();
tgw 0:2ee762ea11b3 991 bool hasChildValue = !childValues_.empty();
tgw 0:2ee762ea11b3 992 unsigned index = 0;
tgw 0:2ee762ea11b3 993 for (;;) {
tgw 0:2ee762ea11b3 994 Value const& childValue = value[index];
tgw 0:2ee762ea11b3 995 writeCommentBeforeValue(childValue);
tgw 0:2ee762ea11b3 996 if (hasChildValue)
tgw 0:2ee762ea11b3 997 writeWithIndent(childValues_[index]);
tgw 0:2ee762ea11b3 998 else {
tgw 0:2ee762ea11b3 999 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 1000 indented_ = true;
tgw 0:2ee762ea11b3 1001 writeValue(childValue);
tgw 0:2ee762ea11b3 1002 indented_ = false;
tgw 0:2ee762ea11b3 1003 }
tgw 0:2ee762ea11b3 1004 if (++index == size) {
tgw 0:2ee762ea11b3 1005 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 1006 break;
tgw 0:2ee762ea11b3 1007 }
tgw 0:2ee762ea11b3 1008 *sout_ << ",";
tgw 0:2ee762ea11b3 1009 writeCommentAfterValueOnSameLine(childValue);
tgw 0:2ee762ea11b3 1010 }
tgw 0:2ee762ea11b3 1011 unindent();
tgw 0:2ee762ea11b3 1012 writeWithIndent("]");
tgw 0:2ee762ea11b3 1013 } else // output on a single line
tgw 0:2ee762ea11b3 1014 {
tgw 0:2ee762ea11b3 1015 assert(childValues_.size() == size);
tgw 0:2ee762ea11b3 1016 *sout_ << "[";
tgw 0:2ee762ea11b3 1017 if (!indentation_.empty()) *sout_ << " ";
tgw 0:2ee762ea11b3 1018 for (unsigned index = 0; index < size; ++index) {
tgw 0:2ee762ea11b3 1019 if (index > 0)
tgw 0:2ee762ea11b3 1020 *sout_ << ((!indentation_.empty()) ? ", " : ",");
tgw 0:2ee762ea11b3 1021 *sout_ << childValues_[index];
tgw 0:2ee762ea11b3 1022 }
tgw 0:2ee762ea11b3 1023 if (!indentation_.empty()) *sout_ << " ";
tgw 0:2ee762ea11b3 1024 *sout_ << "]";
tgw 0:2ee762ea11b3 1025 }
tgw 0:2ee762ea11b3 1026 }
tgw 0:2ee762ea11b3 1027 }
tgw 0:2ee762ea11b3 1028
tgw 0:2ee762ea11b3 1029 bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {
tgw 0:2ee762ea11b3 1030 ArrayIndex const size = value.size();
tgw 0:2ee762ea11b3 1031 bool isMultiLine = size * 3 >= rightMargin_;
tgw 0:2ee762ea11b3 1032 childValues_.clear();
tgw 0:2ee762ea11b3 1033 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
tgw 0:2ee762ea11b3 1034 Value const& childValue = value[index];
tgw 0:2ee762ea11b3 1035 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
tgw 0:2ee762ea11b3 1036 childValue.size() > 0);
tgw 0:2ee762ea11b3 1037 }
tgw 0:2ee762ea11b3 1038 if (!isMultiLine) // check if line length > max line length
tgw 0:2ee762ea11b3 1039 {
tgw 0:2ee762ea11b3 1040 childValues_.reserve(size);
tgw 0:2ee762ea11b3 1041 addChildValues_ = true;
tgw 0:2ee762ea11b3 1042 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
tgw 0:2ee762ea11b3 1043 for (ArrayIndex index = 0; index < size; ++index) {
tgw 0:2ee762ea11b3 1044 if (hasCommentForValue(value[index])) {
tgw 0:2ee762ea11b3 1045 isMultiLine = true;
tgw 0:2ee762ea11b3 1046 }
tgw 0:2ee762ea11b3 1047 writeValue(value[index]);
tgw 0:2ee762ea11b3 1048 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
tgw 0:2ee762ea11b3 1049 }
tgw 0:2ee762ea11b3 1050 addChildValues_ = false;
tgw 0:2ee762ea11b3 1051 isMultiLine = isMultiLine || lineLength >= rightMargin_;
tgw 0:2ee762ea11b3 1052 }
tgw 0:2ee762ea11b3 1053 return isMultiLine;
tgw 0:2ee762ea11b3 1054 }
tgw 0:2ee762ea11b3 1055
tgw 0:2ee762ea11b3 1056 void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {
tgw 0:2ee762ea11b3 1057 if (addChildValues_)
tgw 0:2ee762ea11b3 1058 childValues_.push_back(value);
tgw 0:2ee762ea11b3 1059 else
tgw 0:2ee762ea11b3 1060 *sout_ << value;
tgw 0:2ee762ea11b3 1061 }
tgw 0:2ee762ea11b3 1062
tgw 0:2ee762ea11b3 1063 void BuiltStyledStreamWriter::writeIndent() {
tgw 0:2ee762ea11b3 1064 // blep intended this to look at the so-far-written string
tgw 0:2ee762ea11b3 1065 // to determine whether we are already indented, but
tgw 0:2ee762ea11b3 1066 // with a stream we cannot do that. So we rely on some saved state.
tgw 0:2ee762ea11b3 1067 // The caller checks indented_.
tgw 0:2ee762ea11b3 1068
tgw 0:2ee762ea11b3 1069 if (!indentation_.empty()) {
tgw 0:2ee762ea11b3 1070 // In this case, drop newlines too.
tgw 0:2ee762ea11b3 1071 *sout_ << '\n' << indentString_;
tgw 0:2ee762ea11b3 1072 }
tgw 0:2ee762ea11b3 1073 }
tgw 0:2ee762ea11b3 1074
tgw 0:2ee762ea11b3 1075 void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {
tgw 0:2ee762ea11b3 1076 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 1077 *sout_ << value;
tgw 0:2ee762ea11b3 1078 indented_ = false;
tgw 0:2ee762ea11b3 1079 }
tgw 0:2ee762ea11b3 1080
tgw 0:2ee762ea11b3 1081 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
tgw 0:2ee762ea11b3 1082
tgw 0:2ee762ea11b3 1083 void BuiltStyledStreamWriter::unindent() {
tgw 0:2ee762ea11b3 1084 assert(indentString_.size() >= indentation_.size());
tgw 0:2ee762ea11b3 1085 indentString_.resize(indentString_.size() - indentation_.size());
tgw 0:2ee762ea11b3 1086 }
tgw 0:2ee762ea11b3 1087
tgw 0:2ee762ea11b3 1088 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
tgw 0:2ee762ea11b3 1089 if (cs_ == CommentStyle::None) return;
tgw 0:2ee762ea11b3 1090 if (!root.hasComment(commentBefore))
tgw 0:2ee762ea11b3 1091 return;
tgw 0:2ee762ea11b3 1092
tgw 0:2ee762ea11b3 1093 if (!indented_) writeIndent();
tgw 0:2ee762ea11b3 1094 const JSONCPP_STRING& comment = root.getComment(commentBefore);
tgw 0:2ee762ea11b3 1095 JSONCPP_STRING::const_iterator iter = comment.begin();
tgw 0:2ee762ea11b3 1096 while (iter != comment.end()) {
tgw 0:2ee762ea11b3 1097 *sout_ << *iter;
tgw 0:2ee762ea11b3 1098 if (*iter == '\n' &&
tgw 0:2ee762ea11b3 1099 ((iter+1) != comment.end() && *(iter + 1) == '/'))
tgw 0:2ee762ea11b3 1100 // writeIndent(); // would write extra newline
tgw 0:2ee762ea11b3 1101 *sout_ << indentString_;
tgw 0:2ee762ea11b3 1102 ++iter;
tgw 0:2ee762ea11b3 1103 }
tgw 0:2ee762ea11b3 1104 indented_ = false;
tgw 0:2ee762ea11b3 1105 }
tgw 0:2ee762ea11b3 1106
tgw 0:2ee762ea11b3 1107 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
tgw 0:2ee762ea11b3 1108 if (cs_ == CommentStyle::None) return;
tgw 0:2ee762ea11b3 1109 if (root.hasComment(commentAfterOnSameLine))
tgw 0:2ee762ea11b3 1110 *sout_ << " " + root.getComment(commentAfterOnSameLine);
tgw 0:2ee762ea11b3 1111
tgw 0:2ee762ea11b3 1112 if (root.hasComment(commentAfter)) {
tgw 0:2ee762ea11b3 1113 writeIndent();
tgw 0:2ee762ea11b3 1114 *sout_ << root.getComment(commentAfter);
tgw 0:2ee762ea11b3 1115 }
tgw 0:2ee762ea11b3 1116 }
tgw 0:2ee762ea11b3 1117
tgw 0:2ee762ea11b3 1118 // static
tgw 0:2ee762ea11b3 1119 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
tgw 0:2ee762ea11b3 1120 return value.hasComment(commentBefore) ||
tgw 0:2ee762ea11b3 1121 value.hasComment(commentAfterOnSameLine) ||
tgw 0:2ee762ea11b3 1122 value.hasComment(commentAfter);
tgw 0:2ee762ea11b3 1123 }
tgw 0:2ee762ea11b3 1124
tgw 0:2ee762ea11b3 1125 ///////////////
tgw 0:2ee762ea11b3 1126 // StreamWriter
tgw 0:2ee762ea11b3 1127
tgw 0:2ee762ea11b3 1128 StreamWriter::StreamWriter()
tgw 0:2ee762ea11b3 1129 : sout_(NULL)
tgw 0:2ee762ea11b3 1130 {
tgw 0:2ee762ea11b3 1131 }
tgw 0:2ee762ea11b3 1132 StreamWriter::~StreamWriter()
tgw 0:2ee762ea11b3 1133 {
tgw 0:2ee762ea11b3 1134 }
tgw 0:2ee762ea11b3 1135 StreamWriter::Factory::~Factory()
tgw 0:2ee762ea11b3 1136 {}
tgw 0:2ee762ea11b3 1137 StreamWriterBuilder::StreamWriterBuilder()
tgw 0:2ee762ea11b3 1138 {
tgw 0:2ee762ea11b3 1139 setDefaults(&settings_);
tgw 0:2ee762ea11b3 1140 }
tgw 0:2ee762ea11b3 1141 StreamWriterBuilder::~StreamWriterBuilder()
tgw 0:2ee762ea11b3 1142 {}
tgw 0:2ee762ea11b3 1143 StreamWriter* StreamWriterBuilder::newStreamWriter() const
tgw 0:2ee762ea11b3 1144 {
tgw 0:2ee762ea11b3 1145 JSONCPP_STRING indentation = settings_["indentation"].asString();
tgw 0:2ee762ea11b3 1146 JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
tgw 0:2ee762ea11b3 1147 bool eyc = settings_["enableYAMLCompatibility"].asBool();
tgw 0:2ee762ea11b3 1148 bool dnp = settings_["dropNullPlaceholders"].asBool();
tgw 0:2ee762ea11b3 1149 bool usf = settings_["useSpecialFloats"].asBool();
tgw 0:2ee762ea11b3 1150 unsigned int pre = settings_["precision"].asUInt();
tgw 0:2ee762ea11b3 1151 CommentStyle::Enum cs = CommentStyle::All;
tgw 0:2ee762ea11b3 1152 if (cs_str == "All") {
tgw 0:2ee762ea11b3 1153 cs = CommentStyle::All;
tgw 0:2ee762ea11b3 1154 } else if (cs_str == "None") {
tgw 0:2ee762ea11b3 1155 cs = CommentStyle::None;
tgw 0:2ee762ea11b3 1156 } else {
tgw 0:2ee762ea11b3 1157 throwRuntimeError("commentStyle must be 'All' or 'None'");
tgw 0:2ee762ea11b3 1158 }
tgw 0:2ee762ea11b3 1159 JSONCPP_STRING colonSymbol = " : ";
tgw 0:2ee762ea11b3 1160 if (eyc) {
tgw 0:2ee762ea11b3 1161 colonSymbol = ": ";
tgw 0:2ee762ea11b3 1162 } else if (indentation.empty()) {
tgw 0:2ee762ea11b3 1163 colonSymbol = ":";
tgw 0:2ee762ea11b3 1164 }
tgw 0:2ee762ea11b3 1165 JSONCPP_STRING nullSymbol = "null";
tgw 0:2ee762ea11b3 1166 if (dnp) {
tgw 0:2ee762ea11b3 1167 nullSymbol.clear();
tgw 0:2ee762ea11b3 1168 }
tgw 0:2ee762ea11b3 1169 if (pre > 17) pre = 17;
tgw 0:2ee762ea11b3 1170 JSONCPP_STRING endingLineFeedSymbol;
tgw 0:2ee762ea11b3 1171 return new BuiltStyledStreamWriter(
tgw 0:2ee762ea11b3 1172 indentation, cs,
tgw 0:2ee762ea11b3 1173 colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
tgw 0:2ee762ea11b3 1174 }
tgw 0:2ee762ea11b3 1175 static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
tgw 0:2ee762ea11b3 1176 {
tgw 0:2ee762ea11b3 1177 valid_keys->clear();
tgw 0:2ee762ea11b3 1178 valid_keys->insert("indentation");
tgw 0:2ee762ea11b3 1179 valid_keys->insert("commentStyle");
tgw 0:2ee762ea11b3 1180 valid_keys->insert("enableYAMLCompatibility");
tgw 0:2ee762ea11b3 1181 valid_keys->insert("dropNullPlaceholders");
tgw 0:2ee762ea11b3 1182 valid_keys->insert("useSpecialFloats");
tgw 0:2ee762ea11b3 1183 valid_keys->insert("precision");
tgw 0:2ee762ea11b3 1184 }
tgw 0:2ee762ea11b3 1185 bool StreamWriterBuilder::validate(Json::Value* invalid) const
tgw 0:2ee762ea11b3 1186 {
tgw 0:2ee762ea11b3 1187 Json::Value my_invalid;
tgw 0:2ee762ea11b3 1188 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
tgw 0:2ee762ea11b3 1189 Json::Value& inv = *invalid;
tgw 0:2ee762ea11b3 1190 std::set<JSONCPP_STRING> valid_keys;
tgw 0:2ee762ea11b3 1191 getValidWriterKeys(&valid_keys);
tgw 0:2ee762ea11b3 1192 Value::Members keys = settings_.getMemberNames();
tgw 0:2ee762ea11b3 1193 size_t n = keys.size();
tgw 0:2ee762ea11b3 1194 for (size_t i = 0; i < n; ++i) {
tgw 0:2ee762ea11b3 1195 JSONCPP_STRING const& key = keys[i];
tgw 0:2ee762ea11b3 1196 if (valid_keys.find(key) == valid_keys.end()) {
tgw 0:2ee762ea11b3 1197 inv[key] = settings_[key];
tgw 0:2ee762ea11b3 1198 }
tgw 0:2ee762ea11b3 1199 }
tgw 0:2ee762ea11b3 1200 return 0u == inv.size();
tgw 0:2ee762ea11b3 1201 }
tgw 0:2ee762ea11b3 1202 Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)
tgw 0:2ee762ea11b3 1203 {
tgw 0:2ee762ea11b3 1204 return settings_[key];
tgw 0:2ee762ea11b3 1205 }
tgw 0:2ee762ea11b3 1206 // static
tgw 0:2ee762ea11b3 1207 void StreamWriterBuilder::setDefaults(Json::Value* settings)
tgw 0:2ee762ea11b3 1208 {
tgw 0:2ee762ea11b3 1209 //! [StreamWriterBuilderDefaults]
tgw 0:2ee762ea11b3 1210 (*settings)["commentStyle"] = "All";
tgw 0:2ee762ea11b3 1211 (*settings)["indentation"] = "\t";
tgw 0:2ee762ea11b3 1212 (*settings)["enableYAMLCompatibility"] = false;
tgw 0:2ee762ea11b3 1213 (*settings)["dropNullPlaceholders"] = false;
tgw 0:2ee762ea11b3 1214 (*settings)["useSpecialFloats"] = false;
tgw 0:2ee762ea11b3 1215 (*settings)["precision"] = 17;
tgw 0:2ee762ea11b3 1216 //! [StreamWriterBuilderDefaults]
tgw 0:2ee762ea11b3 1217 }
tgw 0:2ee762ea11b3 1218
tgw 0:2ee762ea11b3 1219 JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {
tgw 0:2ee762ea11b3 1220 JSONCPP_OSTRINGSTREAM sout;
tgw 0:2ee762ea11b3 1221 StreamWriterPtr const writer(builder.newStreamWriter());
tgw 0:2ee762ea11b3 1222 writer->write(root, &sout);
tgw 0:2ee762ea11b3 1223 return sout.str();
tgw 0:2ee762ea11b3 1224 }
tgw 0:2ee762ea11b3 1225
tgw 0:2ee762ea11b3 1226 JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
tgw 0:2ee762ea11b3 1227 StreamWriterBuilder builder;
tgw 0:2ee762ea11b3 1228 StreamWriterPtr const writer(builder.newStreamWriter());
tgw 0:2ee762ea11b3 1229 writer->write(root, &sout);
tgw 0:2ee762ea11b3 1230 return sout;
tgw 0:2ee762ea11b3 1231 }
tgw 0:2ee762ea11b3 1232
tgw 0:2ee762ea11b3 1233 } // namespace Json