涂 桂旺
/
mbed-os-example-cj
json test
Embed:
(wiki syntax)
Show/hide line numbers
json_writer.cpp
00001 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors 00002 // Distributed under MIT license, or public domain if desired and 00003 // recognized in your jurisdiction. 00004 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 00005 00006 #if !defined(JSON_IS_AMALGAMATION) 00007 #include <json/writer.h> 00008 #include "json_tool.h" 00009 #endif // if !defined(JSON_IS_AMALGAMATION) 00010 #include <iomanip> 00011 #include <memory> 00012 #include <sstream> 00013 #include <utility> 00014 #include <set> 00015 #include <cassert> 00016 #include <cstring> 00017 #include <cstdio> 00018 00019 #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 00020 #include <float.h> 00021 #define isfinite _finite 00022 #elif defined(__sun) && defined(__SVR4) //Solaris 00023 #if !defined(isfinite) 00024 #include <ieeefp.h> 00025 #define isfinite finite 00026 #endif 00027 #elif defined(_AIX) 00028 #if !defined(isfinite) 00029 #include <math.h> 00030 #define isfinite finite 00031 #endif 00032 #elif defined(__hpux) 00033 #if !defined(isfinite) 00034 #if defined(__ia64) && !defined(finite) 00035 #define isfinite(x) ((sizeof(x) == sizeof(float) ? \ 00036 _Isfinitef(x) : _IsFinite(x))) 00037 #else 00038 #include <math.h> 00039 #define isfinite finite 00040 #endif 00041 #endif 00042 #else 00043 #include <cmath> 00044 #if !(defined(__QNXNTO__)) // QNX already defines isfinite 00045 #define isfinite std::isfinite 00046 #endif 00047 #endif 00048 00049 #if defined(_MSC_VER) 00050 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above 00051 #define snprintf sprintf_s 00052 #elif _MSC_VER >= 1900 // VC++ 14.0 and above 00053 #define snprintf std::snprintf 00054 #else 00055 #define snprintf _snprintf 00056 #endif 00057 #elif defined(__ANDROID__) || defined(__QNXNTO__) 00058 #define snprintf snprintf 00059 #elif __cplusplus >= 201103L 00060 #if !defined(__MINGW32__) && !defined(__CYGWIN__) 00061 #define snprintf std::snprintf 00062 #endif 00063 #endif 00064 00065 #if defined(__BORLANDC__) 00066 #include <float.h> 00067 #define isfinite _finite 00068 #define snprintf _snprintf 00069 #endif 00070 00071 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 00072 // Disable warning about strdup being deprecated. 00073 #pragma warning(disable : 4996) 00074 #endif 00075 using namespace std; 00076 namespace Json { 00077 00078 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) 00079 typedef std::unique_ptr<StreamWriter> StreamWriterPtr; 00080 #else 00081 typedef std::auto_ptr<StreamWriter> StreamWriterPtr; 00082 #endif 00083 00084 JSONCPP_STRING valueToString(LargestInt value) { 00085 UIntToStringBuffer buffer; 00086 char* current = buffer + sizeof(buffer); 00087 if (value == Value::minLargestInt) { 00088 uintToString(LargestUInt(Value::maxLargestInt) + 1, current); 00089 *--current = '-'; 00090 } else if (value < 0) { 00091 uintToString(LargestUInt(-value), current); 00092 *--current = '-'; 00093 } else { 00094 uintToString(LargestUInt(value), current); 00095 } 00096 assert(current >= buffer); 00097 return current; 00098 } 00099 00100 JSONCPP_STRING valueToString(LargestUInt value) { 00101 UIntToStringBuffer buffer; 00102 char* current = buffer + sizeof(buffer); 00103 uintToString(value, current); 00104 assert(current >= buffer); 00105 return current; 00106 } 00107 00108 #if defined(JSON_HAS_INT64) 00109 00110 JSONCPP_STRING valueToString(Int value) { 00111 return valueToString(LargestInt(value)); 00112 } 00113 00114 JSONCPP_STRING valueToString(UInt value) { 00115 return valueToString(LargestUInt(value)); 00116 } 00117 00118 #endif // # if defined(JSON_HAS_INT64) 00119 00120 namespace { 00121 JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { 00122 // Allocate a buffer that is more than large enough to store the 16 digits of 00123 // precision requested below. 00124 char buffer[36]; 00125 int len = -1; 00126 00127 char formatString[15]; 00128 snprintf(formatString, sizeof(formatString), "%%.%ug", precision); 00129 00130 // Print into the buffer. We need not request the alternative representation 00131 // that always has a decimal point because JSON doesn't distinguish the 00132 // concepts of reals and integers. 00133 if (isfinite(value)) { 00134 len = snprintf(buffer, sizeof(buffer), formatString, value); 00135 fixNumericLocale(buffer, buffer + len); 00136 00137 // try to ensure we preserve the fact that this was given to us as a double on input 00138 if (!strchr(buffer, '.') && !strchr(buffer, 'e')) { 00139 strcat(buffer, ".0"); 00140 } 00141 00142 } else { 00143 // IEEE standard states that NaN values will not compare to themselves 00144 if (value != value) { 00145 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); 00146 } else if (value < 0) { 00147 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); 00148 } else { 00149 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); 00150 } 00151 } 00152 assert(len >= 0); 00153 return buffer; 00154 } 00155 } 00156 00157 JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } 00158 00159 JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } 00160 00161 static bool isAnyCharRequiredQuoting(char const* s, size_t n) { 00162 assert(s || !n); 00163 00164 char const* const end = s + n; 00165 for (char const* cur = s; cur < end; ++cur) { 00166 if (*cur == '\\' || *cur == '\"' || *cur < ' ' 00167 || static_cast<unsigned char>(*cur) < 0x80) 00168 return true; 00169 } 00170 return false; 00171 } 00172 00173 static unsigned int utf8ToCodepoint(const char*& s, const char* e) { 00174 const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; 00175 00176 unsigned int firstByte = static_cast<unsigned char>(*s); 00177 00178 if (firstByte < 0x80) 00179 return firstByte; 00180 00181 if (firstByte < 0xE0) { 00182 if (e - s < 2) 00183 return REPLACEMENT_CHARACTER; 00184 00185 unsigned int calculated = ((firstByte & 0x1F) << 6) 00186 | (static_cast<unsigned int>(s[1]) & 0x3F); 00187 s += 1; 00188 // oversized encoded characters are invalid 00189 return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; 00190 } 00191 00192 if (firstByte < 0xF0) { 00193 if (e - s < 3) 00194 return REPLACEMENT_CHARACTER; 00195 00196 unsigned int calculated = ((firstByte & 0x0F) << 12) 00197 | ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) 00198 | (static_cast<unsigned int>(s[2]) & 0x3F); 00199 s += 2; 00200 // surrogates aren't valid codepoints itself 00201 // shouldn't be UTF-8 encoded 00202 if (calculated >= 0xD800 && calculated <= 0xDFFF) 00203 return REPLACEMENT_CHARACTER; 00204 // oversized encoded characters are invalid 00205 return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; 00206 } 00207 00208 if (firstByte < 0xF8) { 00209 if (e - s < 4) 00210 return REPLACEMENT_CHARACTER; 00211 00212 unsigned int calculated = ((firstByte & 0x07) << 24) 00213 | ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) 00214 | ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) 00215 | (static_cast<unsigned int>(s[3]) & 0x3F); 00216 s += 3; 00217 // oversized encoded characters are invalid 00218 return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; 00219 } 00220 00221 return REPLACEMENT_CHARACTER; 00222 } 00223 00224 static const char hex2[] = 00225 "000102030405060708090a0b0c0d0e0f" 00226 "101112131415161718191a1b1c1d1e1f" 00227 "202122232425262728292a2b2c2d2e2f" 00228 "303132333435363738393a3b3c3d3e3f" 00229 "404142434445464748494a4b4c4d4e4f" 00230 "505152535455565758595a5b5c5d5e5f" 00231 "606162636465666768696a6b6c6d6e6f" 00232 "707172737475767778797a7b7c7d7e7f" 00233 "808182838485868788898a8b8c8d8e8f" 00234 "909192939495969798999a9b9c9d9e9f" 00235 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" 00236 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" 00237 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" 00238 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" 00239 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" 00240 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; 00241 00242 static JSONCPP_STRING toHex16Bit(unsigned int x) { 00243 const unsigned int hi = (x >> 8) & 0xff; 00244 const unsigned int lo = x & 0xff; 00245 JSONCPP_STRING result(4, ' '); 00246 result[0] = hex2[2 * hi]; 00247 result[1] = hex2[2 * hi + 1]; 00248 result[2] = hex2[2 * lo]; 00249 result[3] = hex2[2 * lo + 1]; 00250 return result; 00251 } 00252 00253 static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { 00254 if (value == NULL) 00255 return ""; 00256 00257 if (!isAnyCharRequiredQuoting(value, length)) 00258 return JSONCPP_STRING("\"") + value + "\""; 00259 // We have to walk value and escape any special characters. 00260 // Appending to JSONCPP_STRING is not efficient, but this should be rare. 00261 // (Note: forward slashes are *not* rare, but I am not escaping them.) 00262 JSONCPP_STRING::size_type maxsize = 00263 length * 2 + 3; // allescaped+quotes+NULL 00264 JSONCPP_STRING result; 00265 result.reserve(maxsize); // to avoid lots of mallocs 00266 result += "\""; 00267 char const* end = value + length; 00268 for (const char* c = value; c != end; ++c) { 00269 switch (*c) { 00270 case '\"': 00271 result += "\\\""; 00272 break; 00273 case '\\': 00274 result += "\\\\"; 00275 break; 00276 case '\b': 00277 result += "\\b"; 00278 break; 00279 case '\f': 00280 result += "\\f"; 00281 break; 00282 case '\n': 00283 result += "\\n"; 00284 break; 00285 case '\r': 00286 result += "\\r"; 00287 break; 00288 case '\t': 00289 result += "\\t"; 00290 break; 00291 // case '/': 00292 // Even though \/ is considered a legal escape in JSON, a bare 00293 // slash is also legal, so I see no reason to escape it. 00294 // (I hope I am not misunderstanding something.) 00295 // blep notes: actually escaping \/ may be useful in javascript to avoid </ 00296 // sequence. 00297 // Should add a flag to allow this compatibility mode and prevent this 00298 // sequence from occurring. 00299 default: { 00300 unsigned int cp = utf8ToCodepoint(c, end); 00301 // don't escape non-control characters 00302 // (short escape sequence are applied above) 00303 if (cp < 0x80 && cp >= 0x20) 00304 result += static_cast<char>(cp); 00305 else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane 00306 result += "\\u"; 00307 result += toHex16Bit(cp); 00308 } 00309 else { // codepoint is not in Basic Multilingual Plane 00310 // convert to surrogate pair first 00311 cp -= 0x10000; 00312 result += "\\u"; 00313 result += toHex16Bit((cp >> 10) + 0xD800); 00314 result += "\\u"; 00315 result += toHex16Bit((cp & 0x3FF) + 0xDC00); 00316 } 00317 } 00318 break; 00319 } 00320 } 00321 result += "\""; 00322 return result; 00323 } 00324 00325 JSONCPP_STRING valueToQuotedString(const char* value) { 00326 return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value))); 00327 } 00328 00329 // Class Writer 00330 // ////////////////////////////////////////////////////////////////// 00331 Writer::~Writer() {} 00332 00333 // Class FastWriter 00334 // ////////////////////////////////////////////////////////////////// 00335 00336 FastWriter::FastWriter() 00337 : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), 00338 omitEndingLineFeed_(false) {} 00339 00340 void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } 00341 00342 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } 00343 00344 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } 00345 00346 JSONCPP_STRING FastWriter::write(const Value& root) { 00347 document_.clear(); 00348 writeValue(root); 00349 if (!omitEndingLineFeed_) 00350 document_ += "\n"; 00351 return document_; 00352 } 00353 00354 void FastWriter::writeValue(const Value& value) { 00355 switch (value.type()) { 00356 case nullValue: 00357 if (!dropNullPlaceholders_) 00358 document_ += "null"; 00359 break; 00360 case intValue: 00361 document_ += valueToString(value.asLargestInt()); 00362 break; 00363 case uintValue: 00364 document_ += valueToString(value.asLargestUInt()); 00365 break; 00366 case realValue: 00367 document_ += valueToString(value.asDouble()); 00368 break; 00369 case stringValue: 00370 { 00371 // Is NULL possible for value.string_? No. 00372 char const* str; 00373 char const* end; 00374 bool ok = value.getString(&str, &end); 00375 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str)); 00376 break; 00377 } 00378 case booleanValue: 00379 document_ += valueToString(value.asBool()); 00380 break; 00381 case arrayValue: { 00382 document_ += '['; 00383 ArrayIndex size = value.size(); 00384 for (ArrayIndex index = 0; index < size; ++index) { 00385 if (index > 0) 00386 document_ += ','; 00387 writeValue(value[index]); 00388 } 00389 document_ += ']'; 00390 } break; 00391 case objectValue: { 00392 Value::Members members(value.getMemberNames()); 00393 document_ += '{'; 00394 for (Value::Members::iterator it = members.begin(); it != members.end(); 00395 ++it) { 00396 const JSONCPP_STRING& name = *it; 00397 if (it != members.begin()) 00398 document_ += ','; 00399 document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); 00400 document_ += yamlCompatibilityEnabled_ ? ": " : ":"; 00401 writeValue(value[name]); 00402 } 00403 document_ += '}'; 00404 } break; 00405 } 00406 } 00407 00408 // Class StyledWriter 00409 // ////////////////////////////////////////////////////////////////// 00410 00411 StyledWriter::StyledWriter() 00412 : rightMargin_(74), indentSize_(3), addChildValues_() {} 00413 00414 JSONCPP_STRING StyledWriter::write(const Value& root) { 00415 document_.clear(); 00416 addChildValues_ = false; 00417 indentString_.clear(); 00418 writeCommentBeforeValue(root); 00419 writeValue(root); 00420 writeCommentAfterValueOnSameLine(root); 00421 document_ += "\n"; 00422 return document_; 00423 } 00424 00425 void StyledWriter::writeValue(const Value& value) { 00426 switch (value.type()) { 00427 case nullValue: 00428 pushValue("null"); 00429 break; 00430 case intValue: 00431 pushValue(valueToString(value.asLargestInt())); 00432 break; 00433 case uintValue: 00434 pushValue(valueToString(value.asLargestUInt())); 00435 break; 00436 case realValue: 00437 pushValue(valueToString(value.asDouble())); 00438 break; 00439 case stringValue: 00440 { 00441 // Is NULL possible for value.string_? No. 00442 char const* str; 00443 char const* end; 00444 bool ok = value.getString(&str, &end); 00445 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); 00446 else pushValue(""); 00447 break; 00448 } 00449 case booleanValue: 00450 pushValue(valueToString(value.asBool())); 00451 break; 00452 case arrayValue: 00453 writeArrayValue(value); 00454 break; 00455 case objectValue: { 00456 Value::Members members(value.getMemberNames()); 00457 if (members.empty()) 00458 pushValue("{}"); 00459 else { 00460 writeWithIndent("{"); 00461 indent(); 00462 Value::Members::iterator it = members.begin(); 00463 for (;;) { 00464 const JSONCPP_STRING& name = *it; 00465 const Value& childValue = value[name]; 00466 writeCommentBeforeValue(childValue); 00467 writeWithIndent(valueToQuotedString(name.c_str())); 00468 document_ += " : "; 00469 writeValue(childValue); 00470 if (++it == members.end()) { 00471 writeCommentAfterValueOnSameLine(childValue); 00472 break; 00473 } 00474 document_ += ','; 00475 writeCommentAfterValueOnSameLine(childValue); 00476 } 00477 unindent(); 00478 writeWithIndent("}"); 00479 } 00480 } break; 00481 } 00482 } 00483 00484 void StyledWriter::writeArrayValue(const Value& value) { 00485 unsigned size = value.size(); 00486 if (size == 0) 00487 pushValue("[]"); 00488 else { 00489 bool isArrayMultiLine = isMultilineArray(value); 00490 if (isArrayMultiLine) { 00491 writeWithIndent("["); 00492 indent(); 00493 bool hasChildValue = !childValues_.empty(); 00494 unsigned index = 0; 00495 for (;;) { 00496 const Value& childValue = value[index]; 00497 writeCommentBeforeValue(childValue); 00498 if (hasChildValue) 00499 writeWithIndent(childValues_[index]); 00500 else { 00501 writeIndent(); 00502 writeValue(childValue); 00503 } 00504 if (++index == size) { 00505 writeCommentAfterValueOnSameLine(childValue); 00506 break; 00507 } 00508 document_ += ','; 00509 writeCommentAfterValueOnSameLine(childValue); 00510 } 00511 unindent(); 00512 writeWithIndent("]"); 00513 } else // output on a single line 00514 { 00515 assert(childValues_.size() == size); 00516 document_ += "[ "; 00517 for (unsigned index = 0; index < size; ++index) { 00518 if (index > 0) 00519 document_ += ", "; 00520 document_ += childValues_[index]; 00521 } 00522 document_ += " ]"; 00523 } 00524 } 00525 } 00526 00527 bool StyledWriter::isMultilineArray(const Value& value) { 00528 ArrayIndex const size = value.size(); 00529 bool isMultiLine = size * 3 >= rightMargin_; 00530 childValues_.clear(); 00531 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { 00532 const Value& childValue = value[index]; 00533 isMultiLine = ((childValue.isArray() || childValue.isObject()) && 00534 childValue.size() > 0); 00535 } 00536 if (!isMultiLine) // check if line length > max line length 00537 { 00538 childValues_.reserve(size); 00539 addChildValues_ = true; 00540 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' 00541 for (ArrayIndex index = 0; index < size; ++index) { 00542 if (hasCommentForValue(value[index])) { 00543 isMultiLine = true; 00544 } 00545 writeValue(value[index]); 00546 lineLength += static_cast<ArrayIndex>(childValues_[index].length()); 00547 } 00548 addChildValues_ = false; 00549 isMultiLine = isMultiLine || lineLength >= rightMargin_; 00550 } 00551 return isMultiLine; 00552 } 00553 00554 void StyledWriter::pushValue(const JSONCPP_STRING& value) { 00555 if (addChildValues_) 00556 childValues_.push_back(value); 00557 else 00558 document_ += value; 00559 } 00560 00561 void StyledWriter::writeIndent() { 00562 if (!document_.empty()) { 00563 char last = document_[document_.length() - 1]; 00564 if (last == ' ') // already indented 00565 return; 00566 if (last != '\n') // Comments may add new-line 00567 document_ += '\n'; 00568 } 00569 document_ += indentString_; 00570 } 00571 00572 void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { 00573 writeIndent(); 00574 document_ += value; 00575 } 00576 00577 void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } 00578 00579 void StyledWriter::unindent() { 00580 assert(indentString_.size() >= indentSize_); 00581 indentString_.resize(indentString_.size() - indentSize_); 00582 } 00583 00584 void StyledWriter::writeCommentBeforeValue(const Value& root) { 00585 if (!root.hasComment(commentBefore)) 00586 return; 00587 00588 document_ += "\n"; 00589 writeIndent(); 00590 const JSONCPP_STRING& comment = root.getComment(commentBefore); 00591 JSONCPP_STRING::const_iterator iter = comment.begin(); 00592 while (iter != comment.end()) { 00593 document_ += *iter; 00594 if (*iter == '\n' && 00595 ((iter+1) != comment.end() && *(iter + 1) == '/')) 00596 writeIndent(); 00597 ++iter; 00598 } 00599 00600 // Comments are stripped of trailing newlines, so add one here 00601 document_ += "\n"; 00602 } 00603 00604 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { 00605 if (root.hasComment(commentAfterOnSameLine)) 00606 document_ += " " + root.getComment(commentAfterOnSameLine); 00607 00608 if (root.hasComment(commentAfter)) { 00609 document_ += "\n"; 00610 document_ += root.getComment(commentAfter); 00611 document_ += "\n"; 00612 } 00613 } 00614 00615 bool StyledWriter::hasCommentForValue(const Value& value) { 00616 return value.hasComment(commentBefore) || 00617 value.hasComment(commentAfterOnSameLine) || 00618 value.hasComment(commentAfter); 00619 } 00620 00621 // Class StyledStreamWriter 00622 // ////////////////////////////////////////////////////////////////// 00623 00624 StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) 00625 : document_(NULL), rightMargin_(74), indentation_(indentation), 00626 addChildValues_() {} 00627 00628 void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { 00629 document_ = &out; 00630 addChildValues_ = false; 00631 indentString_.clear(); 00632 indented_ = true; 00633 writeCommentBeforeValue(root); 00634 if (!indented_) writeIndent(); 00635 indented_ = true; 00636 writeValue(root); 00637 writeCommentAfterValueOnSameLine(root); 00638 *document_ << "\n"; 00639 document_ = NULL; // Forget the stream, for safety. 00640 } 00641 00642 void StyledStreamWriter::writeValue(const Value& value) { 00643 switch (value.type()) { 00644 case nullValue: 00645 pushValue("null"); 00646 break; 00647 case intValue: 00648 pushValue(valueToString(value.asLargestInt())); 00649 break; 00650 case uintValue: 00651 pushValue(valueToString(value.asLargestUInt())); 00652 break; 00653 case realValue: 00654 pushValue(valueToString(value.asDouble())); 00655 break; 00656 case stringValue: 00657 { 00658 // Is NULL possible for value.string_? No. 00659 char const* str; 00660 char const* end; 00661 bool ok = value.getString(&str, &end); 00662 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); 00663 else pushValue(""); 00664 break; 00665 } 00666 case booleanValue: 00667 pushValue(valueToString(value.asBool())); 00668 break; 00669 case arrayValue: 00670 writeArrayValue(value); 00671 break; 00672 case objectValue: { 00673 Value::Members members(value.getMemberNames()); 00674 if (members.empty()) 00675 pushValue("{}"); 00676 else { 00677 writeWithIndent("{"); 00678 indent(); 00679 Value::Members::iterator it = members.begin(); 00680 for (;;) { 00681 const JSONCPP_STRING& name = *it; 00682 const Value& childValue = value[name]; 00683 writeCommentBeforeValue(childValue); 00684 writeWithIndent(valueToQuotedString(name.c_str())); 00685 *document_ << " : "; 00686 writeValue(childValue); 00687 if (++it == members.end()) { 00688 writeCommentAfterValueOnSameLine(childValue); 00689 break; 00690 } 00691 *document_ << ","; 00692 writeCommentAfterValueOnSameLine(childValue); 00693 } 00694 unindent(); 00695 writeWithIndent("}"); 00696 } 00697 } break; 00698 } 00699 } 00700 00701 void StyledStreamWriter::writeArrayValue(const Value& value) { 00702 unsigned size = value.size(); 00703 if (size == 0) 00704 pushValue("[]"); 00705 else { 00706 bool isArrayMultiLine = isMultilineArray(value); 00707 if (isArrayMultiLine) { 00708 writeWithIndent("["); 00709 indent(); 00710 bool hasChildValue = !childValues_.empty(); 00711 unsigned index = 0; 00712 for (;;) { 00713 const Value& childValue = value[index]; 00714 writeCommentBeforeValue(childValue); 00715 if (hasChildValue) 00716 writeWithIndent(childValues_[index]); 00717 else { 00718 if (!indented_) writeIndent(); 00719 indented_ = true; 00720 writeValue(childValue); 00721 indented_ = false; 00722 } 00723 if (++index == size) { 00724 writeCommentAfterValueOnSameLine(childValue); 00725 break; 00726 } 00727 *document_ << ","; 00728 writeCommentAfterValueOnSameLine(childValue); 00729 } 00730 unindent(); 00731 writeWithIndent("]"); 00732 } else // output on a single line 00733 { 00734 assert(childValues_.size() == size); 00735 *document_ << "[ "; 00736 for (unsigned index = 0; index < size; ++index) { 00737 if (index > 0) 00738 *document_ << ", "; 00739 *document_ << childValues_[index]; 00740 } 00741 *document_ << " ]"; 00742 } 00743 } 00744 } 00745 00746 bool StyledStreamWriter::isMultilineArray(const Value& value) { 00747 ArrayIndex const size = value.size(); 00748 bool isMultiLine = size * 3 >= rightMargin_; 00749 childValues_.clear(); 00750 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { 00751 const Value& childValue = value[index]; 00752 isMultiLine = ((childValue.isArray() || childValue.isObject()) && 00753 childValue.size() > 0); 00754 } 00755 if (!isMultiLine) // check if line length > max line length 00756 { 00757 childValues_.reserve(size); 00758 addChildValues_ = true; 00759 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' 00760 for (ArrayIndex index = 0; index < size; ++index) { 00761 if (hasCommentForValue(value[index])) { 00762 isMultiLine = true; 00763 } 00764 writeValue(value[index]); 00765 lineLength += static_cast<ArrayIndex>(childValues_[index].length()); 00766 } 00767 addChildValues_ = false; 00768 isMultiLine = isMultiLine || lineLength >= rightMargin_; 00769 } 00770 return isMultiLine; 00771 } 00772 00773 void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { 00774 if (addChildValues_) 00775 childValues_.push_back(value); 00776 else 00777 *document_ << value; 00778 } 00779 00780 void StyledStreamWriter::writeIndent() { 00781 // blep intended this to look at the so-far-written string 00782 // to determine whether we are already indented, but 00783 // with a stream we cannot do that. So we rely on some saved state. 00784 // The caller checks indented_. 00785 *document_ << '\n' << indentString_; 00786 } 00787 00788 void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { 00789 if (!indented_) writeIndent(); 00790 *document_ << value; 00791 indented_ = false; 00792 } 00793 00794 void StyledStreamWriter::indent() { indentString_ += indentation_; } 00795 00796 void StyledStreamWriter::unindent() { 00797 assert(indentString_.size() >= indentation_.size()); 00798 indentString_.resize(indentString_.size() - indentation_.size()); 00799 } 00800 00801 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { 00802 if (!root.hasComment(commentBefore)) 00803 return; 00804 00805 if (!indented_) writeIndent(); 00806 const JSONCPP_STRING& comment = root.getComment(commentBefore); 00807 JSONCPP_STRING::const_iterator iter = comment.begin(); 00808 while (iter != comment.end()) { 00809 *document_ << *iter; 00810 if (*iter == '\n' && 00811 ((iter+1) != comment.end() && *(iter + 1) == '/')) 00812 // writeIndent(); // would include newline 00813 *document_ << indentString_; 00814 ++iter; 00815 } 00816 indented_ = false; 00817 } 00818 00819 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { 00820 if (root.hasComment(commentAfterOnSameLine)) 00821 *document_ << ' ' << root.getComment(commentAfterOnSameLine); 00822 00823 if (root.hasComment(commentAfter)) { 00824 writeIndent(); 00825 *document_ << root.getComment(commentAfter); 00826 } 00827 indented_ = false; 00828 } 00829 00830 bool StyledStreamWriter::hasCommentForValue(const Value& value) { 00831 return value.hasComment(commentBefore) || 00832 value.hasComment(commentAfterOnSameLine) || 00833 value.hasComment(commentAfter); 00834 } 00835 00836 ////////////////////////// 00837 // BuiltStyledStreamWriter 00838 00839 /// Scoped enums are not available until C++11. 00840 struct CommentStyle { 00841 /// Decide whether to write comments. 00842 enum Enum { 00843 None, ///< Drop all comments. 00844 Most, ///< Recover odd behavior of previous versions (not implemented yet). 00845 All ///< Keep all comments. 00846 }; 00847 }; 00848 00849 struct BuiltStyledStreamWriter : public StreamWriter 00850 { 00851 BuiltStyledStreamWriter( 00852 JSONCPP_STRING const& indentation, 00853 CommentStyle::Enum cs, 00854 JSONCPP_STRING const& colonSymbol, 00855 JSONCPP_STRING const& nullSymbol, 00856 JSONCPP_STRING const& endingLineFeedSymbol, 00857 bool useSpecialFloats, 00858 unsigned int precision); 00859 int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; 00860 private: 00861 void writeValue(Value const& value); 00862 void writeArrayValue(Value const& value); 00863 bool isMultilineArray(Value const& value); 00864 void pushValue(JSONCPP_STRING const& value); 00865 void writeIndent(); 00866 void writeWithIndent(JSONCPP_STRING const& value); 00867 void indent(); 00868 void unindent(); 00869 void writeCommentBeforeValue(Value const& root); 00870 void writeCommentAfterValueOnSameLine(Value const& root); 00871 static bool hasCommentForValue(const Value& value); 00872 00873 typedef std::vector<JSONCPP_STRING> ChildValues; 00874 00875 ChildValues childValues_; 00876 JSONCPP_STRING indentString_; 00877 unsigned int rightMargin_; 00878 JSONCPP_STRING indentation_; 00879 CommentStyle::Enum cs_; 00880 JSONCPP_STRING colonSymbol_; 00881 JSONCPP_STRING nullSymbol_; 00882 JSONCPP_STRING endingLineFeedSymbol_; 00883 bool addChildValues_ : 1; 00884 bool indented_ : 1; 00885 bool useSpecialFloats_ : 1; 00886 unsigned int precision_; 00887 }; 00888 BuiltStyledStreamWriter::BuiltStyledStreamWriter( 00889 JSONCPP_STRING const& indentation, 00890 CommentStyle::Enum cs, 00891 JSONCPP_STRING const& colonSymbol, 00892 JSONCPP_STRING const& nullSymbol, 00893 JSONCPP_STRING const& endingLineFeedSymbol, 00894 bool useSpecialFloats, 00895 unsigned int precision) 00896 : rightMargin_(74) 00897 , indentation_(indentation) 00898 , cs_(cs) 00899 , colonSymbol_(colonSymbol) 00900 , nullSymbol_(nullSymbol) 00901 , endingLineFeedSymbol_(endingLineFeedSymbol) 00902 , addChildValues_(false) 00903 , indented_(false) 00904 , useSpecialFloats_(useSpecialFloats) 00905 , precision_(precision) 00906 { 00907 } 00908 int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) 00909 { 00910 sout_ = sout; 00911 addChildValues_ = false; 00912 indented_ = true; 00913 indentString_.clear(); 00914 writeCommentBeforeValue(root); 00915 if (!indented_) writeIndent(); 00916 indented_ = true; 00917 writeValue(root); 00918 writeCommentAfterValueOnSameLine(root); 00919 *sout_ << endingLineFeedSymbol_; 00920 sout_ = NULL; 00921 return 0; 00922 } 00923 void BuiltStyledStreamWriter::writeValue(Value const& value) { 00924 switch (value.type()) { 00925 case nullValue: 00926 pushValue(nullSymbol_); 00927 break; 00928 case intValue: 00929 pushValue(valueToString(value.asLargestInt())); 00930 break; 00931 case uintValue: 00932 pushValue(valueToString(value.asLargestUInt())); 00933 break; 00934 case realValue: 00935 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); 00936 break; 00937 case stringValue: 00938 { 00939 // Is NULL is possible for value.string_? No. 00940 char const* str; 00941 char const* end; 00942 bool ok = value.getString(&str, &end); 00943 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); 00944 else pushValue(""); 00945 break; 00946 } 00947 case booleanValue: 00948 pushValue(valueToString(value.asBool())); 00949 break; 00950 case arrayValue: 00951 writeArrayValue(value); 00952 break; 00953 case objectValue: { 00954 Value::Members members(value.getMemberNames()); 00955 if (members.empty()) 00956 pushValue("{}"); 00957 else { 00958 writeWithIndent("{"); 00959 indent(); 00960 Value::Members::iterator it = members.begin(); 00961 for (;;) { 00962 JSONCPP_STRING const& name = *it; 00963 Value const& childValue = value[name]; 00964 writeCommentBeforeValue(childValue); 00965 writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); 00966 *sout_ << colonSymbol_; 00967 writeValue(childValue); 00968 if (++it == members.end()) { 00969 writeCommentAfterValueOnSameLine(childValue); 00970 break; 00971 } 00972 *sout_ << ","; 00973 writeCommentAfterValueOnSameLine(childValue); 00974 } 00975 unindent(); 00976 writeWithIndent("}"); 00977 } 00978 } break; 00979 } 00980 } 00981 00982 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { 00983 unsigned size = value.size(); 00984 if (size == 0) 00985 pushValue("[]"); 00986 else { 00987 bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); 00988 if (isMultiLine) { 00989 writeWithIndent("["); 00990 indent(); 00991 bool hasChildValue = !childValues_.empty(); 00992 unsigned index = 0; 00993 for (;;) { 00994 Value const& childValue = value[index]; 00995 writeCommentBeforeValue(childValue); 00996 if (hasChildValue) 00997 writeWithIndent(childValues_[index]); 00998 else { 00999 if (!indented_) writeIndent(); 01000 indented_ = true; 01001 writeValue(childValue); 01002 indented_ = false; 01003 } 01004 if (++index == size) { 01005 writeCommentAfterValueOnSameLine(childValue); 01006 break; 01007 } 01008 *sout_ << ","; 01009 writeCommentAfterValueOnSameLine(childValue); 01010 } 01011 unindent(); 01012 writeWithIndent("]"); 01013 } else // output on a single line 01014 { 01015 assert(childValues_.size() == size); 01016 *sout_ << "["; 01017 if (!indentation_.empty()) *sout_ << " "; 01018 for (unsigned index = 0; index < size; ++index) { 01019 if (index > 0) 01020 *sout_ << ((!indentation_.empty()) ? ", " : ","); 01021 *sout_ << childValues_[index]; 01022 } 01023 if (!indentation_.empty()) *sout_ << " "; 01024 *sout_ << "]"; 01025 } 01026 } 01027 } 01028 01029 bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { 01030 ArrayIndex const size = value.size(); 01031 bool isMultiLine = size * 3 >= rightMargin_; 01032 childValues_.clear(); 01033 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { 01034 Value const& childValue = value[index]; 01035 isMultiLine = ((childValue.isArray() || childValue.isObject()) && 01036 childValue.size() > 0); 01037 } 01038 if (!isMultiLine) // check if line length > max line length 01039 { 01040 childValues_.reserve(size); 01041 addChildValues_ = true; 01042 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' 01043 for (ArrayIndex index = 0; index < size; ++index) { 01044 if (hasCommentForValue(value[index])) { 01045 isMultiLine = true; 01046 } 01047 writeValue(value[index]); 01048 lineLength += static_cast<ArrayIndex>(childValues_[index].length()); 01049 } 01050 addChildValues_ = false; 01051 isMultiLine = isMultiLine || lineLength >= rightMargin_; 01052 } 01053 return isMultiLine; 01054 } 01055 01056 void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { 01057 if (addChildValues_) 01058 childValues_.push_back(value); 01059 else 01060 *sout_ << value; 01061 } 01062 01063 void BuiltStyledStreamWriter::writeIndent() { 01064 // blep intended this to look at the so-far-written string 01065 // to determine whether we are already indented, but 01066 // with a stream we cannot do that. So we rely on some saved state. 01067 // The caller checks indented_. 01068 01069 if (!indentation_.empty()) { 01070 // In this case, drop newlines too. 01071 *sout_ << '\n' << indentString_; 01072 } 01073 } 01074 01075 void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { 01076 if (!indented_) writeIndent(); 01077 *sout_ << value; 01078 indented_ = false; 01079 } 01080 01081 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } 01082 01083 void BuiltStyledStreamWriter::unindent() { 01084 assert(indentString_.size() >= indentation_.size()); 01085 indentString_.resize(indentString_.size() - indentation_.size()); 01086 } 01087 01088 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { 01089 if (cs_ == CommentStyle::None) return; 01090 if (!root.hasComment(commentBefore)) 01091 return; 01092 01093 if (!indented_) writeIndent(); 01094 const JSONCPP_STRING& comment = root.getComment(commentBefore); 01095 JSONCPP_STRING::const_iterator iter = comment.begin(); 01096 while (iter != comment.end()) { 01097 *sout_ << *iter; 01098 if (*iter == '\n' && 01099 ((iter+1) != comment.end() && *(iter + 1) == '/')) 01100 // writeIndent(); // would write extra newline 01101 *sout_ << indentString_; 01102 ++iter; 01103 } 01104 indented_ = false; 01105 } 01106 01107 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { 01108 if (cs_ == CommentStyle::None) return; 01109 if (root.hasComment(commentAfterOnSameLine)) 01110 *sout_ << " " + root.getComment(commentAfterOnSameLine); 01111 01112 if (root.hasComment(commentAfter)) { 01113 writeIndent(); 01114 *sout_ << root.getComment(commentAfter); 01115 } 01116 } 01117 01118 // static 01119 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { 01120 return value.hasComment(commentBefore) || 01121 value.hasComment(commentAfterOnSameLine) || 01122 value.hasComment(commentAfter); 01123 } 01124 01125 /////////////// 01126 // StreamWriter 01127 01128 StreamWriter::StreamWriter() 01129 : sout_(NULL) 01130 { 01131 } 01132 StreamWriter::~StreamWriter() 01133 { 01134 } 01135 StreamWriter::Factory::~Factory() 01136 {} 01137 StreamWriterBuilder::StreamWriterBuilder() 01138 { 01139 setDefaults(&settings_); 01140 } 01141 StreamWriterBuilder::~StreamWriterBuilder() 01142 {} 01143 StreamWriter* StreamWriterBuilder::newStreamWriter () const 01144 { 01145 JSONCPP_STRING indentation = settings_["indentation"].asString(); 01146 JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); 01147 bool eyc = settings_["enableYAMLCompatibility"].asBool(); 01148 bool dnp = settings_["dropNullPlaceholders"].asBool(); 01149 bool usf = settings_["useSpecialFloats"].asBool(); 01150 unsigned int pre = settings_["precision"].asUInt(); 01151 CommentStyle::Enum cs = CommentStyle::All; 01152 if (cs_str == "All") { 01153 cs = CommentStyle::All; 01154 } else if (cs_str == "None") { 01155 cs = CommentStyle::None; 01156 } else { 01157 throwRuntimeError("commentStyle must be 'All' or 'None'"); 01158 } 01159 JSONCPP_STRING colonSymbol = " : "; 01160 if (eyc) { 01161 colonSymbol = ": "; 01162 } else if (indentation.empty()) { 01163 colonSymbol = ":"; 01164 } 01165 JSONCPP_STRING nullSymbol = "null"; 01166 if (dnp) { 01167 nullSymbol.clear(); 01168 } 01169 if (pre > 17) pre = 17; 01170 JSONCPP_STRING endingLineFeedSymbol; 01171 return new BuiltStyledStreamWriter( 01172 indentation, cs, 01173 colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); 01174 } 01175 static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) 01176 { 01177 valid_keys->clear(); 01178 valid_keys->insert("indentation"); 01179 valid_keys->insert("commentStyle"); 01180 valid_keys->insert("enableYAMLCompatibility"); 01181 valid_keys->insert("dropNullPlaceholders"); 01182 valid_keys->insert("useSpecialFloats"); 01183 valid_keys->insert("precision"); 01184 } 01185 bool StreamWriterBuilder::validate (Json::Value* invalid) const 01186 { 01187 Json::Value my_invalid; 01188 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL 01189 Json::Value& inv = *invalid; 01190 std::set<JSONCPP_STRING> valid_keys; 01191 getValidWriterKeys(&valid_keys); 01192 Value::Members keys = settings_.getMemberNames(); 01193 size_t n = keys.size(); 01194 for (size_t i = 0; i < n; ++i) { 01195 JSONCPP_STRING const& key = keys[i]; 01196 if (valid_keys.find(key) == valid_keys.end()) { 01197 inv[key] = settings_[key]; 01198 } 01199 } 01200 return 0u == inv.size(); 01201 } 01202 Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) 01203 { 01204 return settings_[key]; 01205 } 01206 // static 01207 void StreamWriterBuilder::setDefaults(Json::Value* settings) 01208 { 01209 //! [StreamWriterBuilderDefaults] 01210 (*settings)["commentStyle"] = "All"; 01211 (*settings)["indentation"] = "\t"; 01212 (*settings)["enableYAMLCompatibility"] = false; 01213 (*settings)["dropNullPlaceholders"] = false; 01214 (*settings)["useSpecialFloats"] = false; 01215 (*settings)["precision"] = 17; 01216 //! [StreamWriterBuilderDefaults] 01217 } 01218 01219 JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { 01220 JSONCPP_OSTRINGSTREAM sout; 01221 StreamWriterPtr const writer(builder.newStreamWriter()); 01222 writer->write(root, &sout); 01223 return sout.str(); 01224 } 01225 01226 JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { 01227 StreamWriterBuilder builder; 01228 StreamWriterPtr const writer(builder.newStreamWriter ()); 01229 writer->write(root, &sout); 01230 return sout; 01231 } 01232 01233 } // namespace Json
Generated on Tue Jul 12 2022 21:24:54 by 1.7.2