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), dropNullPlaceholders_(false),
00288 omitEndingLineFeed_(false) {}
00289
00290 void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
00291
00292 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
00293
00294 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
00295
00296 std::string FastWriter::write(const Value& root) {
00297 document_ = "";
00298 writeValue(root);
00299 if (!omitEndingLineFeed_)
00300 document_ += "\n";
00301 return document_;
00302 }
00303
00304 void FastWriter::writeValue(const Value& value) {
00305 switch (value.type()) {
00306 case nullValue:
00307 if (!dropNullPlaceholders_)
00308 document_ += "null";
00309 break;
00310 case intValue:
00311 document_ += valueToString(value.asLargestInt());
00312 break;
00313 case uintValue:
00314 document_ += valueToString(value.asLargestUInt());
00315 break;
00316 case realValue:
00317 document_ += valueToString(value.asDouble());
00318 break;
00319 case stringValue:
00320 {
00321
00322 char const* str;
00323 char const* end;
00324 bool ok = value.getString(&str, &end);
00325 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
00326 break;
00327 }
00328 case booleanValue:
00329 document_ += valueToString(value.asBool());
00330 break;
00331 case arrayValue: {
00332 document_ += '[';
00333 int size = value.size();
00334 for (int index = 0; index < size; ++index) {
00335 if (index > 0)
00336 document_ += ',';
00337 writeValue(value[index]);
00338 }
00339 document_ += ']';
00340 } break;
00341 case objectValue: {
00342 Value::Members members(value.getMemberNames());
00343 document_ += '{';
00344 for (Value::Members::iterator it = members.begin(); it != members.end();
00345 ++it) {
00346 const std::string& name = *it;
00347 if (it != members.begin())
00348 document_ += ',';
00349 document_ += valueToQuotedStringN(name.data(), name.length());
00350 document_ += yamlCompatiblityEnabled_ ? ": " : ":";
00351 writeValue(value[name]);
00352 }
00353 document_ += '}';
00354 } break;
00355 }
00356 }
00357
00358
00359
00360
00361 StyledWriter::StyledWriter()
00362 : rightMargin_(74), indentSize_(3), addChildValues_() {}
00363
00364 std::string StyledWriter::write(const Value& root) {
00365 document_ = "";
00366 addChildValues_ = false;
00367 indentString_ = "";
00368 writeCommentBeforeValue(root);
00369 writeValue(root);
00370 writeCommentAfterValueOnSameLine(root);
00371 document_ += "\n";
00372 return document_;
00373 }
00374
00375 void StyledWriter::writeValue(const Value& value) {
00376 switch (value.type()) {
00377 case nullValue:
00378 pushValue("null");
00379 break;
00380 case intValue:
00381 pushValue(valueToString(value.asLargestInt()));
00382 break;
00383 case uintValue:
00384 pushValue(valueToString(value.asLargestUInt()));
00385 break;
00386 case realValue:
00387 pushValue(valueToString(value.asDouble()));
00388 break;
00389 case stringValue:
00390 {
00391
00392 char const* str;
00393 char const* end;
00394 bool ok = value.getString(&str, &end);
00395 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
00396 else pushValue("");
00397 break;
00398 }
00399 case booleanValue:
00400 pushValue(valueToString(value.asBool()));
00401 break;
00402 case arrayValue:
00403 writeArrayValue(value);
00404 break;
00405 case objectValue: {
00406 Value::Members members(value.getMemberNames());
00407 if (members.empty())
00408 pushValue("{}");
00409 else {
00410 writeWithIndent("{");
00411 indent();
00412 Value::Members::iterator it = members.begin();
00413 for (;;) {
00414 const std::string& name = *it;
00415 const Value& childValue = value[name];
00416 writeCommentBeforeValue(childValue);
00417 writeWithIndent(valueToQuotedString(name.c_str()));
00418 document_ += " : ";
00419 writeValue(childValue);
00420 if (++it == members.end()) {
00421 writeCommentAfterValueOnSameLine(childValue);
00422 break;
00423 }
00424 document_ += ',';
00425 writeCommentAfterValueOnSameLine(childValue);
00426 }
00427 unindent();
00428 writeWithIndent("}");
00429 }
00430 } break;
00431 }
00432 }
00433
00434 void StyledWriter::writeArrayValue(const Value& value) {
00435 unsigned size = value.size();
00436 if (size == 0)
00437 pushValue("[]");
00438 else {
00439 bool isArrayMultiLine = isMultineArray(value);
00440 if (isArrayMultiLine) {
00441 writeWithIndent("[");
00442 indent();
00443 bool hasChildValue = !childValues_.empty();
00444 unsigned index = 0;
00445 for (;;) {
00446 const Value& childValue = value[index];
00447 writeCommentBeforeValue(childValue);
00448 if (hasChildValue)
00449 writeWithIndent(childValues_[index]);
00450 else {
00451 writeIndent();
00452 writeValue(childValue);
00453 }
00454 if (++index == size) {
00455 writeCommentAfterValueOnSameLine(childValue);
00456 break;
00457 }
00458 document_ += ',';
00459 writeCommentAfterValueOnSameLine(childValue);
00460 }
00461 unindent();
00462 writeWithIndent("]");
00463 } else
00464 {
00465 assert(childValues_.size() == size);
00466 document_ += "[ ";
00467 for (unsigned index = 0; index < size; ++index) {
00468 if (index > 0)
00469 document_ += ", ";
00470 document_ += childValues_[index];
00471 }
00472 document_ += " ]";
00473 }
00474 }
00475 }
00476
00477 bool StyledWriter::isMultineArray(const Value& value) {
00478 int size = value.size();
00479 bool isMultiLine = size * 3 >= rightMargin_;
00480 childValues_.clear();
00481 for (int index = 0; index < size && !isMultiLine; ++index) {
00482 const Value& childValue = value[index];
00483 isMultiLine =
00484 isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
00485 childValue.size() > 0);
00486 }
00487 if (!isMultiLine)
00488 {
00489 childValues_.reserve(size);
00490 addChildValues_ = true;
00491 int lineLength = 4 + (size - 1) * 2;
00492 for (int index = 0; index < size; ++index) {
00493 if (hasCommentForValue(value[index])) {
00494 isMultiLine = true;
00495 }
00496 writeValue(value[index]);
00497 lineLength += int(childValues_[index].length());
00498 }
00499 addChildValues_ = false;
00500 isMultiLine = isMultiLine || lineLength >= rightMargin_;
00501 }
00502 return isMultiLine;
00503 }
00504
00505 void StyledWriter::pushValue(const std::string& value) {
00506 if (addChildValues_)
00507 childValues_.push_back(value);
00508 else
00509 document_ += value;
00510 }
00511
00512 void StyledWriter::writeIndent() {
00513 if (!document_.empty()) {
00514 char last = document_[document_.length() - 1];
00515 if (last == ' ')
00516 return;
00517 if (last != '\n')
00518 document_ += '\n';
00519 }
00520 document_ += indentString_;
00521 }
00522
00523 void StyledWriter::writeWithIndent(const std::string& value) {
00524 writeIndent();
00525 document_ += value;
00526 }
00527
00528 void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
00529
00530 void StyledWriter::unindent() {
00531 assert(int(indentString_.size()) >= indentSize_);
00532 indentString_.resize(indentString_.size() - indentSize_);
00533 }
00534
00535 void StyledWriter::writeCommentBeforeValue(const Value& root) {
00536 if (!root.hasComment(commentBefore))
00537 return;
00538
00539 document_ += "\n";
00540 writeIndent();
00541 const std::string& comment = root.getComment(commentBefore);
00542 std::string::const_iterator iter = comment.begin();
00543 while (iter != comment.end()) {
00544 document_ += *iter;
00545 if (*iter == '\n' &&
00546 (iter != comment.end() && *(iter + 1) == '/'))
00547 writeIndent();
00548 ++iter;
00549 }
00550
00551
00552 document_ += "\n";
00553 }
00554
00555 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
00556 if (root.hasComment(commentAfterOnSameLine))
00557 document_ += " " + root.getComment(commentAfterOnSameLine);
00558
00559 if (root.hasComment(commentAfter)) {
00560 document_ += "\n";
00561 document_ += root.getComment(commentAfter);
00562 document_ += "\n";
00563 }
00564 }
00565
00566 bool StyledWriter::hasCommentForValue(const Value& value) {
00567 return value.hasComment(commentBefore) ||
00568 value.hasComment(commentAfterOnSameLine) ||
00569 value.hasComment(commentAfter);
00570 }
00571
00572
00573
00574
00575 StyledStreamWriter::StyledStreamWriter(std::string indentation)
00576 : document_(NULL), rightMargin_(74), indentation_(indentation),
00577 addChildValues_() {}
00578
00579 void StyledStreamWriter::write(std::ostream& out, const Value& root) {
00580 document_ = &out;
00581 addChildValues_ = false;
00582 indentString_ = "";
00583 indented_ = true;
00584 writeCommentBeforeValue(root);
00585 if (!indented_) writeIndent();
00586 indented_ = true;
00587 writeValue(root);
00588 writeCommentAfterValueOnSameLine(root);
00589 *document_ << "\n";
00590 document_ = NULL;
00591 }
00592
00593 void StyledStreamWriter::writeValue(const Value& value) {
00594 switch (value.type()) {
00595 case nullValue:
00596 pushValue("null");
00597 break;
00598 case intValue:
00599 pushValue(valueToString(value.asLargestInt()));
00600 break;
00601 case uintValue:
00602 pushValue(valueToString(value.asLargestUInt()));
00603 break;
00604 case realValue:
00605 pushValue(valueToString(value.asDouble()));
00606 break;
00607 case stringValue:
00608 {
00609
00610 char const* str;
00611 char const* end;
00612 bool ok = value.getString(&str, &end);
00613 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
00614 else pushValue("");
00615 break;
00616 }
00617 case booleanValue:
00618 pushValue(valueToString(value.asBool()));
00619 break;
00620 case arrayValue:
00621 writeArrayValue(value);
00622 break;
00623 case objectValue: {
00624 Value::Members members(value.getMemberNames());
00625 if (members.empty())
00626 pushValue("{}");
00627 else {
00628 writeWithIndent("{");
00629 indent();
00630 Value::Members::iterator it = members.begin();
00631 for (;;) {
00632 const std::string& name = *it;
00633 const Value& childValue = value[name];
00634 writeCommentBeforeValue(childValue);
00635 writeWithIndent(valueToQuotedString(name.c_str()));
00636 *document_ << " : ";
00637 writeValue(childValue);
00638 if (++it == members.end()) {
00639 writeCommentAfterValueOnSameLine(childValue);
00640 break;
00641 }
00642 *document_ << ",";
00643 writeCommentAfterValueOnSameLine(childValue);
00644 }
00645 unindent();
00646 writeWithIndent("}");
00647 }
00648 } break;
00649 }
00650 }
00651
00652 void StyledStreamWriter::writeArrayValue(const Value& value) {
00653 unsigned size = value.size();
00654 if (size == 0)
00655 pushValue("[]");
00656 else {
00657 bool isArrayMultiLine = isMultineArray(value);
00658 if (isArrayMultiLine) {
00659 writeWithIndent("[");
00660 indent();
00661 bool hasChildValue = !childValues_.empty();
00662 unsigned index = 0;
00663 for (;;) {
00664 const Value& childValue = value[index];
00665 writeCommentBeforeValue(childValue);
00666 if (hasChildValue)
00667 writeWithIndent(childValues_[index]);
00668 else {
00669 if (!indented_) writeIndent();
00670 indented_ = true;
00671 writeValue(childValue);
00672 indented_ = false;
00673 }
00674 if (++index == size) {
00675 writeCommentAfterValueOnSameLine(childValue);
00676 break;
00677 }
00678 *document_ << ",";
00679 writeCommentAfterValueOnSameLine(childValue);
00680 }
00681 unindent();
00682 writeWithIndent("]");
00683 } else
00684 {
00685 assert(childValues_.size() == size);
00686 *document_ << "[ ";
00687 for (unsigned index = 0; index < size; ++index) {
00688 if (index > 0)
00689 *document_ << ", ";
00690 *document_ << childValues_[index];
00691 }
00692 *document_ << " ]";
00693 }
00694 }
00695 }
00696
00697 bool StyledStreamWriter::isMultineArray(const Value& value) {
00698 int size = value.size();
00699 bool isMultiLine = size * 3 >= rightMargin_;
00700 childValues_.clear();
00701 for (int index = 0; index < size && !isMultiLine; ++index) {
00702 const Value& childValue = value[index];
00703 isMultiLine =
00704 isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
00705 childValue.size() > 0);
00706 }
00707 if (!isMultiLine)
00708 {
00709 childValues_.reserve(size);
00710 addChildValues_ = true;
00711 int lineLength = 4 + (size - 1) * 2;
00712 for (int index = 0; index < size; ++index) {
00713 if (hasCommentForValue(value[index])) {
00714 isMultiLine = true;
00715 }
00716 writeValue(value[index]);
00717 lineLength += int(childValues_[index].length());
00718 }
00719 addChildValues_ = false;
00720 isMultiLine = isMultiLine || lineLength >= rightMargin_;
00721 }
00722 return isMultiLine;
00723 }
00724
00725 void StyledStreamWriter::pushValue(const std::string& value) {
00726 if (addChildValues_)
00727 childValues_.push_back(value);
00728 else
00729 *document_ << value;
00730 }
00731
00732 void StyledStreamWriter::writeIndent() {
00733
00734
00735
00736
00737 *document_ << '\n' << indentString_;
00738 }
00739
00740 void StyledStreamWriter::writeWithIndent(const std::string& value) {
00741 if (!indented_) writeIndent();
00742 *document_ << value;
00743 indented_ = false;
00744 }
00745
00746 void StyledStreamWriter::indent() { indentString_ += indentation_; }
00747
00748 void StyledStreamWriter::unindent() {
00749 assert(indentString_.size() >= indentation_.size());
00750 indentString_.resize(indentString_.size() - indentation_.size());
00751 }
00752
00753 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
00754 if (!root.hasComment(commentBefore))
00755 return;
00756
00757 if (!indented_) writeIndent();
00758 const std::string& comment = root.getComment(commentBefore);
00759 std::string::const_iterator iter = comment.begin();
00760 while (iter != comment.end()) {
00761 *document_ << *iter;
00762 if (*iter == '\n' &&
00763 (iter != comment.end() && *(iter + 1) == '/'))
00764
00765 *document_ << indentString_;
00766 ++iter;
00767 }
00768 indented_ = false;
00769 }
00770
00771 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
00772 if (root.hasComment(commentAfterOnSameLine))
00773 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
00774
00775 if (root.hasComment(commentAfter)) {
00776 writeIndent();
00777 *document_ << root.getComment(commentAfter);
00778 }
00779 indented_ = false;
00780 }
00781
00782 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
00783 return value.hasComment(commentBefore) ||
00784 value.hasComment(commentAfterOnSameLine) ||
00785 value.hasComment(commentAfter);
00786 }
00787
00789
00790
00792 struct CommentStyle {
00794 enum Enum {
00795 None,
00796 Most,
00797 All
00798 };
00799 };
00800
00801 struct BuiltStyledStreamWriter : public StreamWriter
00802 {
00803 BuiltStyledStreamWriter(
00804 std::string const& indentation,
00805 CommentStyle::Enum cs,
00806 std::string const& colonSymbol,
00807 std::string const& nullSymbol,
00808 std::string const& endingLineFeedSymbol);
00809 virtual int write(Value const& root, std::ostream* sout);
00810 private:
00811 void writeValue(Value const& value);
00812 void writeArrayValue(Value const& value);
00813 bool isMultineArray(Value const& value);
00814 void pushValue(std::string const& value);
00815 void writeIndent();
00816 void writeWithIndent(std::string const& value);
00817 void indent();
00818 void unindent();
00819 void writeCommentBeforeValue(Value const& root);
00820 void writeCommentAfterValueOnSameLine(Value const& root);
00821 static bool hasCommentForValue(const Value& value);
00822
00823 typedef std::vector<std::string> ChildValues;
00824
00825 ChildValues childValues_;
00826 std::string indentString_;
00827 int rightMargin_;
00828 std::string indentation_;
00829 CommentStyle::Enum cs_;
00830 std::string colonSymbol_;
00831 std::string nullSymbol_;
00832 std::string endingLineFeedSymbol_;
00833 bool addChildValues_ : 1;
00834 bool indented_ : 1;
00835 };
00836 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
00837 std::string const& indentation,
00838 CommentStyle::Enum cs,
00839 std::string const& colonSymbol,
00840 std::string const& nullSymbol,
00841 std::string const& endingLineFeedSymbol)
00842 : rightMargin_(74)
00843 , indentation_(indentation)
00844 , cs_(cs)
00845 , colonSymbol_(colonSymbol)
00846 , nullSymbol_(nullSymbol)
00847 , endingLineFeedSymbol_(endingLineFeedSymbol)
00848 , addChildValues_(false)
00849 , indented_(false)
00850 {
00851 }
00852 int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
00853 {
00854 sout_ = sout;
00855 addChildValues_ = false;
00856 indented_ = true;
00857 indentString_ = "";
00858 writeCommentBeforeValue(root);
00859 if (!indented_) writeIndent();
00860 indented_ = true;
00861 writeValue(root);
00862 writeCommentAfterValueOnSameLine(root);
00863 *sout_ << endingLineFeedSymbol_;
00864 sout_ = NULL;
00865 return 0;
00866 }
00867 void BuiltStyledStreamWriter::writeValue(Value const& value) {
00868 switch (value.type()) {
00869 case nullValue:
00870 pushValue(nullSymbol_);
00871 break;
00872 case intValue:
00873 pushValue(valueToString(value.asLargestInt()));
00874 break;
00875 case uintValue:
00876 pushValue(valueToString(value.asLargestUInt()));
00877 break;
00878 case realValue:
00879 pushValue(valueToString(value.asDouble()));
00880 break;
00881 case stringValue:
00882 {
00883
00884 char const* str;
00885 char const* end;
00886 bool ok = value.getString(&str, &end);
00887 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
00888 else pushValue("");
00889 break;
00890 }
00891 case booleanValue:
00892 pushValue(valueToString(value.asBool()));
00893 break;
00894 case arrayValue:
00895 writeArrayValue(value);
00896 break;
00897 case objectValue: {
00898 Value::Members members(value.getMemberNames());
00899 if (members.empty())
00900 pushValue("{}");
00901 else {
00902 writeWithIndent("{");
00903 indent();
00904 Value::Members::iterator it = members.begin();
00905 for (;;) {
00906 std::string const& name = *it;
00907 Value const& childValue = value[name];
00908 writeCommentBeforeValue(childValue);
00909 writeWithIndent(valueToQuotedStringN(name.data(), name.length()));
00910 *sout_ << colonSymbol_;
00911 writeValue(childValue);
00912 if (++it == members.end()) {
00913 writeCommentAfterValueOnSameLine(childValue);
00914 break;
00915 }
00916 *sout_ << ",";
00917 writeCommentAfterValueOnSameLine(childValue);
00918 }
00919 unindent();
00920 writeWithIndent("}");
00921 }
00922 } break;
00923 }
00924 }
00925
00926 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
00927 unsigned size = value.size();
00928 if (size == 0)
00929 pushValue("[]");
00930 else {
00931 bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
00932 if (isMultiLine) {
00933 writeWithIndent("[");
00934 indent();
00935 bool hasChildValue = !childValues_.empty();
00936 unsigned index = 0;
00937 for (;;) {
00938 Value const& childValue = value[index];
00939 writeCommentBeforeValue(childValue);
00940 if (hasChildValue)
00941 writeWithIndent(childValues_[index]);
00942 else {
00943 if (!indented_) writeIndent();
00944 indented_ = true;
00945 writeValue(childValue);
00946 indented_ = false;
00947 }
00948 if (++index == size) {
00949 writeCommentAfterValueOnSameLine(childValue);
00950 break;
00951 }
00952 *sout_ << ",";
00953 writeCommentAfterValueOnSameLine(childValue);
00954 }
00955 unindent();
00956 writeWithIndent("]");
00957 } else
00958 {
00959 assert(childValues_.size() == size);
00960 *sout_ << "[";
00961 if (!indentation_.empty()) *sout_ << " ";
00962 for (unsigned index = 0; index < size; ++index) {
00963 if (index > 0)
00964 *sout_ << ", ";
00965 *sout_ << childValues_[index];
00966 }
00967 if (!indentation_.empty()) *sout_ << " ";
00968 *sout_ << "]";
00969 }
00970 }
00971 }
00972
00973 bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
00974 int size = value.size();
00975 bool isMultiLine = size * 3 >= rightMargin_;
00976 childValues_.clear();
00977 for (int index = 0; index < size && !isMultiLine; ++index) {
00978 Value const& childValue = value[index];
00979 isMultiLine =
00980 isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
00981 childValue.size() > 0);
00982 }
00983 if (!isMultiLine)
00984 {
00985 childValues_.reserve(size);
00986 addChildValues_ = true;
00987 int lineLength = 4 + (size - 1) * 2;
00988 for (int index = 0; index < size; ++index) {
00989 if (hasCommentForValue(value[index])) {
00990 isMultiLine = true;
00991 }
00992 writeValue(value[index]);
00993 lineLength += int(childValues_[index].length());
00994 }
00995 addChildValues_ = false;
00996 isMultiLine = isMultiLine || lineLength >= rightMargin_;
00997 }
00998 return isMultiLine;
00999 }
01000
01001 void BuiltStyledStreamWriter::pushValue(std::string const& value) {
01002 if (addChildValues_)
01003 childValues_.push_back(value);
01004 else
01005 *sout_ << value;
01006 }
01007
01008 void BuiltStyledStreamWriter::writeIndent() {
01009
01010
01011
01012
01013
01014 if (!indentation_.empty()) {
01015
01016 *sout_ << '\n' << indentString_;
01017 }
01018 }
01019
01020 void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) {
01021 if (!indented_) writeIndent();
01022 *sout_ << value;
01023 indented_ = false;
01024 }
01025
01026 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
01027
01028 void BuiltStyledStreamWriter::unindent() {
01029 assert(indentString_.size() >= indentation_.size());
01030 indentString_.resize(indentString_.size() - indentation_.size());
01031 }
01032
01033 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
01034 if (cs_ == CommentStyle::None) return;
01035 if (!root.hasComment(commentBefore))
01036 return;
01037
01038 if (!indented_) writeIndent();
01039 const std::string& comment = root.getComment(commentBefore);
01040 std::string::const_iterator iter = comment.begin();
01041 while (iter != comment.end()) {
01042 *sout_ << *iter;
01043 if (*iter == '\n' &&
01044 (iter != comment.end() && *(iter + 1) == '/'))
01045
01046 *sout_ << indentString_;
01047 ++iter;
01048 }
01049 indented_ = false;
01050 }
01051
01052 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
01053 if (cs_ == CommentStyle::None) return;
01054 if (root.hasComment(commentAfterOnSameLine))
01055 *sout_ << " " + root.getComment(commentAfterOnSameLine);
01056
01057 if (root.hasComment(commentAfter)) {
01058 writeIndent();
01059 *sout_ << root.getComment(commentAfter);
01060 }
01061 }
01062
01063
01064 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
01065 return value.hasComment(commentBefore) ||
01066 value.hasComment(commentAfterOnSameLine) ||
01067 value.hasComment(commentAfter);
01068 }
01069
01071
01072
01073 StreamWriter::StreamWriter()
01074 : sout_(NULL)
01075 {
01076 }
01077 StreamWriter::~StreamWriter()
01078 {
01079 }
01080 StreamWriter::Factory::~Factory()
01081 {}
01082 StreamWriterBuilder::StreamWriterBuilder()
01083 {
01084 setDefaults(&settings_);
01085 }
01086 StreamWriterBuilder::~StreamWriterBuilder()
01087 {}
01088 StreamWriter* StreamWriterBuilder::newStreamWriter() const
01089 {
01090 std::string indentation = settings_["indentation"].asString();
01091 std::string cs_str = settings_["commentStyle"].asString();
01092 bool eyc = settings_["enableYAMLCompatibility"].asBool();
01093 bool dnp = settings_["dropNullPlaceholders"].asBool();
01094 CommentStyle::Enum cs = CommentStyle::All;
01095 if (cs_str == "All") {
01096 cs = CommentStyle::All;
01097 } else if (cs_str == "None") {
01098 cs = CommentStyle::None;
01099 } else {
01100 throwRuntimeError("commentStyle must be 'All' or 'None'");
01101 }
01102 std::string colonSymbol = " : ";
01103 if (eyc) {
01104 colonSymbol = ": ";
01105 } else if (indentation.empty()) {
01106 colonSymbol = ":";
01107 }
01108 std::string nullSymbol = "null";
01109 if (dnp) {
01110 nullSymbol = "";
01111 }
01112 std::string endingLineFeedSymbol = "";
01113 return new BuiltStyledStreamWriter(
01114 indentation, cs,
01115 colonSymbol, nullSymbol, endingLineFeedSymbol);
01116 }
01117 static void getValidWriterKeys(std::set<std::string>* valid_keys)
01118 {
01119 valid_keys->clear();
01120 valid_keys->insert("indentation");
01121 valid_keys->insert("commentStyle");
01122 valid_keys->insert("enableYAMLCompatibility");
01123 valid_keys->insert("dropNullPlaceholders");
01124 }
01125 bool StreamWriterBuilder::validate(Json::Value* invalid) const
01126 {
01127 Json::Value my_invalid;
01128 if (!invalid) invalid = &my_invalid;
01129 Json::Value& inv = *invalid;
01130 std::set<std::string> valid_keys;
01131 getValidWriterKeys(&valid_keys);
01132 Value::Members keys = settings_.getMemberNames();
01133 size_t n = keys.size();
01134 for (size_t i = 0; i < n; ++i) {
01135 std::string const& key = keys[i];
01136 if (valid_keys.find(key) == valid_keys.end()) {
01137 inv[key] = settings_[key];
01138 }
01139 }
01140 return 0u == inv.size();
01141 }
01142 Value& StreamWriterBuilder::operator[](std::string key)
01143 {
01144 return settings_[key];
01145 }
01146
01147 void StreamWriterBuilder::setDefaults(Json::Value* settings)
01148 {
01150 (*settings)["commentStyle"] = "All";
01151 (*settings)["indentation"] = "\t";
01152 (*settings)["enableYAMLCompatibility"] = false;
01153 (*settings)["dropNullPlaceholders"] = false;
01155 }
01156
01157 std::string writeString(StreamWriter::Factory const& builder, Value const& root) {
01158 std::ostringstream sout;
01159 StreamWriterPtr const writer(builder.newStreamWriter());
01160 writer->write(root, &sout);
01161 return sout.str();
01162 }
01163
01164 std::ostream& operator<<(std::ostream& sout, Value const& root) {
01165 StreamWriterBuilder builder;
01166 StreamWriterPtr const writer(builder.newStreamWriter());
01167 writer->write(root, &sout);
01168 return sout;
01169 }
01170
01171 }