LCOV - code coverage report
Current view: top level - toolkit/components/jsoncpp/src/lib_json - json_writer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 717 0.1 %
Date: 2017-07-14 16:53:18 Functions: 2 78 2.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright 2011 Baptiste Lepilleur
       2             : // Distributed under MIT license, or public domain if desired and
       3             : // recognized in your jurisdiction.
       4             : // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
       5             : 
       6             : #if !defined(JSON_IS_AMALGAMATION)
       7             : #include <json/writer.h>
       8             : #include "json_tool.h"
       9             : #endif // if !defined(JSON_IS_AMALGAMATION)
      10             : #include <iomanip>
      11             : #include <memory>
      12             : #include <sstream>
      13             : #include <utility>
      14             : #include <set>
      15             : #include <cassert>
      16             : #include <cstring>
      17             : #include <cstdio>
      18             : 
      19             : #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
      20             : #include <float.h>
      21             : #define isfinite _finite
      22             : #elif defined(__sun) && defined(__SVR4) //Solaris
      23             : #if !defined(isfinite)
      24             : #include <ieeefp.h>
      25             : #define isfinite finite
      26             : #endif
      27             : #elif defined(_AIX)
      28             : #if !defined(isfinite)
      29             : #include <math.h>
      30             : #define isfinite finite
      31             : #endif
      32             : #elif defined(__hpux)
      33             : #if !defined(isfinite)
      34             : #if defined(__ia64) && !defined(finite)
      35             : #define isfinite(x) ((sizeof(x) == sizeof(float) ? \
      36             :                      _Isfinitef(x) : _IsFinite(x)))
      37             : #else
      38             : #include <math.h>
      39             : #define isfinite finite
      40             : #endif
      41             : #endif
      42             : #else
      43             : #include <cmath>
      44             : #if !(defined(__QNXNTO__)) // QNX already defines isfinite
      45             : #define isfinite std::isfinite
      46             : #endif
      47             : #endif
      48             : 
      49             : #if defined(_MSC_VER)
      50             : #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
      51             : #define snprintf sprintf_s
      52             : #elif _MSC_VER >= 1900 // VC++ 14.0 and above
      53             : #define snprintf std::snprintf
      54             : #else
      55             : #define snprintf _snprintf
      56             : #endif
      57             : #elif defined(__ANDROID__) || defined(__QNXNTO__)
      58             : #define snprintf snprintf
      59             : #elif __cplusplus >= 201103L
      60             : #if !defined(__MINGW32__) && !defined(__CYGWIN__)
      61             : #define snprintf std::snprintf
      62             : #endif
      63             : #endif
      64             : 
      65             : #if defined(__BORLANDC__)  
      66             : #include <float.h>
      67             : #define isfinite _finite
      68             : #define snprintf _snprintf
      69             : #endif
      70             : 
      71             : #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
      72             : // Disable warning about strdup being deprecated.
      73             : #pragma warning(disable : 4996)
      74             : #endif
      75             : 
      76             : namespace Json {
      77             : 
      78             : #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
      79             : typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
      80             : #else
      81             : typedef std::auto_ptr<StreamWriter>   StreamWriterPtr;
      82             : #endif
      83             : 
      84           0 : static bool containsControlCharacter(const char* str) {
      85           0 :   while (*str) {
      86           0 :     if (isControlCharacter(*(str++)))
      87           0 :       return true;
      88             :   }
      89           0 :   return false;
      90             : }
      91             : 
      92           0 : static bool containsControlCharacter0(const char* str, unsigned len) {
      93           0 :   char const* end = str + len;
      94           0 :   while (end != str) {
      95           0 :     if (isControlCharacter(*str) || 0==*str)
      96           0 :       return true;
      97           0 :     ++str;
      98             :   }
      99           0 :   return false;
     100             : }
     101             : 
     102           0 : JSONCPP_STRING valueToString(LargestInt value) {
     103             :   UIntToStringBuffer buffer;
     104           0 :   char* current = buffer + sizeof(buffer);
     105           0 :   if (value == Value::minLargestInt) {
     106           0 :     uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
     107           0 :     *--current = '-';
     108           0 :   } else if (value < 0) {
     109           0 :     uintToString(LargestUInt(-value), current);
     110           0 :     *--current = '-';
     111             :   } else {
     112           0 :     uintToString(LargestUInt(value), current);
     113             :   }
     114           0 :   assert(current >= buffer);
     115           0 :   return current;
     116             : }
     117             : 
     118           0 : JSONCPP_STRING valueToString(LargestUInt value) {
     119             :   UIntToStringBuffer buffer;
     120           0 :   char* current = buffer + sizeof(buffer);
     121           0 :   uintToString(value, current);
     122           0 :   assert(current >= buffer);
     123           0 :   return current;
     124             : }
     125             : 
     126             : #if defined(JSON_HAS_INT64)
     127             : 
     128           0 : JSONCPP_STRING valueToString(Int value) {
     129           0 :   return valueToString(LargestInt(value));
     130             : }
     131             : 
     132           0 : JSONCPP_STRING valueToString(UInt value) {
     133           0 :   return valueToString(LargestUInt(value));
     134             : }
     135             : 
     136             : #endif // # if defined(JSON_HAS_INT64)
     137             : 
     138             : namespace {
     139           0 : JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
     140             :   // Allocate a buffer that is more than large enough to store the 16 digits of
     141             :   // precision requested below.
     142             :   char buffer[36];
     143           0 :   int len = -1;
     144             : 
     145             :   char formatString[15];
     146           0 :   snprintf(formatString, sizeof(formatString), "%%.%dg", precision);
     147             : 
     148             :   // Print into the buffer. We need not request the alternative representation
     149             :   // that always has a decimal point because JSON doesn't distingish the
     150             :   // concepts of reals and integers.
     151           0 :   if (isfinite(value)) {
     152           0 :     len = snprintf(buffer, sizeof(buffer), formatString, value);
     153             :     
     154             :     // try to ensure we preserve the fact that this was given to us as a double on input
     155           0 :     if (!strstr(buffer, ".") && !strstr(buffer, "e")) {
     156           0 :       strcat(buffer, ".0");
     157             :     }
     158             : 
     159             :   } else {
     160             :     // IEEE standard states that NaN values will not compare to themselves
     161           0 :     if (value != value) {
     162           0 :       len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
     163           0 :     } else if (value < 0) {
     164           0 :       len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
     165             :     } else {
     166           0 :       len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
     167             :     }
     168             :     // For those, we do not need to call fixNumLoc, but it is fast.
     169             :   }
     170           0 :   assert(len >= 0);
     171           0 :   fixNumericLocale(buffer, buffer + len);
     172           0 :   return buffer;
     173             : }
     174             : }
     175             : 
     176           0 : JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
     177             : 
     178           0 : JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
     179             : 
     180           0 : JSONCPP_STRING valueToQuotedString(const char* value) {
     181           0 :   if (value == NULL)
     182           0 :     return "";
     183             :   // Not sure how to handle unicode...
     184           0 :   if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
     185           0 :       !containsControlCharacter(value))
     186           0 :     return JSONCPP_STRING("\"") + value + "\"";
     187             :   // We have to walk value and escape any special characters.
     188             :   // Appending to JSONCPP_STRING is not efficient, but this should be rare.
     189             :   // (Note: forward slashes are *not* rare, but I am not escaping them.)
     190             :   JSONCPP_STRING::size_type maxsize =
     191           0 :       strlen(value) * 2 + 3; // allescaped+quotes+NULL
     192           0 :   JSONCPP_STRING result;
     193           0 :   result.reserve(maxsize); // to avoid lots of mallocs
     194           0 :   result += "\"";
     195           0 :   for (const char* c = value; *c != 0; ++c) {
     196           0 :     switch (*c) {
     197             :     case '\"':
     198           0 :       result += "\\\"";
     199           0 :       break;
     200             :     case '\\':
     201           0 :       result += "\\\\";
     202           0 :       break;
     203             :     case '\b':
     204           0 :       result += "\\b";
     205           0 :       break;
     206             :     case '\f':
     207           0 :       result += "\\f";
     208           0 :       break;
     209             :     case '\n':
     210           0 :       result += "\\n";
     211           0 :       break;
     212             :     case '\r':
     213           0 :       result += "\\r";
     214           0 :       break;
     215             :     case '\t':
     216           0 :       result += "\\t";
     217           0 :       break;
     218             :     // case '/':
     219             :     // Even though \/ is considered a legal escape in JSON, a bare
     220             :     // slash is also legal, so I see no reason to escape it.
     221             :     // (I hope I am not misunderstanding something.
     222             :     // blep notes: actually escaping \/ may be useful in javascript to avoid </
     223             :     // sequence.
     224             :     // Should add a flag to allow this compatibility mode and prevent this
     225             :     // sequence from occurring.
     226             :     default:
     227           0 :       if (isControlCharacter(*c)) {
     228           0 :         JSONCPP_OSTRINGSTREAM oss;
     229           0 :         oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
     230           0 :             << std::setw(4) << static_cast<int>(*c);
     231           0 :         result += oss.str();
     232             :       } else {
     233           0 :         result += *c;
     234             :       }
     235           0 :       break;
     236             :     }
     237             :   }
     238           0 :   result += "\"";
     239           0 :   return result;
     240             : }
     241             : 
     242             : // https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
     243           0 : static char const* strnpbrk(char const* s, char const* accept, size_t n) {
     244           0 :   assert((s || !n) && accept);
     245             : 
     246           0 :   char const* const end = s + n;
     247           0 :   for (char const* cur = s; cur < end; ++cur) {
     248           0 :     int const c = *cur;
     249           0 :     for (char const* a = accept; *a; ++a) {
     250           0 :       if (*a == c) {
     251           0 :         return cur;
     252             :       }
     253             :     }
     254             :   }
     255           0 :   return NULL;
     256             : }
     257           0 : static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
     258           0 :   if (value == NULL)
     259           0 :     return "";
     260             :   // Not sure how to handle unicode...
     261           0 :   if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
     262           0 :       !containsControlCharacter0(value, length))
     263           0 :     return JSONCPP_STRING("\"") + value + "\"";
     264             :   // We have to walk value and escape any special characters.
     265             :   // Appending to JSONCPP_STRING is not efficient, but this should be rare.
     266             :   // (Note: forward slashes are *not* rare, but I am not escaping them.)
     267             :   JSONCPP_STRING::size_type maxsize =
     268           0 :       length * 2 + 3; // allescaped+quotes+NULL
     269           0 :   JSONCPP_STRING result;
     270           0 :   result.reserve(maxsize); // to avoid lots of mallocs
     271           0 :   result += "\"";
     272           0 :   char const* end = value + length;
     273           0 :   for (const char* c = value; c != end; ++c) {
     274           0 :     switch (*c) {
     275             :     case '\"':
     276           0 :       result += "\\\"";
     277           0 :       break;
     278             :     case '\\':
     279           0 :       result += "\\\\";
     280           0 :       break;
     281             :     case '\b':
     282           0 :       result += "\\b";
     283           0 :       break;
     284             :     case '\f':
     285           0 :       result += "\\f";
     286           0 :       break;
     287             :     case '\n':
     288           0 :       result += "\\n";
     289           0 :       break;
     290             :     case '\r':
     291           0 :       result += "\\r";
     292           0 :       break;
     293             :     case '\t':
     294           0 :       result += "\\t";
     295           0 :       break;
     296             :     // case '/':
     297             :     // Even though \/ is considered a legal escape in JSON, a bare
     298             :     // slash is also legal, so I see no reason to escape it.
     299             :     // (I hope I am not misunderstanding something.)
     300             :     // blep notes: actually escaping \/ may be useful in javascript to avoid </
     301             :     // sequence.
     302             :     // Should add a flag to allow this compatibility mode and prevent this
     303             :     // sequence from occurring.
     304             :     default:
     305           0 :       if ((isControlCharacter(*c)) || (*c == 0)) {
     306           0 :         JSONCPP_OSTRINGSTREAM oss;
     307           0 :         oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
     308           0 :             << std::setw(4) << static_cast<int>(*c);
     309           0 :         result += oss.str();
     310             :       } else {
     311           0 :         result += *c;
     312             :       }
     313           0 :       break;
     314             :     }
     315             :   }
     316           0 :   result += "\"";
     317           0 :   return result;
     318             : }
     319             : 
     320             : // Class Writer
     321             : // //////////////////////////////////////////////////////////////////
     322           0 : Writer::~Writer() {}
     323             : 
     324             : // Class FastWriter
     325             : // //////////////////////////////////////////////////////////////////
     326             : 
     327           0 : FastWriter::FastWriter()
     328             :     : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
     329           0 :       omitEndingLineFeed_(false) {}
     330             : 
     331           0 : void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
     332             : 
     333           0 : void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
     334             : 
     335           0 : void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
     336             : 
     337           0 : JSONCPP_STRING FastWriter::write(const Value& root) {
     338           0 :   document_.clear();
     339           0 :   writeValue(root);
     340           0 :   if (!omitEndingLineFeed_)
     341           0 :     document_ += "\n";
     342           0 :   return document_;
     343             : }
     344             : 
     345           0 : void FastWriter::writeValue(const Value& value) {
     346           0 :   switch (value.type()) {
     347             :   case nullValue:
     348           0 :     if (!dropNullPlaceholders_)
     349           0 :       document_ += "null";
     350           0 :     break;
     351             :   case intValue:
     352           0 :     document_ += valueToString(value.asLargestInt());
     353           0 :     break;
     354             :   case uintValue:
     355           0 :     document_ += valueToString(value.asLargestUInt());
     356           0 :     break;
     357             :   case realValue:
     358           0 :     document_ += valueToString(value.asDouble());
     359           0 :     break;
     360             :   case stringValue:
     361             :   {
     362             :     // Is NULL possible for value.string_? No.
     363             :     char const* str;
     364             :     char const* end;
     365           0 :     bool ok = value.getString(&str, &end);
     366           0 :     if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
     367           0 :     break;
     368             :   }
     369             :   case booleanValue:
     370           0 :     document_ += valueToString(value.asBool());
     371           0 :     break;
     372             :   case arrayValue: {
     373           0 :     document_ += '[';
     374           0 :     ArrayIndex size = value.size();
     375           0 :     for (ArrayIndex index = 0; index < size; ++index) {
     376           0 :       if (index > 0)
     377           0 :         document_ += ',';
     378           0 :       writeValue(value[index]);
     379             :     }
     380           0 :     document_ += ']';
     381           0 :   } break;
     382             :   case objectValue: {
     383           0 :     Value::Members members(value.getMemberNames());
     384           0 :     document_ += '{';
     385           0 :     for (Value::Members::iterator it = members.begin(); it != members.end();
     386             :          ++it) {
     387           0 :       const JSONCPP_STRING& name = *it;
     388           0 :       if (it != members.begin())
     389           0 :         document_ += ',';
     390           0 :       document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
     391           0 :       document_ += yamlCompatiblityEnabled_ ? ": " : ":";
     392           0 :       writeValue(value[name]);
     393             :     }
     394           0 :     document_ += '}';
     395           0 :   } break;
     396             :   }
     397           0 : }
     398             : 
     399             : // Class StyledWriter
     400             : // //////////////////////////////////////////////////////////////////
     401             : 
     402           0 : StyledWriter::StyledWriter()
     403           0 :     : rightMargin_(74), indentSize_(3), addChildValues_() {}
     404             : 
     405           0 : JSONCPP_STRING StyledWriter::write(const Value& root) {
     406           0 :   document_.clear();
     407           0 :   addChildValues_ = false;
     408           0 :   indentString_.clear();
     409           0 :   writeCommentBeforeValue(root);
     410           0 :   writeValue(root);
     411           0 :   writeCommentAfterValueOnSameLine(root);
     412           0 :   document_ += "\n";
     413           0 :   return document_;
     414             : }
     415             : 
     416           0 : void StyledWriter::writeValue(const Value& value) {
     417           0 :   switch (value.type()) {
     418             :   case nullValue:
     419           0 :     pushValue("null");
     420           0 :     break;
     421             :   case intValue:
     422           0 :     pushValue(valueToString(value.asLargestInt()));
     423           0 :     break;
     424             :   case uintValue:
     425           0 :     pushValue(valueToString(value.asLargestUInt()));
     426           0 :     break;
     427             :   case realValue:
     428           0 :     pushValue(valueToString(value.asDouble()));
     429           0 :     break;
     430             :   case stringValue:
     431             :   {
     432             :     // Is NULL possible for value.string_? No.
     433             :     char const* str;
     434             :     char const* end;
     435           0 :     bool ok = value.getString(&str, &end);
     436           0 :     if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
     437           0 :     else pushValue("");
     438           0 :     break;
     439             :   }
     440             :   case booleanValue:
     441           0 :     pushValue(valueToString(value.asBool()));
     442           0 :     break;
     443             :   case arrayValue:
     444           0 :     writeArrayValue(value);
     445           0 :     break;
     446             :   case objectValue: {
     447           0 :     Value::Members members(value.getMemberNames());
     448           0 :     if (members.empty())
     449           0 :       pushValue("{}");
     450             :     else {
     451           0 :       writeWithIndent("{");
     452           0 :       indent();
     453           0 :       Value::Members::iterator it = members.begin();
     454             :       for (;;) {
     455           0 :         const JSONCPP_STRING& name = *it;
     456           0 :         const Value& childValue = value[name];
     457           0 :         writeCommentBeforeValue(childValue);
     458           0 :         writeWithIndent(valueToQuotedString(name.c_str()));
     459           0 :         document_ += " : ";
     460           0 :         writeValue(childValue);
     461           0 :         if (++it == members.end()) {
     462           0 :           writeCommentAfterValueOnSameLine(childValue);
     463           0 :           break;
     464             :         }
     465           0 :         document_ += ',';
     466           0 :         writeCommentAfterValueOnSameLine(childValue);
     467           0 :       }
     468           0 :       unindent();
     469           0 :       writeWithIndent("}");
     470             :     }
     471           0 :   } break;
     472             :   }
     473           0 : }
     474             : 
     475           0 : void StyledWriter::writeArrayValue(const Value& value) {
     476           0 :   unsigned size = value.size();
     477           0 :   if (size == 0)
     478           0 :     pushValue("[]");
     479             :   else {
     480           0 :     bool isArrayMultiLine = isMultineArray(value);
     481           0 :     if (isArrayMultiLine) {
     482           0 :       writeWithIndent("[");
     483           0 :       indent();
     484           0 :       bool hasChildValue = !childValues_.empty();
     485           0 :       unsigned index = 0;
     486             :       for (;;) {
     487           0 :         const Value& childValue = value[index];
     488           0 :         writeCommentBeforeValue(childValue);
     489           0 :         if (hasChildValue)
     490           0 :           writeWithIndent(childValues_[index]);
     491             :         else {
     492           0 :           writeIndent();
     493           0 :           writeValue(childValue);
     494             :         }
     495           0 :         if (++index == size) {
     496           0 :           writeCommentAfterValueOnSameLine(childValue);
     497           0 :           break;
     498             :         }
     499           0 :         document_ += ',';
     500           0 :         writeCommentAfterValueOnSameLine(childValue);
     501           0 :       }
     502           0 :       unindent();
     503           0 :       writeWithIndent("]");
     504             :     } else // output on a single line
     505             :     {
     506           0 :       assert(childValues_.size() == size);
     507           0 :       document_ += "[ ";
     508           0 :       for (unsigned index = 0; index < size; ++index) {
     509           0 :         if (index > 0)
     510           0 :           document_ += ", ";
     511           0 :         document_ += childValues_[index];
     512             :       }
     513           0 :       document_ += " ]";
     514             :     }
     515             :   }
     516           0 : }
     517             : 
     518           0 : bool StyledWriter::isMultineArray(const Value& value) {
     519           0 :   ArrayIndex const size = value.size();
     520           0 :   bool isMultiLine = size * 3 >= rightMargin_;
     521           0 :   childValues_.clear();
     522           0 :   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     523           0 :     const Value& childValue = value[index];
     524           0 :     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
     525           0 :                         childValue.size() > 0);
     526             :   }
     527           0 :   if (!isMultiLine) // check if line length > max line length
     528             :   {
     529           0 :     childValues_.reserve(size);
     530           0 :     addChildValues_ = true;
     531           0 :     ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
     532           0 :     for (ArrayIndex index = 0; index < size; ++index) {
     533           0 :       if (hasCommentForValue(value[index])) {
     534           0 :         isMultiLine = true;
     535             :       }
     536           0 :       writeValue(value[index]);
     537           0 :       lineLength += static_cast<ArrayIndex>(childValues_[index].length());
     538             :     }
     539           0 :     addChildValues_ = false;
     540           0 :     isMultiLine = isMultiLine || lineLength >= rightMargin_;
     541             :   }
     542           0 :   return isMultiLine;
     543             : }
     544             : 
     545           0 : void StyledWriter::pushValue(const JSONCPP_STRING& value) {
     546           0 :   if (addChildValues_)
     547           0 :     childValues_.push_back(value);
     548             :   else
     549           0 :     document_ += value;
     550           0 : }
     551             : 
     552           0 : void StyledWriter::writeIndent() {
     553           0 :   if (!document_.empty()) {
     554           0 :     char last = document_[document_.length() - 1];
     555           0 :     if (last == ' ') // already indented
     556           0 :       return;
     557           0 :     if (last != '\n') // Comments may add new-line
     558           0 :       document_ += '\n';
     559             :   }
     560           0 :   document_ += indentString_;
     561             : }
     562             : 
     563           0 : void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {
     564           0 :   writeIndent();
     565           0 :   document_ += value;
     566           0 : }
     567             : 
     568           0 : void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
     569             : 
     570           0 : void StyledWriter::unindent() {
     571           0 :   assert(indentString_.size() >= indentSize_);
     572           0 :   indentString_.resize(indentString_.size() - indentSize_);
     573           0 : }
     574             : 
     575           0 : void StyledWriter::writeCommentBeforeValue(const Value& root) {
     576           0 :   if (!root.hasComment(commentBefore))
     577           0 :     return;
     578             : 
     579           0 :   document_ += "\n";
     580           0 :   writeIndent();
     581           0 :   const JSONCPP_STRING& comment = root.getComment(commentBefore);
     582           0 :   JSONCPP_STRING::const_iterator iter = comment.begin();
     583           0 :   while (iter != comment.end()) {
     584           0 :     document_ += *iter;
     585           0 :     if (*iter == '\n' &&
     586           0 :        (iter != comment.end() && *(iter + 1) == '/'))
     587           0 :       writeIndent();
     588           0 :     ++iter;
     589             :   }
     590             : 
     591             :   // Comments are stripped of trailing newlines, so add one here
     592           0 :   document_ += "\n";
     593             : }
     594             : 
     595           0 : void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
     596           0 :   if (root.hasComment(commentAfterOnSameLine))
     597           0 :     document_ += " " + root.getComment(commentAfterOnSameLine);
     598             : 
     599           0 :   if (root.hasComment(commentAfter)) {
     600           0 :     document_ += "\n";
     601           0 :     document_ += root.getComment(commentAfter);
     602           0 :     document_ += "\n";
     603             :   }
     604           0 : }
     605             : 
     606           0 : bool StyledWriter::hasCommentForValue(const Value& value) {
     607           0 :   return value.hasComment(commentBefore) ||
     608           0 :          value.hasComment(commentAfterOnSameLine) ||
     609           0 :          value.hasComment(commentAfter);
     610             : }
     611             : 
     612             : // Class StyledStreamWriter
     613             : // //////////////////////////////////////////////////////////////////
     614             : 
     615           0 : StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
     616             :     : document_(NULL), rightMargin_(74), indentation_(indentation),
     617           0 :       addChildValues_() {}
     618             : 
     619           0 : void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {
     620           0 :   document_ = &out;
     621           0 :   addChildValues_ = false;
     622           0 :   indentString_.clear();
     623           0 :   indented_ = true;
     624           0 :   writeCommentBeforeValue(root);
     625           0 :   if (!indented_) writeIndent();
     626           0 :   indented_ = true;
     627           0 :   writeValue(root);
     628           0 :   writeCommentAfterValueOnSameLine(root);
     629           0 :   *document_ << "\n";
     630           0 :   document_ = NULL; // Forget the stream, for safety.
     631           0 : }
     632             : 
     633           0 : void StyledStreamWriter::writeValue(const Value& value) {
     634           0 :   switch (value.type()) {
     635             :   case nullValue:
     636           0 :     pushValue("null");
     637           0 :     break;
     638             :   case intValue:
     639           0 :     pushValue(valueToString(value.asLargestInt()));
     640           0 :     break;
     641             :   case uintValue:
     642           0 :     pushValue(valueToString(value.asLargestUInt()));
     643           0 :     break;
     644             :   case realValue:
     645           0 :     pushValue(valueToString(value.asDouble()));
     646           0 :     break;
     647             :   case stringValue:
     648             :   {
     649             :     // Is NULL possible for value.string_? No.
     650             :     char const* str;
     651             :     char const* end;
     652           0 :     bool ok = value.getString(&str, &end);
     653           0 :     if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
     654           0 :     else pushValue("");
     655           0 :     break;
     656             :   }
     657             :   case booleanValue:
     658           0 :     pushValue(valueToString(value.asBool()));
     659           0 :     break;
     660             :   case arrayValue:
     661           0 :     writeArrayValue(value);
     662           0 :     break;
     663             :   case objectValue: {
     664           0 :     Value::Members members(value.getMemberNames());
     665           0 :     if (members.empty())
     666           0 :       pushValue("{}");
     667             :     else {
     668           0 :       writeWithIndent("{");
     669           0 :       indent();
     670           0 :       Value::Members::iterator it = members.begin();
     671             :       for (;;) {
     672           0 :         const JSONCPP_STRING& name = *it;
     673           0 :         const Value& childValue = value[name];
     674           0 :         writeCommentBeforeValue(childValue);
     675           0 :         writeWithIndent(valueToQuotedString(name.c_str()));
     676           0 :         *document_ << " : ";
     677           0 :         writeValue(childValue);
     678           0 :         if (++it == members.end()) {
     679           0 :           writeCommentAfterValueOnSameLine(childValue);
     680           0 :           break;
     681             :         }
     682           0 :         *document_ << ",";
     683           0 :         writeCommentAfterValueOnSameLine(childValue);
     684           0 :       }
     685           0 :       unindent();
     686           0 :       writeWithIndent("}");
     687             :     }
     688           0 :   } break;
     689             :   }
     690           0 : }
     691             : 
     692           0 : void StyledStreamWriter::writeArrayValue(const Value& value) {
     693           0 :   unsigned size = value.size();
     694           0 :   if (size == 0)
     695           0 :     pushValue("[]");
     696             :   else {
     697           0 :     bool isArrayMultiLine = isMultineArray(value);
     698           0 :     if (isArrayMultiLine) {
     699           0 :       writeWithIndent("[");
     700           0 :       indent();
     701           0 :       bool hasChildValue = !childValues_.empty();
     702           0 :       unsigned index = 0;
     703             :       for (;;) {
     704           0 :         const Value& childValue = value[index];
     705           0 :         writeCommentBeforeValue(childValue);
     706           0 :         if (hasChildValue)
     707           0 :           writeWithIndent(childValues_[index]);
     708             :         else {
     709           0 :           if (!indented_) writeIndent();
     710           0 :           indented_ = true;
     711           0 :           writeValue(childValue);
     712           0 :           indented_ = false;
     713             :         }
     714           0 :         if (++index == size) {
     715           0 :           writeCommentAfterValueOnSameLine(childValue);
     716           0 :           break;
     717             :         }
     718           0 :         *document_ << ",";
     719           0 :         writeCommentAfterValueOnSameLine(childValue);
     720           0 :       }
     721           0 :       unindent();
     722           0 :       writeWithIndent("]");
     723             :     } else // output on a single line
     724             :     {
     725           0 :       assert(childValues_.size() == size);
     726           0 :       *document_ << "[ ";
     727           0 :       for (unsigned index = 0; index < size; ++index) {
     728           0 :         if (index > 0)
     729           0 :           *document_ << ", ";
     730           0 :         *document_ << childValues_[index];
     731             :       }
     732           0 :       *document_ << " ]";
     733             :     }
     734             :   }
     735           0 : }
     736             : 
     737           0 : bool StyledStreamWriter::isMultineArray(const Value& value) {
     738           0 :   ArrayIndex const size = value.size();
     739           0 :   bool isMultiLine = size * 3 >= rightMargin_;
     740           0 :   childValues_.clear();
     741           0 :   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     742           0 :     const Value& childValue = value[index];
     743           0 :     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
     744           0 :                         childValue.size() > 0);
     745             :   }
     746           0 :   if (!isMultiLine) // check if line length > max line length
     747             :   {
     748           0 :     childValues_.reserve(size);
     749           0 :     addChildValues_ = true;
     750           0 :     ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
     751           0 :     for (ArrayIndex index = 0; index < size; ++index) {
     752           0 :       if (hasCommentForValue(value[index])) {
     753           0 :         isMultiLine = true;
     754             :       }
     755           0 :       writeValue(value[index]);
     756           0 :       lineLength += static_cast<ArrayIndex>(childValues_[index].length());
     757             :     }
     758           0 :     addChildValues_ = false;
     759           0 :     isMultiLine = isMultiLine || lineLength >= rightMargin_;
     760             :   }
     761           0 :   return isMultiLine;
     762             : }
     763             : 
     764           0 : void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {
     765           0 :   if (addChildValues_)
     766           0 :     childValues_.push_back(value);
     767             :   else
     768           0 :     *document_ << value;
     769           0 : }
     770             : 
     771           0 : void StyledStreamWriter::writeIndent() {
     772             :   // blep intended this to look at the so-far-written string
     773             :   // to determine whether we are already indented, but
     774             :   // with a stream we cannot do that. So we rely on some saved state.
     775             :   // The caller checks indented_.
     776           0 :   *document_ << '\n' << indentString_;
     777           0 : }
     778             : 
     779           0 : void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {
     780           0 :   if (!indented_) writeIndent();
     781           0 :   *document_ << value;
     782           0 :   indented_ = false;
     783           0 : }
     784             : 
     785           0 : void StyledStreamWriter::indent() { indentString_ += indentation_; }
     786             : 
     787           0 : void StyledStreamWriter::unindent() {
     788           0 :   assert(indentString_.size() >= indentation_.size());
     789           0 :   indentString_.resize(indentString_.size() - indentation_.size());
     790           0 : }
     791             : 
     792           0 : void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
     793           0 :   if (!root.hasComment(commentBefore))
     794           0 :     return;
     795             : 
     796           0 :   if (!indented_) writeIndent();
     797           0 :   const JSONCPP_STRING& comment = root.getComment(commentBefore);
     798           0 :   JSONCPP_STRING::const_iterator iter = comment.begin();
     799           0 :   while (iter != comment.end()) {
     800           0 :     *document_ << *iter;
     801           0 :     if (*iter == '\n' &&
     802           0 :        (iter != comment.end() && *(iter + 1) == '/'))
     803             :       // writeIndent();  // would include newline
     804           0 :       *document_ << indentString_;
     805           0 :     ++iter;
     806             :   }
     807           0 :   indented_ = false;
     808             : }
     809             : 
     810           0 : void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
     811           0 :   if (root.hasComment(commentAfterOnSameLine))
     812           0 :     *document_ << ' ' << root.getComment(commentAfterOnSameLine);
     813             : 
     814           0 :   if (root.hasComment(commentAfter)) {
     815           0 :     writeIndent();
     816           0 :     *document_ << root.getComment(commentAfter);
     817             :   }
     818           0 :   indented_ = false;
     819           0 : }
     820             : 
     821           0 : bool StyledStreamWriter::hasCommentForValue(const Value& value) {
     822           0 :   return value.hasComment(commentBefore) ||
     823           0 :          value.hasComment(commentAfterOnSameLine) ||
     824           0 :          value.hasComment(commentAfter);
     825             : }
     826             : 
     827             : //////////////////////////
     828             : // BuiltStyledStreamWriter
     829             : 
     830             : /// Scoped enums are not available until C++11.
     831             : struct CommentStyle {
     832             :   /// Decide whether to write comments.
     833             :   enum Enum {
     834             :     None,  ///< Drop all comments.
     835             :     Most,  ///< Recover odd behavior of previous versions (not implemented yet).
     836             :     All  ///< Keep all comments.
     837             :   };
     838             : };
     839             : 
     840           0 : struct BuiltStyledStreamWriter : public StreamWriter
     841             : {
     842             :   BuiltStyledStreamWriter(
     843             :       JSONCPP_STRING const& indentation,
     844             :       CommentStyle::Enum cs,
     845             :       JSONCPP_STRING const& colonSymbol,
     846             :       JSONCPP_STRING const& nullSymbol,
     847             :       JSONCPP_STRING const& endingLineFeedSymbol,
     848             :       bool useSpecialFloats,
     849             :       unsigned int precision);
     850             :   int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
     851             : private:
     852             :   void writeValue(Value const& value);
     853             :   void writeArrayValue(Value const& value);
     854             :   bool isMultineArray(Value const& value);
     855             :   void pushValue(JSONCPP_STRING const& value);
     856             :   void writeIndent();
     857             :   void writeWithIndent(JSONCPP_STRING const& value);
     858             :   void indent();
     859             :   void unindent();
     860             :   void writeCommentBeforeValue(Value const& root);
     861             :   void writeCommentAfterValueOnSameLine(Value const& root);
     862             :   static bool hasCommentForValue(const Value& value);
     863             : 
     864             :   typedef std::vector<JSONCPP_STRING> ChildValues;
     865             : 
     866             :   ChildValues childValues_;
     867             :   JSONCPP_STRING indentString_;
     868             :   unsigned int rightMargin_;
     869             :   JSONCPP_STRING indentation_;
     870             :   CommentStyle::Enum cs_;
     871             :   JSONCPP_STRING colonSymbol_;
     872             :   JSONCPP_STRING nullSymbol_;
     873             :   JSONCPP_STRING endingLineFeedSymbol_;
     874             :   bool addChildValues_ : 1;
     875             :   bool indented_ : 1;
     876             :   bool useSpecialFloats_ : 1;
     877             :   unsigned int precision_;
     878             : };
     879           0 : BuiltStyledStreamWriter::BuiltStyledStreamWriter(
     880             :       JSONCPP_STRING const& indentation,
     881             :       CommentStyle::Enum cs,
     882             :       JSONCPP_STRING const& colonSymbol,
     883             :       JSONCPP_STRING const& nullSymbol,
     884             :       JSONCPP_STRING const& endingLineFeedSymbol,
     885             :       bool useSpecialFloats,
     886           0 :       unsigned int precision)
     887             :   : rightMargin_(74)
     888             :   , indentation_(indentation)
     889             :   , cs_(cs)
     890             :   , colonSymbol_(colonSymbol)
     891             :   , nullSymbol_(nullSymbol)
     892             :   , endingLineFeedSymbol_(endingLineFeedSymbol)
     893             :   , addChildValues_(false)
     894             :   , indented_(false)
     895             :   , useSpecialFloats_(useSpecialFloats)
     896           0 :   , precision_(precision)
     897             : {
     898           0 : }
     899           0 : int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
     900             : {
     901           0 :   sout_ = sout;
     902           0 :   addChildValues_ = false;
     903           0 :   indented_ = true;
     904           0 :   indentString_.clear();
     905           0 :   writeCommentBeforeValue(root);
     906           0 :   if (!indented_) writeIndent();
     907           0 :   indented_ = true;
     908           0 :   writeValue(root);
     909           0 :   writeCommentAfterValueOnSameLine(root);
     910           0 :   *sout_ << endingLineFeedSymbol_;
     911           0 :   sout_ = NULL;
     912           0 :   return 0;
     913             : }
     914           0 : void BuiltStyledStreamWriter::writeValue(Value const& value) {
     915           0 :   switch (value.type()) {
     916             :   case nullValue:
     917           0 :     pushValue(nullSymbol_);
     918           0 :     break;
     919             :   case intValue:
     920           0 :     pushValue(valueToString(value.asLargestInt()));
     921           0 :     break;
     922             :   case uintValue:
     923           0 :     pushValue(valueToString(value.asLargestUInt()));
     924           0 :     break;
     925             :   case realValue:
     926           0 :     pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
     927           0 :     break;
     928             :   case stringValue:
     929             :   {
     930             :     // Is NULL is possible for value.string_? No.
     931             :     char const* str;
     932             :     char const* end;
     933           0 :     bool ok = value.getString(&str, &end);
     934           0 :     if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
     935           0 :     else pushValue("");
     936           0 :     break;
     937             :   }
     938             :   case booleanValue:
     939           0 :     pushValue(valueToString(value.asBool()));
     940           0 :     break;
     941             :   case arrayValue:
     942           0 :     writeArrayValue(value);
     943           0 :     break;
     944             :   case objectValue: {
     945           0 :     Value::Members members(value.getMemberNames());
     946           0 :     if (members.empty())
     947           0 :       pushValue("{}");
     948             :     else {
     949           0 :       writeWithIndent("{");
     950           0 :       indent();
     951           0 :       Value::Members::iterator it = members.begin();
     952             :       for (;;) {
     953           0 :         JSONCPP_STRING const& name = *it;
     954           0 :         Value const& childValue = value[name];
     955           0 :         writeCommentBeforeValue(childValue);
     956           0 :         writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
     957           0 :         *sout_ << colonSymbol_;
     958           0 :         writeValue(childValue);
     959           0 :         if (++it == members.end()) {
     960           0 :           writeCommentAfterValueOnSameLine(childValue);
     961           0 :           break;
     962             :         }
     963           0 :         *sout_ << ",";
     964           0 :         writeCommentAfterValueOnSameLine(childValue);
     965           0 :       }
     966           0 :       unindent();
     967           0 :       writeWithIndent("}");
     968             :     }
     969           0 :   } break;
     970             :   }
     971           0 : }
     972             : 
     973           0 : void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
     974           0 :   unsigned size = value.size();
     975           0 :   if (size == 0)
     976           0 :     pushValue("[]");
     977             :   else {
     978           0 :     bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
     979           0 :     if (isMultiLine) {
     980           0 :       writeWithIndent("[");
     981           0 :       indent();
     982           0 :       bool hasChildValue = !childValues_.empty();
     983           0 :       unsigned index = 0;
     984             :       for (;;) {
     985           0 :         Value const& childValue = value[index];
     986           0 :         writeCommentBeforeValue(childValue);
     987           0 :         if (hasChildValue)
     988           0 :           writeWithIndent(childValues_[index]);
     989             :         else {
     990           0 :           if (!indented_) writeIndent();
     991           0 :           indented_ = true;
     992           0 :           writeValue(childValue);
     993           0 :           indented_ = false;
     994             :         }
     995           0 :         if (++index == size) {
     996           0 :           writeCommentAfterValueOnSameLine(childValue);
     997           0 :           break;
     998             :         }
     999           0 :         *sout_ << ",";
    1000           0 :         writeCommentAfterValueOnSameLine(childValue);
    1001           0 :       }
    1002           0 :       unindent();
    1003           0 :       writeWithIndent("]");
    1004             :     } else // output on a single line
    1005             :     {
    1006           0 :       assert(childValues_.size() == size);
    1007           0 :       *sout_ << "[";
    1008           0 :       if (!indentation_.empty()) *sout_ << " ";
    1009           0 :       for (unsigned index = 0; index < size; ++index) {
    1010           0 :         if (index > 0)
    1011           0 :           *sout_ << ((!indentation_.empty()) ? ", " : ",");
    1012           0 :         *sout_ << childValues_[index];
    1013             :       }
    1014           0 :       if (!indentation_.empty()) *sout_ << " ";
    1015           0 :       *sout_ << "]";
    1016             :     }
    1017             :   }
    1018           0 : }
    1019             : 
    1020           0 : bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
    1021           0 :   ArrayIndex const size = value.size();
    1022           0 :   bool isMultiLine = size * 3 >= rightMargin_;
    1023           0 :   childValues_.clear();
    1024           0 :   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
    1025           0 :     Value const& childValue = value[index];
    1026           0 :     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
    1027           0 :                         childValue.size() > 0);
    1028             :   }
    1029           0 :   if (!isMultiLine) // check if line length > max line length
    1030             :   {
    1031           0 :     childValues_.reserve(size);
    1032           0 :     addChildValues_ = true;
    1033           0 :     ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
    1034           0 :     for (ArrayIndex index = 0; index < size; ++index) {
    1035           0 :       if (hasCommentForValue(value[index])) {
    1036           0 :         isMultiLine = true;
    1037             :       }
    1038           0 :       writeValue(value[index]);
    1039           0 :       lineLength += static_cast<ArrayIndex>(childValues_[index].length());
    1040             :     }
    1041           0 :     addChildValues_ = false;
    1042           0 :     isMultiLine = isMultiLine || lineLength >= rightMargin_;
    1043             :   }
    1044           0 :   return isMultiLine;
    1045             : }
    1046             : 
    1047           0 : void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {
    1048           0 :   if (addChildValues_)
    1049           0 :     childValues_.push_back(value);
    1050             :   else
    1051           0 :     *sout_ << value;
    1052           0 : }
    1053             : 
    1054           0 : void BuiltStyledStreamWriter::writeIndent() {
    1055             :   // blep intended this to look at the so-far-written string
    1056             :   // to determine whether we are already indented, but
    1057             :   // with a stream we cannot do that. So we rely on some saved state.
    1058             :   // The caller checks indented_.
    1059             : 
    1060           0 :   if (!indentation_.empty()) {
    1061             :     // In this case, drop newlines too.
    1062           0 :     *sout_ << '\n' << indentString_;
    1063             :   }
    1064           0 : }
    1065             : 
    1066           0 : void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {
    1067           0 :   if (!indented_) writeIndent();
    1068           0 :   *sout_ << value;
    1069           0 :   indented_ = false;
    1070           0 : }
    1071             : 
    1072           0 : void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
    1073             : 
    1074           0 : void BuiltStyledStreamWriter::unindent() {
    1075           0 :   assert(indentString_.size() >= indentation_.size());
    1076           0 :   indentString_.resize(indentString_.size() - indentation_.size());
    1077           0 : }
    1078             : 
    1079           0 : void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
    1080           0 :   if (cs_ == CommentStyle::None) return;
    1081           0 :   if (!root.hasComment(commentBefore))
    1082           0 :     return;
    1083             : 
    1084           0 :   if (!indented_) writeIndent();
    1085           0 :   const JSONCPP_STRING& comment = root.getComment(commentBefore);
    1086           0 :   JSONCPP_STRING::const_iterator iter = comment.begin();
    1087           0 :   while (iter != comment.end()) {
    1088           0 :     *sout_ << *iter;
    1089           0 :     if (*iter == '\n' &&
    1090           0 :        (iter != comment.end() && *(iter + 1) == '/'))
    1091             :       // writeIndent();  // would write extra newline
    1092           0 :       *sout_ << indentString_;
    1093           0 :     ++iter;
    1094             :   }
    1095           0 :   indented_ = false;
    1096             : }
    1097             : 
    1098           0 : void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
    1099           0 :   if (cs_ == CommentStyle::None) return;
    1100           0 :   if (root.hasComment(commentAfterOnSameLine))
    1101           0 :     *sout_ << " " + root.getComment(commentAfterOnSameLine);
    1102             : 
    1103           0 :   if (root.hasComment(commentAfter)) {
    1104           0 :     writeIndent();
    1105           0 :     *sout_ << root.getComment(commentAfter);
    1106             :   }
    1107             : }
    1108             : 
    1109             : // static
    1110           0 : bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
    1111           0 :   return value.hasComment(commentBefore) ||
    1112           0 :          value.hasComment(commentAfterOnSameLine) ||
    1113           0 :          value.hasComment(commentAfter);
    1114             : }
    1115             : 
    1116             : ///////////////
    1117             : // StreamWriter
    1118             : 
    1119           0 : StreamWriter::StreamWriter()
    1120           0 :     : sout_(NULL)
    1121             : {
    1122           0 : }
    1123           0 : StreamWriter::~StreamWriter()
    1124             : {
    1125           0 : }
    1126           0 : StreamWriter::Factory::~Factory()
    1127           0 : {}
    1128           0 : StreamWriterBuilder::StreamWriterBuilder()
    1129             : {
    1130           0 :   setDefaults(&settings_);
    1131           0 : }
    1132           0 : StreamWriterBuilder::~StreamWriterBuilder()
    1133           0 : {}
    1134           0 : StreamWriter* StreamWriterBuilder::newStreamWriter() const
    1135             : {
    1136           0 :   JSONCPP_STRING indentation = settings_["indentation"].asString();
    1137           0 :   JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
    1138           0 :   bool eyc = settings_["enableYAMLCompatibility"].asBool();
    1139           0 :   bool dnp = settings_["dropNullPlaceholders"].asBool();
    1140           0 :   bool usf = settings_["useSpecialFloats"].asBool(); 
    1141           0 :   unsigned int pre = settings_["precision"].asUInt();
    1142           0 :   CommentStyle::Enum cs = CommentStyle::All;
    1143           0 :   if (cs_str == "All") {
    1144           0 :     cs = CommentStyle::All;
    1145           0 :   } else if (cs_str == "None") {
    1146           0 :     cs = CommentStyle::None;
    1147             :   } else {
    1148           0 :     throwRuntimeError("commentStyle must be 'All' or 'None'");
    1149             :   }
    1150           0 :   JSONCPP_STRING colonSymbol = " : ";
    1151           0 :   if (eyc) {
    1152           0 :     colonSymbol = ": ";
    1153           0 :   } else if (indentation.empty()) {
    1154           0 :     colonSymbol = ":";
    1155             :   }
    1156           0 :   JSONCPP_STRING nullSymbol = "null";
    1157           0 :   if (dnp) {
    1158           0 :     nullSymbol.clear();
    1159             :   }
    1160           0 :   if (pre > 17) pre = 17;
    1161           0 :   JSONCPP_STRING endingLineFeedSymbol;
    1162             :   return new BuiltStyledStreamWriter(
    1163             :       indentation, cs,
    1164           0 :       colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
    1165             : }
    1166           0 : static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
    1167             : {
    1168           0 :   valid_keys->clear();
    1169           0 :   valid_keys->insert("indentation");
    1170           0 :   valid_keys->insert("commentStyle");
    1171           0 :   valid_keys->insert("enableYAMLCompatibility");
    1172           0 :   valid_keys->insert("dropNullPlaceholders");
    1173           0 :   valid_keys->insert("useSpecialFloats");
    1174           0 :   valid_keys->insert("precision");
    1175           0 : }
    1176           0 : bool StreamWriterBuilder::validate(Json::Value* invalid) const
    1177             : {
    1178           0 :   Json::Value my_invalid;
    1179           0 :   if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
    1180           0 :   Json::Value& inv = *invalid;
    1181           0 :   std::set<JSONCPP_STRING> valid_keys;
    1182           0 :   getValidWriterKeys(&valid_keys);
    1183           0 :   Value::Members keys = settings_.getMemberNames();
    1184           0 :   size_t n = keys.size();
    1185           0 :   for (size_t i = 0; i < n; ++i) {
    1186           0 :     JSONCPP_STRING const& key = keys[i];
    1187           0 :     if (valid_keys.find(key) == valid_keys.end()) {
    1188           0 :       inv[key] = settings_[key];
    1189             :     }
    1190             :   }
    1191           0 :   return 0u == inv.size();
    1192             : }
    1193           0 : Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)
    1194             : {
    1195           0 :   return settings_[key];
    1196             : }
    1197             : // static
    1198           0 : void StreamWriterBuilder::setDefaults(Json::Value* settings)
    1199             : {
    1200             :   //! [StreamWriterBuilderDefaults]
    1201           0 :   (*settings)["commentStyle"] = "All";
    1202           0 :   (*settings)["indentation"] = "\t";
    1203           0 :   (*settings)["enableYAMLCompatibility"] = false;
    1204           0 :   (*settings)["dropNullPlaceholders"] = false;
    1205           0 :   (*settings)["useSpecialFloats"] = false;
    1206           0 :   (*settings)["precision"] = 17;
    1207             :   //! [StreamWriterBuilderDefaults]
    1208           0 : }
    1209             : 
    1210           0 : JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {
    1211           0 :   JSONCPP_OSTRINGSTREAM sout;
    1212           0 :   StreamWriterPtr const writer(builder.newStreamWriter());
    1213           0 :   writer->write(root, &sout);
    1214           0 :   return sout.str();
    1215             : }
    1216             : 
    1217           0 : JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
    1218           0 :   StreamWriterBuilder builder;
    1219           0 :   StreamWriterPtr const writer(builder.newStreamWriter());
    1220           0 :   writer->write(root, &sout);
    1221           0 :   return sout;
    1222             : }
    1223             : 
    1224           9 : } // namespace Json

Generated by: LCOV version 1.13