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