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