00001
00002
00003
00004
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
00073 #pragma warning(disable : 4996)
00074 #endif
00075
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 static bool containsControlCharacter(const char* str) {
00085 while (*str) {
00086 if (isControlCharacter(*(str++)))
00087 return true;
00088 }
00089 return false;
00090 }
00091
00092 static bool containsControlCharacter0(const char* str, unsigned len) {
00093 char const* end = str + len;
00094 while (end != str) {
00095 if (isControlCharacter(*str) || 0==*str)
00096 return true;
00097 ++str;
00098 }
00099 return false;
00100 }
00101
00102 JSONCPP_STRING valueToString(LargestInt value) {
00103 UIntToStringBuffer buffer;
00104 char* current = buffer + sizeof(buffer);
00105 if (value == Value::minLargestInt) {
00106 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
00107 *--current = '-';
00108 } else if (value < 0) {
00109 uintToString(LargestUInt(-value), current);
00110 *--current = '-';
00111 } else {
00112 uintToString(LargestUInt(value), current);
00113 }
00114 assert(current >= buffer);
00115 return current;
00116 }
00117
00118 JSONCPP_STRING valueToString(LargestUInt value) {
00119 UIntToStringBuffer buffer;
00120 char* current = buffer + sizeof(buffer);
00121 uintToString(value, current);
00122 assert(current >= buffer);
00123 return current;
00124 }
00125
00126 #if defined(JSON_HAS_INT64)
00127
00128 JSONCPP_STRING valueToString(Int value) {
00129 return valueToString(LargestInt(value));
00130 }
00131
00132 JSONCPP_STRING valueToString(UInt value) {
00133 return valueToString(LargestUInt(value));
00134 }
00135
00136 #endif // # if defined(JSON_HAS_INT64)
00137
00138 JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
00139
00140
00141 char buffer[32];
00142 int len = -1;
00143
00144 char formatString[6];
00145 sprintf(formatString, "%%.%dg", precision);
00146
00147
00148
00149
00150 if (isfinite(value)) {
00151 len = snprintf(buffer, sizeof(buffer), formatString, value);
00152 } else {
00153
00154 if (value != value) {
00155 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
00156 } else if (value < 0) {
00157 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
00158 } else {
00159 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
00160 }
00161
00162 }
00163 assert(len >= 0);
00164 fixNumericLocale(buffer, buffer + len);
00165 return buffer;
00166 }
00167
00168 JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
00169
00170 JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
00171
00172 JSONCPP_STRING valueToQuotedString(const char* value) {
00173 if (value == NULL)
00174 return "";
00175
00176 if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
00177 !containsControlCharacter(value))
00178 return JSONCPP_STRING("\"") + value + "\"";
00179
00180
00181
00182 JSONCPP_STRING::size_type maxsize =
00183 strlen(value) * 2 + 3;
00184 JSONCPP_STRING result;
00185 result.reserve(maxsize);
00186 result += "\"";
00187 for (const char* c = value; *c != 0; ++c) {
00188 switch (*c) {
00189 case '\"':
00190 result += "\\\"";
00191 break;
00192 case '\\':
00193 result += "\\\\";
00194 break;
00195 case '\b':
00196 result += "\\b";
00197 break;
00198 case '\f':
00199 result += "\\f";
00200 break;
00201 case '\n':
00202 result += "\\n";
00203 break;
00204 case '\r':
00205 result += "\\r";
00206 break;
00207 case '\t':
00208 result += "\\t";
00209 break;
00210
00211
00212
00213
00214
00215
00216
00217
00218 default:
00219 if (isControlCharacter(*c)) {
00220 JSONCPP_OSTRINGSTREAM oss;
00221 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
00222 << std::setw(4) << static_cast<int>(*c);
00223 result += oss.str();
00224 } else {
00225 result += *c;
00226 }
00227 break;
00228 }
00229 }
00230 result += "\"";
00231 return result;
00232 }
00233
00234
00235 static char const* strnpbrk(char const* s, char const* accept, size_t n) {
00236 assert((s || !n) && accept);
00237
00238 char const* const end = s + n;
00239 for (char const* cur = s; cur < end; ++cur) {
00240 int const c = *cur;
00241 for (char const* a = accept; *a; ++a) {
00242 if (*a == c) {
00243 return cur;
00244 }
00245 }
00246 }
00247 return NULL;
00248 }
00249 static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
00250 if (value == NULL)
00251 return "";
00252
00253 if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
00254 !containsControlCharacter0(value, length))
00255 return JSONCPP_STRING("\"") + value + "\"";
00256
00257
00258
00259 JSONCPP_STRING::size_type maxsize =
00260 length * 2 + 3;
00261 JSONCPP_STRING result;
00262 result.reserve(maxsize);
00263 result += "\"";
00264 char const* end = value + length;
00265 for (const char* c = value; c != end; ++c) {
00266 switch (*c) {
00267 case '\"':
00268 result += "\\\"";
00269 break;
00270 case '\\':
00271 result += "\\\\";
00272 break;
00273 case '\b':
00274 result += "\\b";
00275 break;
00276 case '\f':
00277 result += "\\f";
00278 break;
00279 case '\n':
00280 result += "\\n";
00281 break;
00282 case '\r':
00283 result += "\\r";
00284 break;
00285 case '\t':
00286 result += "\\t";
00287 break;
00288
00289
00290
00291
00292
00293
00294
00295
00296 default:
00297 if ((isControlCharacter(*c)) || (*c == 0)) {
00298 JSONCPP_OSTRINGSTREAM oss;
00299 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
00300 << std::setw(4) << static_cast<int>(*c);
00301 result += oss.str();
00302 } else {
00303 result += *c;
00304 }
00305 break;
00306 }
00307 }
00308 result += "\"";
00309 return result;
00310 }
00311
00312
00313
00314 Writer::~Writer() {}
00315
00316
00317
00318
00319 FastWriter::FastWriter()
00320 : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
00321 omitEndingLineFeed_(false) {}
00322
00323 void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
00324
00325 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
00326
00327 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
00328
00329 JSONCPP_STRING FastWriter::write(const Value& root) {
00330 document_ = "";
00331 writeValue(root);
00332 if (!omitEndingLineFeed_)
00333 document_ += "\n";
00334 return document_;
00335 }
00336
00337 void FastWriter::writeValue(const Value& value) {
00338 switch (value.type()) {
00339 case nullValue:
00340 if (!dropNullPlaceholders_)
00341 document_ += "null";
00342 break;
00343 case intValue:
00344 document_ += valueToString(value.asLargestInt());
00345 break;
00346 case uintValue:
00347 document_ += valueToString(value.asLargestUInt());
00348 break;
00349 case realValue:
00350 document_ += valueToString(value.asDouble());
00351 break;
00352 case stringValue:
00353 {
00354
00355 char const* str;
00356 char const* end;
00357 bool ok = value.getString(&str, &end);
00358 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
00359 break;
00360 }
00361 case booleanValue:
00362 document_ += valueToString(value.asBool());
00363 break;
00364 case arrayValue: {
00365 document_ += '[';
00366 ArrayIndex size = value.size();
00367 for (ArrayIndex index = 0; index < size; ++index) {
00368 if (index > 0)
00369 document_ += ',';
00370 writeValue(value[index]);
00371 }
00372 document_ += ']';
00373 } break;
00374 case objectValue: {
00375 Value::Members members(value.getMemberNames());
00376 document_ += '{';
00377 for (Value::Members::iterator it = members.begin(); it != members.end();
00378 ++it) {
00379 const JSONCPP_STRING& name = *it;
00380 if (it != members.begin())
00381 document_ += ',';
00382 document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
00383 document_ += yamlCompatiblityEnabled_ ? ": " : ":";
00384 writeValue(value[name]);
00385 }
00386 document_ += '}';
00387 } break;
00388 }
00389 }
00390
00391
00392
00393
00394 StyledWriter::StyledWriter()
00395 : rightMargin_(74), indentSize_(3), addChildValues_() {}
00396
00397 JSONCPP_STRING StyledWriter::write(const Value& root) {
00398 document_ = "";
00399 addChildValues_ = false;
00400 indentString_ = "";
00401 writeCommentBeforeValue(root);
00402 writeValue(root);
00403 writeCommentAfterValueOnSameLine(root);
00404 document_ += "\n";
00405 return document_;
00406 }
00407
00408 void StyledWriter::writeValue(const Value& value) {
00409 switch (value.type()) {
00410 case nullValue:
00411 pushValue("null");
00412 break;
00413 case intValue:
00414 pushValue(valueToString(value.asLargestInt()));
00415 break;
00416 case uintValue:
00417 pushValue(valueToString(value.asLargestUInt()));
00418 break;
00419 case realValue:
00420 pushValue(valueToString(value.asDouble()));
00421 break;
00422 case stringValue:
00423 {
00424
00425 char const* str;
00426 char const* end;
00427 bool ok = value.getString(&str, &end);
00428 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
00429 else pushValue("");
00430 break;
00431 }
00432 case booleanValue:
00433 pushValue(valueToString(value.asBool()));
00434 break;
00435 case arrayValue:
00436 writeArrayValue(value);
00437 break;
00438 case objectValue: {
00439 Value::Members members(value.getMemberNames());
00440 if (members.empty())
00441 pushValue("{}");
00442 else {
00443 writeWithIndent("{");
00444 indent();
00445 Value::Members::iterator it = members.begin();
00446 for (;;) {
00447 const JSONCPP_STRING& name = *it;
00448 const Value& childValue = value[name];
00449 writeCommentBeforeValue(childValue);
00450 writeWithIndent(valueToQuotedString(name.c_str()));
00451 document_ += " : ";
00452 writeValue(childValue);
00453 if (++it == members.end()) {
00454 writeCommentAfterValueOnSameLine(childValue);
00455 break;
00456 }
00457 document_ += ',';
00458 writeCommentAfterValueOnSameLine(childValue);
00459 }
00460 unindent();
00461 writeWithIndent("}");
00462 }
00463 } break;
00464 }
00465 }
00466
00467 void StyledWriter::writeArrayValue(const Value& value) {
00468 unsigned size = value.size();
00469 if (size == 0)
00470 pushValue("[]");
00471 else {
00472 bool isArrayMultiLine = isMultineArray(value);
00473 if (isArrayMultiLine) {
00474 writeWithIndent("[");
00475 indent();
00476 bool hasChildValue = !childValues_.empty();
00477 unsigned index = 0;
00478 for (;;) {
00479 const Value& childValue = value[index];
00480 writeCommentBeforeValue(childValue);
00481 if (hasChildValue)
00482 writeWithIndent(childValues_[index]);
00483 else {
00484 writeIndent();
00485 writeValue(childValue);
00486 }
00487 if (++index == size) {
00488 writeCommentAfterValueOnSameLine(childValue);
00489 break;
00490 }
00491 document_ += ',';
00492 writeCommentAfterValueOnSameLine(childValue);
00493 }
00494 unindent();
00495 writeWithIndent("]");
00496 } else
00497 {
00498 assert(childValues_.size() == size);
00499 document_ += "[ ";
00500 for (unsigned index = 0; index < size; ++index) {
00501 if (index > 0)
00502 document_ += ", ";
00503 document_ += childValues_[index];
00504 }
00505 document_ += " ]";
00506 }
00507 }
00508 }
00509
00510 bool StyledWriter::isMultineArray(const Value& value) {
00511 ArrayIndex const size = value.size();
00512 bool isMultiLine = size * 3 >= rightMargin_;
00513 childValues_.clear();
00514 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
00515 const Value& childValue = value[index];
00516 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
00517 childValue.size() > 0);
00518 }
00519 if (!isMultiLine)
00520 {
00521 childValues_.reserve(size);
00522 addChildValues_ = true;
00523 ArrayIndex lineLength = 4 + (size - 1) * 2;
00524 for (ArrayIndex index = 0; index < size; ++index) {
00525 if (hasCommentForValue(value[index])) {
00526 isMultiLine = true;
00527 }
00528 writeValue(value[index]);
00529 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
00530 }
00531 addChildValues_ = false;
00532 isMultiLine = isMultiLine || lineLength >= rightMargin_;
00533 }
00534 return isMultiLine;
00535 }
00536
00537 void StyledWriter::pushValue(const JSONCPP_STRING& value) {
00538 if (addChildValues_)
00539 childValues_.push_back(value);
00540 else
00541 document_ += value;
00542 }
00543
00544 void StyledWriter::writeIndent() {
00545 if (!document_.empty()) {
00546 char last = document_[document_.length() - 1];
00547 if (last == ' ')
00548 return;
00549 if (last != '\n')
00550 document_ += '\n';
00551 }
00552 document_ += indentString_;
00553 }
00554
00555 void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {
00556 writeIndent();
00557 document_ += value;
00558 }
00559
00560 void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
00561
00562 void StyledWriter::unindent() {
00563 assert(indentString_.size() >= indentSize_);
00564 indentString_.resize(indentString_.size() - indentSize_);
00565 }
00566
00567 void StyledWriter::writeCommentBeforeValue(const Value& root) {
00568 if (!root.hasComment(commentBefore))
00569 return;
00570
00571 document_ += "\n";
00572 writeIndent();
00573 const JSONCPP_STRING& comment = root.getComment(commentBefore);
00574 JSONCPP_STRING::const_iterator iter = comment.begin();
00575 while (iter != comment.end()) {
00576 document_ += *iter;
00577 if (*iter == '\n' &&
00578 (iter != comment.end() && *(iter + 1) == '/'))
00579 writeIndent();
00580 ++iter;
00581 }
00582
00583
00584 document_ += "\n";
00585 }
00586
00587 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
00588 if (root.hasComment(commentAfterOnSameLine))
00589 document_ += " " + root.getComment(commentAfterOnSameLine);
00590
00591 if (root.hasComment(commentAfter)) {
00592 document_ += "\n";
00593 document_ += root.getComment(commentAfter);
00594 document_ += "\n";
00595 }
00596 }
00597
00598 bool StyledWriter::hasCommentForValue(const Value& value) {
00599 return value.hasComment(commentBefore) ||
00600 value.hasComment(commentAfterOnSameLine) ||
00601 value.hasComment(commentAfter);
00602 }
00603
00604
00605
00606
00607 StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
00608 : document_(NULL), rightMargin_(74), indentation_(indentation),
00609 addChildValues_() {}
00610
00611 void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {
00612 document_ = &out;
00613 addChildValues_ = false;
00614 indentString_ = "";
00615 indented_ = true;
00616 writeCommentBeforeValue(root);
00617 if (!indented_) writeIndent();
00618 indented_ = true;
00619 writeValue(root);
00620 writeCommentAfterValueOnSameLine(root);
00621 *document_ << "\n";
00622 document_ = NULL;
00623 }
00624
00625 void StyledStreamWriter::writeValue(const Value& value) {
00626 switch (value.type()) {
00627 case nullValue:
00628 pushValue("null");
00629 break;
00630 case intValue:
00631 pushValue(valueToString(value.asLargestInt()));
00632 break;
00633 case uintValue:
00634 pushValue(valueToString(value.asLargestUInt()));
00635 break;
00636 case realValue:
00637 pushValue(valueToString(value.asDouble()));
00638 break;
00639 case stringValue:
00640 {
00641
00642 char const* str;
00643 char const* end;
00644 bool ok = value.getString(&str, &end);
00645 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
00646 else pushValue("");
00647 break;
00648 }
00649 case booleanValue:
00650 pushValue(valueToString(value.asBool()));
00651 break;
00652 case arrayValue:
00653 writeArrayValue(value);
00654 break;
00655 case objectValue: {
00656 Value::Members members(value.getMemberNames());
00657 if (members.empty())
00658 pushValue("{}");
00659 else {
00660 writeWithIndent("{");
00661 indent();
00662 Value::Members::iterator it = members.begin();
00663 for (;;) {
00664 const JSONCPP_STRING& name = *it;
00665 const Value& childValue = value[name];
00666 writeCommentBeforeValue(childValue);
00667 writeWithIndent(valueToQuotedString(name.c_str()));
00668 *document_ << " : ";
00669 writeValue(childValue);
00670 if (++it == members.end()) {
00671 writeCommentAfterValueOnSameLine(childValue);
00672 break;
00673 }
00674 *document_ << ",";
00675 writeCommentAfterValueOnSameLine(childValue);
00676 }
00677 unindent();
00678 writeWithIndent("}");
00679 }
00680 } break;
00681 }
00682 }
00683
00684 void StyledStreamWriter::writeArrayValue(const Value& value) {
00685 unsigned size = value.size();
00686 if (size == 0)
00687 pushValue("[]");
00688 else {
00689 bool isArrayMultiLine = isMultineArray(value);
00690 if (isArrayMultiLine) {
00691 writeWithIndent("[");
00692 indent();
00693 bool hasChildValue = !childValues_.empty();
00694 unsigned index = 0;
00695 for (;;) {
00696 const Value& childValue = value[index];
00697 writeCommentBeforeValue(childValue);
00698 if (hasChildValue)
00699 writeWithIndent(childValues_[index]);
00700 else {
00701 if (!indented_) writeIndent();
00702 indented_ = true;
00703 writeValue(childValue);
00704 indented_ = false;
00705 }
00706 if (++index == size) {
00707 writeCommentAfterValueOnSameLine(childValue);
00708 break;
00709 }
00710 *document_ << ",";
00711 writeCommentAfterValueOnSameLine(childValue);
00712 }
00713 unindent();
00714 writeWithIndent("]");
00715 } else
00716 {
00717 assert(childValues_.size() == size);
00718 *document_ << "[ ";
00719 for (unsigned index = 0; index < size; ++index) {
00720 if (index > 0)
00721 *document_ << ", ";
00722 *document_ << childValues_[index];
00723 }
00724 *document_ << " ]";
00725 }
00726 }
00727 }
00728
00729 bool StyledStreamWriter::isMultineArray(const Value& value) {
00730 ArrayIndex const size = value.size();
00731 bool isMultiLine = size * 3 >= rightMargin_;
00732 childValues_.clear();
00733 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
00734 const Value& childValue = value[index];
00735 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
00736 childValue.size() > 0);
00737 }
00738 if (!isMultiLine)
00739 {
00740 childValues_.reserve(size);
00741 addChildValues_ = true;
00742 ArrayIndex lineLength = 4 + (size - 1) * 2;
00743 for (ArrayIndex index = 0; index < size; ++index) {
00744 if (hasCommentForValue(value[index])) {
00745 isMultiLine = true;
00746 }
00747 writeValue(value[index]);
00748 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
00749 }
00750 addChildValues_ = false;
00751 isMultiLine = isMultiLine || lineLength >= rightMargin_;
00752 }
00753 return isMultiLine;
00754 }
00755
00756 void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {
00757 if (addChildValues_)
00758 childValues_.push_back(value);
00759 else
00760 *document_ << value;
00761 }
00762
00763 void StyledStreamWriter::writeIndent() {
00764
00765
00766
00767
00768 *document_ << '\n' << indentString_;
00769 }
00770
00771 void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {
00772 if (!indented_) writeIndent();
00773 *document_ << value;
00774 indented_ = false;
00775 }
00776
00777 void StyledStreamWriter::indent() { indentString_ += indentation_; }
00778
00779 void StyledStreamWriter::unindent() {
00780 assert(indentString_.size() >= indentation_.size());
00781 indentString_.resize(indentString_.size() - indentation_.size());
00782 }
00783
00784 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
00785 if (!root.hasComment(commentBefore))
00786 return;
00787
00788 if (!indented_) writeIndent();
00789 const JSONCPP_STRING& comment = root.getComment(commentBefore);
00790 JSONCPP_STRING::const_iterator iter = comment.begin();
00791 while (iter != comment.end()) {
00792 *document_ << *iter;
00793 if (*iter == '\n' &&
00794 (iter != comment.end() && *(iter + 1) == '/'))
00795
00796 *document_ << indentString_;
00797 ++iter;
00798 }
00799 indented_ = false;
00800 }
00801
00802 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
00803 if (root.hasComment(commentAfterOnSameLine))
00804 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
00805
00806 if (root.hasComment(commentAfter)) {
00807 writeIndent();
00808 *document_ << root.getComment(commentAfter);
00809 }
00810 indented_ = false;
00811 }
00812
00813 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
00814 return value.hasComment(commentBefore) ||
00815 value.hasComment(commentAfterOnSameLine) ||
00816 value.hasComment(commentAfter);
00817 }
00818
00820
00821
00823 struct CommentStyle {
00825 enum Enum {
00826 None,
00827 Most,
00828 All
00829 };
00830 };
00831
00832 struct BuiltStyledStreamWriter : public StreamWriter
00833 {
00834 BuiltStyledStreamWriter(
00835 JSONCPP_STRING const& indentation,
00836 CommentStyle::Enum cs,
00837 JSONCPP_STRING const& colonSymbol,
00838 JSONCPP_STRING const& nullSymbol,
00839 JSONCPP_STRING const& endingLineFeedSymbol,
00840 bool useSpecialFloats,
00841 unsigned int precision);
00842 int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
00843 private:
00844 void writeValue(Value const& value);
00845 void writeArrayValue(Value const& value);
00846 bool isMultineArray(Value const& value);
00847 void pushValue(JSONCPP_STRING const& value);
00848 void writeIndent();
00849 void writeWithIndent(JSONCPP_STRING const& value);
00850 void indent();
00851 void unindent();
00852 void writeCommentBeforeValue(Value const& root);
00853 void writeCommentAfterValueOnSameLine(Value const& root);
00854 static bool hasCommentForValue(const Value& value);
00855
00856 typedef std::vector<JSONCPP_STRING> ChildValues;
00857
00858 ChildValues childValues_;
00859 JSONCPP_STRING indentString_;
00860 unsigned int rightMargin_;
00861 JSONCPP_STRING indentation_;
00862 CommentStyle::Enum cs_;
00863 JSONCPP_STRING colonSymbol_;
00864 JSONCPP_STRING nullSymbol_;
00865 JSONCPP_STRING endingLineFeedSymbol_;
00866 bool addChildValues_ : 1;
00867 bool indented_ : 1;
00868 bool useSpecialFloats_ : 1;
00869 unsigned int precision_;
00870 };
00871 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
00872 JSONCPP_STRING const& indentation,
00873 CommentStyle::Enum cs,
00874 JSONCPP_STRING const& colonSymbol,
00875 JSONCPP_STRING const& nullSymbol,
00876 JSONCPP_STRING const& endingLineFeedSymbol,
00877 bool useSpecialFloats,
00878 unsigned int precision)
00879 : rightMargin_(74)
00880 , indentation_(indentation)
00881 , cs_(cs)
00882 , colonSymbol_(colonSymbol)
00883 , nullSymbol_(nullSymbol)
00884 , endingLineFeedSymbol_(endingLineFeedSymbol)
00885 , addChildValues_(false)
00886 , indented_(false)
00887 , useSpecialFloats_(useSpecialFloats)
00888 , precision_(precision)
00889 {
00890 }
00891 int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
00892 {
00893 sout_ = sout;
00894 addChildValues_ = false;
00895 indented_ = true;
00896 indentString_ = "";
00897 writeCommentBeforeValue(root);
00898 if (!indented_) writeIndent();
00899 indented_ = true;
00900 writeValue(root);
00901 writeCommentAfterValueOnSameLine(root);
00902 *sout_ << endingLineFeedSymbol_;
00903 sout_ = NULL;
00904 return 0;
00905 }
00906 void BuiltStyledStreamWriter::writeValue(Value const& value) {
00907 switch (value.type()) {
00908 case nullValue:
00909 pushValue(nullSymbol_);
00910 break;
00911 case intValue:
00912 pushValue(valueToString(value.asLargestInt()));
00913 break;
00914 case uintValue:
00915 pushValue(valueToString(value.asLargestUInt()));
00916 break;
00917 case realValue:
00918 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
00919 break;
00920 case stringValue:
00921 {
00922
00923 char const* str;
00924 char const* end;
00925 bool ok = value.getString(&str, &end);
00926 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
00927 else pushValue("");
00928 break;
00929 }
00930 case booleanValue:
00931 pushValue(valueToString(value.asBool()));
00932 break;
00933 case arrayValue:
00934 writeArrayValue(value);
00935 break;
00936 case objectValue: {
00937 Value::Members members(value.getMemberNames());
00938 if (members.empty())
00939 pushValue("{}");
00940 else {
00941 writeWithIndent("{");
00942 indent();
00943 Value::Members::iterator it = members.begin();
00944 for (;;) {
00945 JSONCPP_STRING const& name = *it;
00946 Value const& childValue = value[name];
00947 writeCommentBeforeValue(childValue);
00948 writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
00949 *sout_ << colonSymbol_;
00950 writeValue(childValue);
00951 if (++it == members.end()) {
00952 writeCommentAfterValueOnSameLine(childValue);
00953 break;
00954 }
00955 *sout_ << ",";
00956 writeCommentAfterValueOnSameLine(childValue);
00957 }
00958 unindent();
00959 writeWithIndent("}");
00960 }
00961 } break;
00962 }
00963 }
00964
00965 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
00966 unsigned size = value.size();
00967 if (size == 0)
00968 pushValue("[]");
00969 else {
00970 bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
00971 if (isMultiLine) {
00972 writeWithIndent("[");
00973 indent();
00974 bool hasChildValue = !childValues_.empty();
00975 unsigned index = 0;
00976 for (;;) {
00977 Value const& childValue = value[index];
00978 writeCommentBeforeValue(childValue);
00979 if (hasChildValue)
00980 writeWithIndent(childValues_[index]);
00981 else {
00982 if (!indented_) writeIndent();
00983 indented_ = true;
00984 writeValue(childValue);
00985 indented_ = false;
00986 }
00987 if (++index == size) {
00988 writeCommentAfterValueOnSameLine(childValue);
00989 break;
00990 }
00991 *sout_ << ",";
00992 writeCommentAfterValueOnSameLine(childValue);
00993 }
00994 unindent();
00995 writeWithIndent("]");
00996 } else
00997 {
00998 assert(childValues_.size() == size);
00999 *sout_ << "[";
01000 if (!indentation_.empty()) *sout_ << " ";
01001 for (unsigned index = 0; index < size; ++index) {
01002 if (index > 0)
01003 *sout_ << ", ";
01004 *sout_ << childValues_[index];
01005 }
01006 if (!indentation_.empty()) *sout_ << " ";
01007 *sout_ << "]";
01008 }
01009 }
01010 }
01011
01012 bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
01013 ArrayIndex const size = value.size();
01014 bool isMultiLine = size * 3 >= rightMargin_;
01015 childValues_.clear();
01016 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
01017 Value const& childValue = value[index];
01018 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
01019 childValue.size() > 0);
01020 }
01021 if (!isMultiLine)
01022 {
01023 childValues_.reserve(size);
01024 addChildValues_ = true;
01025 ArrayIndex lineLength = 4 + (size - 1) * 2;
01026 for (ArrayIndex index = 0; index < size; ++index) {
01027 if (hasCommentForValue(value[index])) {
01028 isMultiLine = true;
01029 }
01030 writeValue(value[index]);
01031 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
01032 }
01033 addChildValues_ = false;
01034 isMultiLine = isMultiLine || lineLength >= rightMargin_;
01035 }
01036 return isMultiLine;
01037 }
01038
01039 void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {
01040 if (addChildValues_)
01041 childValues_.push_back(value);
01042 else
01043 *sout_ << value;
01044 }
01045
01046 void BuiltStyledStreamWriter::writeIndent() {
01047
01048
01049
01050
01051
01052 if (!indentation_.empty()) {
01053
01054 *sout_ << '\n' << indentString_;
01055 }
01056 }
01057
01058 void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {
01059 if (!indented_) writeIndent();
01060 *sout_ << value;
01061 indented_ = false;
01062 }
01063
01064 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
01065
01066 void BuiltStyledStreamWriter::unindent() {
01067 assert(indentString_.size() >= indentation_.size());
01068 indentString_.resize(indentString_.size() - indentation_.size());
01069 }
01070
01071 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
01072 if (cs_ == CommentStyle::None) return;
01073 if (!root.hasComment(commentBefore))
01074 return;
01075
01076 if (!indented_) writeIndent();
01077 const JSONCPP_STRING& comment = root.getComment(commentBefore);
01078 JSONCPP_STRING::const_iterator iter = comment.begin();
01079 while (iter != comment.end()) {
01080 *sout_ << *iter;
01081 if (*iter == '\n' &&
01082 (iter != comment.end() && *(iter + 1) == '/'))
01083
01084 *sout_ << indentString_;
01085 ++iter;
01086 }
01087 indented_ = false;
01088 }
01089
01090 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
01091 if (cs_ == CommentStyle::None) return;
01092 if (root.hasComment(commentAfterOnSameLine))
01093 *sout_ << " " + root.getComment(commentAfterOnSameLine);
01094
01095 if (root.hasComment(commentAfter)) {
01096 writeIndent();
01097 *sout_ << root.getComment(commentAfter);
01098 }
01099 }
01100
01101
01102 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
01103 return value.hasComment(commentBefore) ||
01104 value.hasComment(commentAfterOnSameLine) ||
01105 value.hasComment(commentAfter);
01106 }
01107
01109
01110
01111 StreamWriter::StreamWriter()
01112 : sout_(NULL)
01113 {
01114 }
01115 StreamWriter::~StreamWriter()
01116 {
01117 }
01118 StreamWriter::Factory::~Factory()
01119 {}
01120 StreamWriterBuilder::StreamWriterBuilder()
01121 {
01122 setDefaults(&settings_);
01123 }
01124 StreamWriterBuilder::~StreamWriterBuilder()
01125 {}
01126 StreamWriter* StreamWriterBuilder::newStreamWriter() const
01127 {
01128 JSONCPP_STRING indentation = settings_["indentation"].asString();
01129 JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
01130 bool eyc = settings_["enableYAMLCompatibility"].asBool();
01131 bool dnp = settings_["dropNullPlaceholders"].asBool();
01132 bool usf = settings_["useSpecialFloats"].asBool();
01133 unsigned int pre = settings_["precision"].asUInt();
01134 CommentStyle::Enum cs = CommentStyle::All;
01135 if (cs_str == "All") {
01136 cs = CommentStyle::All;
01137 } else if (cs_str == "None") {
01138 cs = CommentStyle::None;
01139 } else {
01140 throwRuntimeError("commentStyle must be 'All' or 'None'");
01141 }
01142 JSONCPP_STRING colonSymbol = " : ";
01143 if (eyc) {
01144 colonSymbol = ": ";
01145 } else if (indentation.empty()) {
01146 colonSymbol = ":";
01147 }
01148 JSONCPP_STRING nullSymbol = "null";
01149 if (dnp) {
01150 nullSymbol = "";
01151 }
01152 if (pre > 17) pre = 17;
01153 JSONCPP_STRING endingLineFeedSymbol = "";
01154 return new BuiltStyledStreamWriter(
01155 indentation, cs,
01156 colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
01157 }
01158 static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
01159 {
01160 valid_keys->clear();
01161 valid_keys->insert("indentation");
01162 valid_keys->insert("commentStyle");
01163 valid_keys->insert("enableYAMLCompatibility");
01164 valid_keys->insert("dropNullPlaceholders");
01165 valid_keys->insert("useSpecialFloats");
01166 valid_keys->insert("precision");
01167 }
01168 bool StreamWriterBuilder::validate(Json::Value* invalid) const
01169 {
01170 Json::Value my_invalid;
01171 if (!invalid) invalid = &my_invalid;
01172 Json::Value& inv = *invalid;
01173 std::set<JSONCPP_STRING> valid_keys;
01174 getValidWriterKeys(&valid_keys);
01175 Value::Members keys = settings_.getMemberNames();
01176 size_t n = keys.size();
01177 for (size_t i = 0; i < n; ++i) {
01178 JSONCPP_STRING const& key = keys[i];
01179 if (valid_keys.find(key) == valid_keys.end()) {
01180 inv[key] = settings_[key];
01181 }
01182 }
01183 return 0u == inv.size();
01184 }
01185 Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)
01186 {
01187 return settings_[key];
01188 }
01189
01190 void StreamWriterBuilder::setDefaults(Json::Value* settings)
01191 {
01193 (*settings)["commentStyle"] = "All";
01194 (*settings)["indentation"] = "\t";
01195 (*settings)["enableYAMLCompatibility"] = false;
01196 (*settings)["dropNullPlaceholders"] = false;
01197 (*settings)["useSpecialFloats"] = false;
01198 (*settings)["precision"] = 17;
01200 }
01201
01202 JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {
01203 JSONCPP_OSTRINGSTREAM sout;
01204 StreamWriterPtr const writer(builder.newStreamWriter());
01205 writer->write(root, &sout);
01206 return sout.str();
01207 }
01208
01209 JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
01210 StreamWriterBuilder builder;
01211 StreamWriterPtr const writer(builder.newStreamWriter());
01212 writer->write(root, &sout);
01213 return sout;
01214 }
01215
01216 }