6#if !defined(JSON_IS_AMALGAMATION)
24#pragma warning(disable : 4996)
33 char* current = buffer +
sizeof(buffer);
37 }
else if (value < 0) {
43 assert(current >= buffer);
49 char* current = buffer +
sizeof(buffer);
51 assert(current >= buffer);
55#if defined(JSON_HAS_INT64)
65 unsigned int precision, PrecisionType precisionType) {
69 if (!std::isfinite(value)) {
70 if (std::isnan(value))
71 return useSpecialFloats ?
"NaN" :
"null";
73 return useSpecialFloats ?
"-Infinity" :
"-1e+9999";
74 return useSpecialFloats ?
"Infinity" :
"1e+9999";
77 String buffer(
size_t(36),
'\0');
80 &*buffer.begin(), buffer.size(),
84 auto wouldPrint =
static_cast<size_t>(len);
85 if (wouldPrint >= buffer.size()) {
86 buffer.resize(wouldPrint + 1);
89 buffer.resize(wouldPrint);
97 if (buffer.find(
'.') == buffer.npos && buffer.find(
'e') == buffer.npos) {
113 return valueToString(value,
false, precision, precisionType);
121 return std::any_of(s, s + n, [](
unsigned char c) {
122 return c ==
'\\' || c ==
'"' || c < 0x20 || c > 0x7F;
127 const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
129 unsigned int firstByte =
static_cast<unsigned char>(*s);
131 if (firstByte < 0x80)
134 if (firstByte < 0xE0) {
136 return REPLACEMENT_CHARACTER;
138 unsigned int calculated =
139 ((firstByte & 0x1F) << 6) | (
static_cast<unsigned int>(s[1]) & 0x3F);
142 return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
145 if (firstByte < 0xF0) {
147 return REPLACEMENT_CHARACTER;
149 unsigned int calculated = ((firstByte & 0x0F) << 12) |
150 ((
static_cast<unsigned int>(s[1]) & 0x3F) << 6) |
151 (
static_cast<unsigned int>(s[2]) & 0x3F);
155 if (calculated >= 0xD800 && calculated <= 0xDFFF)
156 return REPLACEMENT_CHARACTER;
158 return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
161 if (firstByte < 0xF8) {
163 return REPLACEMENT_CHARACTER;
165 unsigned int calculated = ((firstByte & 0x07) << 18) |
166 ((
static_cast<unsigned int>(s[1]) & 0x3F) << 12) |
167 ((
static_cast<unsigned int>(s[2]) & 0x3F) << 6) |
168 (
static_cast<unsigned int>(s[3]) & 0x3F);
171 return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
174 return REPLACEMENT_CHARACTER;
177static const char hex2[] =
"000102030405060708090a0b0c0d0e0f"
178 "101112131415161718191a1b1c1d1e1f"
179 "202122232425262728292a2b2c2d2e2f"
180 "303132333435363738393a3b3c3d3e3f"
181 "404142434445464748494a4b4c4d4e4f"
182 "505152535455565758595a5b5c5d5e5f"
183 "606162636465666768696a6b6c6d6e6f"
184 "707172737475767778797a7b7c7d7e7f"
185 "808182838485868788898a8b8c8d8e8f"
186 "909192939495969798999a9b9c9d9e9f"
187 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
188 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
189 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
190 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
191 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
192 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
195 const unsigned int hi = (x >> 8) & 0xff;
196 const unsigned int lo = x & 0xff;
198 result[0] =
hex2[2 * hi];
199 result[1] =
hex2[2 * hi + 1];
200 result[2] =
hex2[2 * lo];
201 result[3] =
hex2[2 * lo + 1];
206 result +=
static_cast<char>(ch);
214 bool emitUTF8 =
false) {
215 if (value ==
nullptr)
219 return String(
"\"") + value +
"\"";
223 String::size_type maxsize = length * 2 + 3;
225 result.reserve(maxsize);
227 char const* end = value + length;
228 for (
const char* c = value; c != end; ++c) {
261 unsigned codepoint =
static_cast<unsigned char>(*c);
262 if (codepoint < 0x20) {
269 if (codepoint < 0x20) {
271 }
else if (codepoint < 0x80) {
273 }
else if (codepoint < 0x10000) {
278 codepoint -= 0x10000;
279 appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff));
280 appendHex(result, 0xdc00 + (codepoint & 0x3ff));
318 if (!omitEndingLineFeed_)
323void FastWriter::writeValue(
const Value& value) {
324 switch (value.
type()) {
326 if (!dropNullPlaceholders_)
353 for (
ArrayIndex index = 0; index < size; ++index) {
356 writeValue(value[index]);
363 for (
auto it = members.begin(); it != members.end(); ++it) {
365 if (it != members.begin())
368 document_ += yamlCompatibilityEnabled_ ?
": " :
":";
369 writeValue(value[name]);
383 addChildValues_ =
false;
384 indentString_.clear();
385 writeCommentBeforeValue(root);
387 writeCommentAfterValueOnSameLine(root);
392void StyledWriter::writeValue(
const Value& value) {
393 switch (value.
type()) {
421 writeArrayValue(value);
428 writeWithIndent(
"{");
430 auto it = members.begin();
433 const Value& childValue = value[name];
434 writeCommentBeforeValue(childValue);
437 writeValue(childValue);
438 if (++it == members.end()) {
439 writeCommentAfterValueOnSameLine(childValue);
443 writeCommentAfterValueOnSameLine(childValue);
446 writeWithIndent(
"}");
452void StyledWriter::writeArrayValue(
const Value& value) {
453 size_t size = value.size();
457 bool isArrayMultiLine = isMultilineArray(value);
458 if (isArrayMultiLine) {
459 writeWithIndent(
"[");
461 bool hasChildValue = !childValues_.empty();
464 const Value& childValue = value[index];
465 writeCommentBeforeValue(childValue);
467 writeWithIndent(childValues_[index]);
470 writeValue(childValue);
472 if (++index == size) {
473 writeCommentAfterValueOnSameLine(childValue);
477 writeCommentAfterValueOnSameLine(childValue);
480 writeWithIndent(
"]");
483 assert(childValues_.size() == size);
485 for (
size_t index = 0; index < size; ++index) {
488 document_ += childValues_[index];
495bool StyledWriter::isMultilineArray(
const Value& value) {
497 bool isMultiLine = size * 3 >= rightMargin_;
498 childValues_.clear();
499 for (
ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
500 const Value& childValue = value[index];
501 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
502 !childValue.empty());
506 childValues_.reserve(size);
507 addChildValues_ =
true;
509 for (
ArrayIndex index = 0; index < size; ++index) {
510 if (hasCommentForValue(value[index])) {
513 writeValue(value[index]);
514 lineLength +=
static_cast<ArrayIndex>(childValues_[index].length());
516 addChildValues_ =
false;
517 isMultiLine = isMultiLine || lineLength >= rightMargin_;
522void StyledWriter::pushValue(
const String& value) {
524 childValues_.push_back(value);
529void StyledWriter::writeIndent() {
530 if (!document_.empty()) {
531 char last = document_[document_.length() - 1];
537 document_ += indentString_;
540void StyledWriter::writeWithIndent(
const String& value) {
545void StyledWriter::indent() { indentString_ +=
String(indentSize_,
' '); }
547void StyledWriter::unindent() {
548 assert(indentString_.size() >= indentSize_);
549 indentString_.resize(indentString_.size() - indentSize_);
552void StyledWriter::writeCommentBeforeValue(
const Value& root) {
559 String::const_iterator iter = comment.begin();
560 while (iter != comment.end()) {
562 if (*iter ==
'\n' && ((iter + 1) != comment.end() && *(iter + 1) ==
'/'))
571void StyledWriter::writeCommentAfterValueOnSameLine(
const Value& root) {
582bool StyledWriter::hasCommentForValue(
const Value& value) {
592 : document_(nullptr), indentation_(std::move(indentation)),
593 addChildValues_(), indented_(false) {}
597 addChildValues_ =
false;
598 indentString_.clear();
600 writeCommentBeforeValue(root);
605 writeCommentAfterValueOnSameLine(root);
610void StyledStreamWriter::writeValue(
const Value& value) {
611 switch (value.
type()) {
639 writeArrayValue(value);
646 writeWithIndent(
"{");
648 auto it = members.begin();
651 const Value& childValue = value[name];
652 writeCommentBeforeValue(childValue);
655 writeValue(childValue);
656 if (++it == members.end()) {
657 writeCommentAfterValueOnSameLine(childValue);
661 writeCommentAfterValueOnSameLine(childValue);
664 writeWithIndent(
"}");
670void StyledStreamWriter::writeArrayValue(
const Value& value) {
671 unsigned size = value.size();
675 bool isArrayMultiLine = isMultilineArray(value);
676 if (isArrayMultiLine) {
677 writeWithIndent(
"[");
679 bool hasChildValue = !childValues_.empty();
682 const Value& childValue = value[index];
683 writeCommentBeforeValue(childValue);
685 writeWithIndent(childValues_[index]);
690 writeValue(childValue);
693 if (++index == size) {
694 writeCommentAfterValueOnSameLine(childValue);
698 writeCommentAfterValueOnSameLine(childValue);
701 writeWithIndent(
"]");
704 assert(childValues_.size() == size);
706 for (
unsigned index = 0; index < size; ++index) {
709 *document_ << childValues_[index];
716bool StyledStreamWriter::isMultilineArray(
const Value& value) {
718 bool isMultiLine = size * 3 >= rightMargin_;
719 childValues_.clear();
720 for (
ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
721 const Value& childValue = value[index];
722 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
723 !childValue.empty());
727 childValues_.reserve(size);
728 addChildValues_ =
true;
730 for (
ArrayIndex index = 0; index < size; ++index) {
731 if (hasCommentForValue(value[index])) {
734 writeValue(value[index]);
735 lineLength +=
static_cast<ArrayIndex>(childValues_[index].length());
737 addChildValues_ =
false;
738 isMultiLine = isMultiLine || lineLength >= rightMargin_;
743void StyledStreamWriter::pushValue(
const String& value) {
745 childValues_.push_back(value);
750void StyledStreamWriter::writeIndent() {
755 *document_ <<
'\n' << indentString_;
758void StyledStreamWriter::writeWithIndent(
const String& value) {
765void StyledStreamWriter::indent() { indentString_ += indentation_; }
767void StyledStreamWriter::unindent() {
768 assert(indentString_.size() >= indentation_.size());
769 indentString_.resize(indentString_.size() - indentation_.size());
772void StyledStreamWriter::writeCommentBeforeValue(
const Value& root) {
779 String::const_iterator iter = comment.begin();
780 while (iter != comment.end()) {
782 if (*iter ==
'\n' && ((iter + 1) != comment.end() && *(iter + 1) ==
'/'))
784 *document_ << indentString_;
790void StyledStreamWriter::writeCommentAfterValueOnSameLine(
const Value& root) {
801bool StyledStreamWriter::hasCommentForValue(
const Value& value) {
821 BuiltStyledStreamWriter(
String indentation, CommentStyle::Enum cs,
823 String endingLineFeedSymbol,
bool useSpecialFloats,
824 bool emitUTF8,
unsigned int precision,
826 int write(Value
const& root,
OStream* sout)
override;
829 void writeValue(Value
const& value);
830 void writeArrayValue(Value
const& value);
831 bool isMultilineArray(Value
const& value);
832 void pushValue(
String const& value);
834 void writeWithIndent(
String const& value);
837 void writeCommentBeforeValue(Value
const& root);
838 void writeCommentAfterValueOnSameLine(Value
const& root);
839 static bool hasCommentForValue(
const Value& value);
841 using ChildValues = std::vector<String>;
843 ChildValues childValues_;
845 unsigned int rightMargin_;
847 CommentStyle::Enum cs_;
850 String endingLineFeedSymbol_;
851 bool addChildValues_ : 1;
853 bool useSpecialFloats_ : 1;
855 unsigned int precision_;
858BuiltStyledStreamWriter::BuiltStyledStreamWriter(
859 String indentation, CommentStyle::Enum cs,
String colonSymbol,
860 String nullSymbol,
String endingLineFeedSymbol,
bool useSpecialFloats,
861 bool emitUTF8,
unsigned int precision,
PrecisionType precisionType)
862 : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
863 colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
864 endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
865 addChildValues_(false), indented_(false),
866 useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
867 precision_(precision), precisionType_(precisionType) {}
868int BuiltStyledStreamWriter::write(
Value const& root,
OStream* sout) {
870 addChildValues_ =
false;
872 indentString_.clear();
873 writeCommentBeforeValue(root);
878 writeCommentAfterValueOnSameLine(root);
879 *
sout_ << endingLineFeedSymbol_;
883void BuiltStyledStreamWriter::writeValue(
Value const& value) {
884 switch (value.type()) {
886 pushValue(nullSymbol_);
895 pushValue(
valueToString(value.asDouble(), useSpecialFloats_, precision_,
902 bool ok = value.getString(&str, &end);
914 writeArrayValue(value);
921 writeWithIndent(
"{");
923 auto it = members.begin();
926 Value
const& childValue = value[name];
927 writeCommentBeforeValue(childValue);
930 *
sout_ << colonSymbol_;
931 writeValue(childValue);
932 if (++it == members.end()) {
933 writeCommentAfterValueOnSameLine(childValue);
937 writeCommentAfterValueOnSameLine(childValue);
940 writeWithIndent(
"}");
946void BuiltStyledStreamWriter::writeArrayValue(
Value const& value) {
947 unsigned size = value.size();
951 bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
953 writeWithIndent(
"[");
955 bool hasChildValue = !childValues_.empty();
958 Value
const& childValue = value[index];
959 writeCommentBeforeValue(childValue);
961 writeWithIndent(childValues_[index]);
966 writeValue(childValue);
969 if (++index == size) {
970 writeCommentAfterValueOnSameLine(childValue);
974 writeCommentAfterValueOnSameLine(childValue);
977 writeWithIndent(
"]");
980 assert(childValues_.size() == size);
982 if (!indentation_.empty())
984 for (
unsigned index = 0; index < size; ++index) {
986 *
sout_ << ((!indentation_.empty()) ?
", " :
",");
987 *
sout_ << childValues_[index];
989 if (!indentation_.empty())
996bool BuiltStyledStreamWriter::isMultilineArray(
Value const& value) {
998 bool isMultiLine = size * 3 >= rightMargin_;
999 childValues_.clear();
1000 for (
ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
1001 Value
const& childValue = value[index];
1002 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
1003 !childValue.empty());
1007 childValues_.reserve(size);
1008 addChildValues_ =
true;
1010 for (
ArrayIndex index = 0; index < size; ++index) {
1011 if (hasCommentForValue(value[index])) {
1014 writeValue(value[index]);
1015 lineLength +=
static_cast<ArrayIndex>(childValues_[index].length());
1017 addChildValues_ =
false;
1018 isMultiLine = isMultiLine || lineLength >= rightMargin_;
1023void BuiltStyledStreamWriter::pushValue(
String const& value) {
1024 if (addChildValues_)
1025 childValues_.push_back(value);
1030void BuiltStyledStreamWriter::writeIndent() {
1036 if (!indentation_.empty()) {
1038 *
sout_ <<
'\n' << indentString_;
1042void BuiltStyledStreamWriter::writeWithIndent(
String const& value) {
1049void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
1051void BuiltStyledStreamWriter::unindent() {
1052 assert(indentString_.size() >= indentation_.size());
1053 indentString_.resize(indentString_.size() - indentation_.size());
1056void BuiltStyledStreamWriter::writeCommentBeforeValue(
Value const& root) {
1057 if (cs_ == CommentStyle::None)
1065 String::const_iterator iter = comment.begin();
1066 while (iter != comment.end()) {
1068 if (*iter ==
'\n' && ((iter + 1) != comment.end() && *(iter + 1) ==
'/'))
1070 *
sout_ << indentString_;
1076void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
1077 Value const& root) {
1078 if (cs_ == CommentStyle::None)
1090bool BuiltStyledStreamWriter::hasCommentForValue(
const Value& value) {
1102StreamWriterBuilder::StreamWriterBuilder() {
setDefaults(&settings_); }
1103StreamWriterBuilder::~StreamWriterBuilder() =
default;
1105 const String indentation = settings_[
"indentation"].asString();
1106 const String cs_str = settings_[
"commentStyle"].asString();
1107 const String pt_str = settings_[
"precisionType"].asString();
1108 const bool eyc = settings_[
"enableYAMLCompatibility"].asBool();
1109 const bool dnp = settings_[
"dropNullPlaceholders"].asBool();
1110 const bool usf = settings_[
"useSpecialFloats"].asBool();
1111 const bool emitUTF8 = settings_[
"emitUTF8"].asBool();
1112 unsigned int pre = settings_[
"precision"].asUInt();
1113 CommentStyle::Enum cs = CommentStyle::All;
1114 if (cs_str ==
"All") {
1115 cs = CommentStyle::All;
1116 }
else if (cs_str ==
"None") {
1117 cs = CommentStyle::None;
1119 throwRuntimeError(
"commentStyle must be 'All' or 'None'");
1122 if (pt_str ==
"significant") {
1124 }
else if (pt_str ==
"decimal") {
1127 throwRuntimeError(
"precisionType must be 'significant' or 'decimal'");
1129 String colonSymbol =
" : ";
1132 }
else if (indentation.empty()) {
1135 String nullSymbol =
"null";
1141 String endingLineFeedSymbol;
1142 return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
1143 endingLineFeedSymbol, usf, emitUTF8, pre,
1148 static const auto& valid_keys = *
new std::set<String>{
1151 "enableYAMLCompatibility",
1152 "dropNullPlaceholders",
1158 for (
auto si = settings_.begin(); si != settings_.end(); ++si) {
1159 auto key = si.name();
1160 if (valid_keys.count(key))
1163 (*invalid)[key] = *si;
1167 return invalid ? invalid->
empty() :
true;
1171 return settings_[key];
1176 (*settings)[
"commentStyle"] =
"All";
1177 (*settings)[
"indentation"] =
"\t";
1178 (*settings)[
"enableYAMLCompatibility"] =
false;
1179 (*settings)[
"dropNullPlaceholders"] =
false;
1180 (*settings)[
"useSpecialFloats"] =
false;
1181 (*settings)[
"emitUTF8"] =
false;
1182 (*settings)[
"precision"] = 17;
1183 (*settings)[
"precisionType"] =
"significant";
1190 writer->
write(root, &sout);
1191 return std::move(sout).str();
1197 writer->
write(root, &sout);
String write(const Value &root) override
void dropNullPlaceholders()
Drop the "null" string from the writer's output for nullValues.
void enableYAMLCompatibility()
void omitEndingLineFeed()
A simple abstract factory.
virtual StreamWriter * newStreamWriter() const =0
Allocate a CharReader via operator new().
Build a StreamWriter implementation.
StreamWriter * newStreamWriter() const override
Configuration of this builder.
bool validate(Json::Value *invalid) const
static void setDefaults(Json::Value *settings)
Called by ctor, but you can use this to reset settings_.
Value & operator[](const String &key)
A simple way to update a specific setting.
virtual int write(Value const &root, OStream *sout)=0
Write Value into document as configured in sub-class.
void write(OStream &out, const Value &root)
Serialize a Value in JSON format.
StyledStreamWriter(String indentation="\t")
String write(const Value &root) override
Serialize a Value in JSON format.
bool empty() const
Return true if empty array, empty object, or null; otherwise, false.
static constexpr LargestInt maxLargestInt
Maximum signed integer value that can be stored in a Json::Value.
ArrayIndex size() const
Number of values in array or object.
bool getString(char const **begin, char const **end) const
Get raw char* of string-value.
std::vector< String > Members
Members getMemberNames() const
Return a list of the member names.
LargestInt asLargestInt() const
LargestUInt asLargestUInt() const
static constexpr LargestInt minLargestInt
Minimum signed integer value that can be stored in a Json::Value.
JSON (JavaScript Object Notation).
std::basic_ostringstream< String::value_type, String::traits_type, String::allocator_type > OStringStream
static unsigned int utf8ToCodepoint(const char *&s, const char *e)
std::unique_ptr< StreamWriter > StreamWriterPtr
static void appendRaw(String &result, unsigned ch)
String writeString(StreamWriter::Factory const &factory, Value const &root)
Write into stringstream, then return string, for convenience.
Iter fixNumericLocale(Iter begin, Iter end)
Change ',' to '.
@ commentAfterOnSameLine
a comment just after a value on the same line
@ commentBefore
a comment placed on the line before a value
@ commentAfter
a comment on the line after a value (only make sense for
static String toHex16Bit(unsigned int x)
static bool doesAnyCharRequireEscaping(char const *s, size_t n)
String valueToQuotedString(const char *value)
static String valueToQuotedStringN(const char *value, size_t length, bool emitUTF8=false)
String valueToString(Int value)
@ stringValue
UTF-8 string value.
@ arrayValue
array value (ordered list)
@ intValue
signed integer value
@ objectValue
object value (collection of name/value pairs).
@ uintValue
unsigned integer value
OStream & operator<<(OStream &, const Value &root)
Output using the StyledStreamWriter.
static void appendHex(String &result, unsigned ch)
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision)
Return iterator that would be the new end of the range [begin,end), if we were to delete zeros in the...
std::basic_string< char, std::char_traits< char >, Allocator< char > > String
char[uintToStringBufferSize] UIntToStringBuffer
static void uintToString(LargestUInt value, char *¤t)
Converts an unsigned integer to string.
PrecisionType
Type of precision for formatting of real values.
@ decimalPlaces
we set max number of digits after "." in string
@ significantDigits
we set max number of significant digits in string