JsonCpp project page | JsonCpp home page

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