json_writer.cpp 36 KB

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