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