json_writer.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. // Copyright 2007-2010 Baptiste Lepilleur
  2. // Distributed under MIT license, or public domain if desired and
  3. // recognized in your jurisdiction.
  4. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
  5. #if !defined(JSON_IS_AMALGAMATION)
  6. # include <json/writer.h>
  7. # include "json_tool.h"
  8. #endif // if !defined(JSON_IS_AMALGAMATION)
  9. #include <utility>
  10. #include <assert.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <iostream>
  14. #include <sstream>
  15. #include <iomanip>
  16. #if _MSC_VER >= 1400 // VC++ 8.0
  17. #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
  18. #endif
  19. namespace Json {
  20. static bool containsControlCharacter( const char* str )
  21. {
  22. while ( *str )
  23. {
  24. if ( isControlCharacter( *(str++) ) )
  25. return true;
  26. }
  27. return false;
  28. }
  29. std::string valueToString( LargestInt value )
  30. {
  31. UIntToStringBuffer buffer;
  32. char *current = buffer + sizeof(buffer);
  33. bool isNegative = value < 0;
  34. if ( isNegative )
  35. value = -value;
  36. uintToString( LargestUInt(value), current );
  37. if ( isNegative )
  38. *--current = '-';
  39. assert( current >= buffer );
  40. return current;
  41. }
  42. std::string valueToString( LargestUInt value )
  43. {
  44. UIntToStringBuffer buffer;
  45. char *current = buffer + sizeof(buffer);
  46. uintToString( value, current );
  47. assert( current >= buffer );
  48. return current;
  49. }
  50. #if defined(JSON_HAS_INT64)
  51. std::string valueToString( Int value )
  52. {
  53. return valueToString( LargestInt(value) );
  54. }
  55. std::string valueToString( UInt value )
  56. {
  57. return valueToString( LargestUInt(value) );
  58. }
  59. #endif // # if defined(JSON_HAS_INT64)
  60. std::string valueToString( double value )
  61. {
  62. char buffer[32];
  63. #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
  64. sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
  65. #else
  66. sprintf(buffer, "%#.16g", value);
  67. #endif
  68. char* ch = buffer + strlen(buffer) - 1;
  69. if (*ch != '0') return buffer; // nothing to truncate, so save time
  70. while(ch > buffer && *ch == '0'){
  71. --ch;
  72. }
  73. char* last_nonzero = ch;
  74. while(ch >= buffer){
  75. switch(*ch){
  76. case '0':
  77. case '1':
  78. case '2':
  79. case '3':
  80. case '4':
  81. case '5':
  82. case '6':
  83. case '7':
  84. case '8':
  85. case '9':
  86. --ch;
  87. continue;
  88. case '.':
  89. // Truncate zeroes to save bytes in output, but keep one.
  90. *(last_nonzero+2) = '\0';
  91. return buffer;
  92. default:
  93. return buffer;
  94. }
  95. }
  96. return buffer;
  97. }
  98. std::string valueToString( bool value )
  99. {
  100. return value ? "true" : "false";
  101. }
  102. std::string valueToQuotedString( const char *value )
  103. {
  104. // Not sure how to handle unicode...
  105. if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
  106. return std::string("\"") + value + "\"";
  107. // We have to walk value and escape any special characters.
  108. // Appending to std::string is not efficient, but this should be rare.
  109. // (Note: forward slashes are *not* rare, but I am not escaping them.)
  110. std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
  111. std::string result;
  112. result.reserve(maxsize); // to avoid lots of mallocs
  113. result += "\"";
  114. for (const char* c=value; *c != 0; ++c)
  115. {
  116. switch(*c)
  117. {
  118. case '\"':
  119. result += "\\\"";
  120. break;
  121. case '\\':
  122. result += "\\\\";
  123. break;
  124. case '\b':
  125. result += "\\b";
  126. break;
  127. case '\f':
  128. result += "\\f";
  129. break;
  130. case '\n':
  131. result += "\\n";
  132. break;
  133. case '\r':
  134. result += "\\r";
  135. break;
  136. case '\t':
  137. result += "\\t";
  138. break;
  139. //case '/':
  140. // Even though \/ is considered a legal escape in JSON, a bare
  141. // slash is also legal, so I see no reason to escape it.
  142. // (I hope I am not misunderstanding something.
  143. // blep notes: actually escaping \/ may be useful in javascript to avoid </
  144. // sequence.
  145. // Should add a flag to allow this compatibility mode and prevent this
  146. // sequence from occurring.
  147. default:
  148. if ( isControlCharacter( *c ) )
  149. {
  150. std::ostringstream oss;
  151. oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
  152. result += oss.str();
  153. }
  154. else
  155. {
  156. result += *c;
  157. }
  158. break;
  159. }
  160. }
  161. result += "\"";
  162. return result;
  163. }
  164. // Class Writer
  165. // //////////////////////////////////////////////////////////////////
  166. Writer::~Writer()
  167. {
  168. }
  169. // Class FastWriter
  170. // //////////////////////////////////////////////////////////////////
  171. FastWriter::FastWriter()
  172. : yamlCompatiblityEnabled_( false )
  173. {
  174. }
  175. void
  176. FastWriter::enableYAMLCompatibility()
  177. {
  178. yamlCompatiblityEnabled_ = true;
  179. }
  180. std::string
  181. FastWriter::write( const Value &root )
  182. {
  183. document_ = "";
  184. writeValue( root );
  185. document_ += "\n";
  186. return document_;
  187. }
  188. void
  189. FastWriter::writeValue( const Value &value )
  190. {
  191. switch ( value.type() )
  192. {
  193. case nullValue:
  194. document_ += "null";
  195. break;
  196. case intValue:
  197. document_ += valueToString( value.asLargestInt() );
  198. break;
  199. case uintValue:
  200. document_ += valueToString( value.asLargestUInt() );
  201. break;
  202. case realValue:
  203. document_ += valueToString( value.asDouble() );
  204. break;
  205. case stringValue:
  206. document_ += valueToQuotedString( value.asCString() );
  207. break;
  208. case booleanValue:
  209. document_ += valueToString( value.asBool() );
  210. break;
  211. case arrayValue:
  212. {
  213. document_ += "[";
  214. int size = value.size();
  215. for ( int index =0; index < size; ++index )
  216. {
  217. if ( index > 0 )
  218. document_ += ",";
  219. writeValue( value[index] );
  220. }
  221. document_ += "]";
  222. }
  223. break;
  224. case objectValue:
  225. {
  226. Value::Members members( value.getMemberNames() );
  227. document_ += "{";
  228. for ( Value::Members::iterator it = members.begin();
  229. it != members.end();
  230. ++it )
  231. {
  232. const std::string &name = *it;
  233. if ( it != members.begin() )
  234. document_ += ",";
  235. document_ += valueToQuotedString( name.c_str() );
  236. document_ += yamlCompatiblityEnabled_ ? ": "
  237. : ":";
  238. writeValue( value[name] );
  239. }
  240. document_ += "}";
  241. }
  242. break;
  243. }
  244. }
  245. // Class StyledWriter
  246. // //////////////////////////////////////////////////////////////////
  247. StyledWriter::StyledWriter()
  248. : rightMargin_( 74 )
  249. , indentSize_( 3 )
  250. {
  251. }
  252. std::string
  253. StyledWriter::write( const Value &root )
  254. {
  255. document_ = "";
  256. addChildValues_ = false;
  257. indentString_ = "";
  258. writeCommentBeforeValue( root );
  259. writeValue( root );
  260. writeCommentAfterValueOnSameLine( root );
  261. document_ += "\n";
  262. return document_;
  263. }
  264. void
  265. StyledWriter::writeValue( const Value &value )
  266. {
  267. switch ( value.type() )
  268. {
  269. case nullValue:
  270. pushValue( "null" );
  271. break;
  272. case intValue:
  273. pushValue( valueToString( value.asLargestInt() ) );
  274. break;
  275. case uintValue:
  276. pushValue( valueToString( value.asLargestUInt() ) );
  277. break;
  278. case realValue:
  279. pushValue( valueToString( value.asDouble() ) );
  280. break;
  281. case stringValue:
  282. pushValue( valueToQuotedString( value.asCString() ) );
  283. break;
  284. case booleanValue:
  285. pushValue( valueToString( value.asBool() ) );
  286. break;
  287. case arrayValue:
  288. writeArrayValue( value);
  289. break;
  290. case objectValue:
  291. {
  292. Value::Members members( value.getMemberNames() );
  293. if ( members.empty() )
  294. pushValue( "{}" );
  295. else
  296. {
  297. writeWithIndent( "{" );
  298. indent();
  299. Value::Members::iterator it = members.begin();
  300. for (;;)
  301. {
  302. const std::string &name = *it;
  303. const Value &childValue = value[name];
  304. writeCommentBeforeValue( childValue );
  305. writeWithIndent( valueToQuotedString( name.c_str() ) );
  306. document_ += " : ";
  307. writeValue( childValue );
  308. if ( ++it == members.end() )
  309. {
  310. writeCommentAfterValueOnSameLine( childValue );
  311. break;
  312. }
  313. document_ += ",";
  314. writeCommentAfterValueOnSameLine( childValue );
  315. }
  316. unindent();
  317. writeWithIndent( "}" );
  318. }
  319. }
  320. break;
  321. }
  322. }
  323. void
  324. StyledWriter::writeArrayValue( const Value &value )
  325. {
  326. unsigned size = value.size();
  327. if ( size == 0 )
  328. pushValue( "[]" );
  329. else
  330. {
  331. bool isArrayMultiLine = isMultineArray( value );
  332. if ( isArrayMultiLine )
  333. {
  334. writeWithIndent( "[" );
  335. indent();
  336. bool hasChildValue = !childValues_.empty();
  337. unsigned index =0;
  338. for (;;)
  339. {
  340. const Value &childValue = value[index];
  341. writeCommentBeforeValue( childValue );
  342. if ( hasChildValue )
  343. writeWithIndent( childValues_[index] );
  344. else
  345. {
  346. writeIndent();
  347. writeValue( childValue );
  348. }
  349. if ( ++index == size )
  350. {
  351. writeCommentAfterValueOnSameLine( childValue );
  352. break;
  353. }
  354. document_ += ",";
  355. writeCommentAfterValueOnSameLine( childValue );
  356. }
  357. unindent();
  358. writeWithIndent( "]" );
  359. }
  360. else // output on a single line
  361. {
  362. assert( childValues_.size() == size );
  363. document_ += "[ ";
  364. for ( unsigned index =0; index < size; ++index )
  365. {
  366. if ( index > 0 )
  367. document_ += ", ";
  368. document_ += childValues_[index];
  369. }
  370. document_ += " ]";
  371. }
  372. }
  373. }
  374. bool
  375. StyledWriter::isMultineArray( const Value &value )
  376. {
  377. int size = value.size();
  378. bool isMultiLine = size*3 >= rightMargin_ ;
  379. childValues_.clear();
  380. for ( int index =0; index < size && !isMultiLine; ++index )
  381. {
  382. const Value &childValue = value[index];
  383. isMultiLine = isMultiLine ||
  384. ( (childValue.isArray() || childValue.isObject()) &&
  385. childValue.size() > 0 );
  386. }
  387. if ( !isMultiLine ) // check if line length > max line length
  388. {
  389. childValues_.reserve( size );
  390. addChildValues_ = true;
  391. int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
  392. for ( int index =0; index < size && !isMultiLine; ++index )
  393. {
  394. writeValue( value[index] );
  395. lineLength += int( childValues_[index].length() );
  396. isMultiLine = isMultiLine && hasCommentForValue( value[index] );
  397. }
  398. addChildValues_ = false;
  399. isMultiLine = isMultiLine || lineLength >= rightMargin_;
  400. }
  401. return isMultiLine;
  402. }
  403. void
  404. StyledWriter::pushValue( const std::string &value )
  405. {
  406. if ( addChildValues_ )
  407. childValues_.push_back( value );
  408. else
  409. document_ += value;
  410. }
  411. void
  412. StyledWriter::writeIndent()
  413. {
  414. if ( !document_.empty() )
  415. {
  416. char last = document_[document_.length()-1];
  417. if ( last == ' ' ) // already indented
  418. return;
  419. if ( last != '\n' ) // Comments may add new-line
  420. document_ += '\n';
  421. }
  422. document_ += indentString_;
  423. }
  424. void
  425. StyledWriter::writeWithIndent( const std::string &value )
  426. {
  427. writeIndent();
  428. document_ += value;
  429. }
  430. void
  431. StyledWriter::indent()
  432. {
  433. indentString_ += std::string( indentSize_, ' ' );
  434. }
  435. void
  436. StyledWriter::unindent()
  437. {
  438. assert( int(indentString_.size()) >= indentSize_ );
  439. indentString_.resize( indentString_.size() - indentSize_ );
  440. }
  441. void
  442. StyledWriter::writeCommentBeforeValue( const Value &root )
  443. {
  444. if ( !root.hasComment( commentBefore ) )
  445. return;
  446. document_ += normalizeEOL( root.getComment( commentBefore ) );
  447. document_ += "\n";
  448. }
  449. void
  450. StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
  451. {
  452. if ( root.hasComment( commentAfterOnSameLine ) )
  453. document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
  454. if ( root.hasComment( commentAfter ) )
  455. {
  456. document_ += "\n";
  457. document_ += normalizeEOL( root.getComment( commentAfter ) );
  458. document_ += "\n";
  459. }
  460. }
  461. bool
  462. StyledWriter::hasCommentForValue( const Value &value )
  463. {
  464. return value.hasComment( commentBefore )
  465. || value.hasComment( commentAfterOnSameLine )
  466. || value.hasComment( commentAfter );
  467. }
  468. std::string
  469. StyledWriter::normalizeEOL( const std::string &text )
  470. {
  471. std::string normalized;
  472. normalized.reserve( text.length() );
  473. const char *begin = text.c_str();
  474. const char *end = begin + text.length();
  475. const char *current = begin;
  476. while ( current != end )
  477. {
  478. char c = *current++;
  479. if ( c == '\r' ) // mac or dos EOL
  480. {
  481. if ( *current == '\n' ) // convert dos EOL
  482. ++current;
  483. normalized += '\n';
  484. }
  485. else // handle unix EOL & other char
  486. normalized += c;
  487. }
  488. return normalized;
  489. }
  490. // Class StyledStreamWriter
  491. // //////////////////////////////////////////////////////////////////
  492. StyledStreamWriter::StyledStreamWriter( std::string indentation )
  493. : document_(NULL)
  494. , rightMargin_( 74 )
  495. , indentation_( indentation )
  496. {
  497. }
  498. void
  499. StyledStreamWriter::write( std::ostream &out, const Value &root )
  500. {
  501. document_ = &out;
  502. addChildValues_ = false;
  503. indentString_ = "";
  504. writeCommentBeforeValue( root );
  505. writeValue( root );
  506. writeCommentAfterValueOnSameLine( root );
  507. *document_ << "\n";
  508. document_ = NULL; // Forget the stream, for safety.
  509. }
  510. void
  511. StyledStreamWriter::writeValue( const Value &value )
  512. {
  513. switch ( value.type() )
  514. {
  515. case nullValue:
  516. pushValue( "null" );
  517. break;
  518. case intValue:
  519. pushValue( valueToString( value.asLargestInt() ) );
  520. break;
  521. case uintValue:
  522. pushValue( valueToString( value.asLargestUInt() ) );
  523. break;
  524. case realValue:
  525. pushValue( valueToString( value.asDouble() ) );
  526. break;
  527. case stringValue:
  528. pushValue( valueToQuotedString( value.asCString() ) );
  529. break;
  530. case booleanValue:
  531. pushValue( valueToString( value.asBool() ) );
  532. break;
  533. case arrayValue:
  534. writeArrayValue( value);
  535. break;
  536. case objectValue:
  537. {
  538. Value::Members members( value.getMemberNames() );
  539. if ( members.empty() )
  540. pushValue( "{}" );
  541. else
  542. {
  543. writeWithIndent( "{" );
  544. indent();
  545. Value::Members::iterator it = members.begin();
  546. for (;;)
  547. {
  548. const std::string &name = *it;
  549. const Value &childValue = value[name];
  550. writeCommentBeforeValue( childValue );
  551. writeWithIndent( valueToQuotedString( name.c_str() ) );
  552. *document_ << " : ";
  553. writeValue( childValue );
  554. if ( ++it == members.end() )
  555. {
  556. writeCommentAfterValueOnSameLine( childValue );
  557. break;
  558. }
  559. *document_ << ",";
  560. writeCommentAfterValueOnSameLine( childValue );
  561. }
  562. unindent();
  563. writeWithIndent( "}" );
  564. }
  565. }
  566. break;
  567. }
  568. }
  569. void
  570. StyledStreamWriter::writeArrayValue( const Value &value )
  571. {
  572. unsigned size = value.size();
  573. if ( size == 0 )
  574. pushValue( "[]" );
  575. else
  576. {
  577. bool isArrayMultiLine = isMultineArray( value );
  578. if ( isArrayMultiLine )
  579. {
  580. writeWithIndent( "[" );
  581. indent();
  582. bool hasChildValue = !childValues_.empty();
  583. unsigned index =0;
  584. for (;;)
  585. {
  586. const Value &childValue = value[index];
  587. writeCommentBeforeValue( childValue );
  588. if ( hasChildValue )
  589. writeWithIndent( childValues_[index] );
  590. else
  591. {
  592. writeIndent();
  593. writeValue( childValue );
  594. }
  595. if ( ++index == size )
  596. {
  597. writeCommentAfterValueOnSameLine( childValue );
  598. break;
  599. }
  600. *document_ << ",";
  601. writeCommentAfterValueOnSameLine( childValue );
  602. }
  603. unindent();
  604. writeWithIndent( "]" );
  605. }
  606. else // output on a single line
  607. {
  608. assert( childValues_.size() == size );
  609. *document_ << "[ ";
  610. for ( unsigned index =0; index < size; ++index )
  611. {
  612. if ( index > 0 )
  613. *document_ << ", ";
  614. *document_ << childValues_[index];
  615. }
  616. *document_ << " ]";
  617. }
  618. }
  619. }
  620. bool
  621. StyledStreamWriter::isMultineArray( const Value &value )
  622. {
  623. int size = value.size();
  624. bool isMultiLine = size*3 >= rightMargin_ ;
  625. childValues_.clear();
  626. for ( int index =0; index < size && !isMultiLine; ++index )
  627. {
  628. const Value &childValue = value[index];
  629. isMultiLine = isMultiLine ||
  630. ( (childValue.isArray() || childValue.isObject()) &&
  631. childValue.size() > 0 );
  632. }
  633. if ( !isMultiLine ) // check if line length > max line length
  634. {
  635. childValues_.reserve( size );
  636. addChildValues_ = true;
  637. int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
  638. for ( int index =0; index < size && !isMultiLine; ++index )
  639. {
  640. writeValue( value[index] );
  641. lineLength += int( childValues_[index].length() );
  642. isMultiLine = isMultiLine && hasCommentForValue( value[index] );
  643. }
  644. addChildValues_ = false;
  645. isMultiLine = isMultiLine || lineLength >= rightMargin_;
  646. }
  647. return isMultiLine;
  648. }
  649. void
  650. StyledStreamWriter::pushValue( const std::string &value )
  651. {
  652. if ( addChildValues_ )
  653. childValues_.push_back( value );
  654. else
  655. *document_ << value;
  656. }
  657. void
  658. StyledStreamWriter::writeIndent()
  659. {
  660. /*
  661. Some comments in this method would have been nice. ;-)
  662. if ( !document_.empty() )
  663. {
  664. char last = document_[document_.length()-1];
  665. if ( last == ' ' ) // already indented
  666. return;
  667. if ( last != '\n' ) // Comments may add new-line
  668. *document_ << '\n';
  669. }
  670. */
  671. *document_ << '\n' << indentString_;
  672. }
  673. void
  674. StyledStreamWriter::writeWithIndent( const std::string &value )
  675. {
  676. writeIndent();
  677. *document_ << value;
  678. }
  679. void
  680. StyledStreamWriter::indent()
  681. {
  682. indentString_ += indentation_;
  683. }
  684. void
  685. StyledStreamWriter::unindent()
  686. {
  687. assert( indentString_.size() >= indentation_.size() );
  688. indentString_.resize( indentString_.size() - indentation_.size() );
  689. }
  690. void
  691. StyledStreamWriter::writeCommentBeforeValue( const Value &root )
  692. {
  693. if ( !root.hasComment( commentBefore ) )
  694. return;
  695. *document_ << normalizeEOL( root.getComment( commentBefore ) );
  696. *document_ << "\n";
  697. }
  698. void
  699. StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
  700. {
  701. if ( root.hasComment( commentAfterOnSameLine ) )
  702. *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
  703. if ( root.hasComment( commentAfter ) )
  704. {
  705. *document_ << "\n";
  706. *document_ << normalizeEOL( root.getComment( commentAfter ) );
  707. *document_ << "\n";
  708. }
  709. }
  710. bool
  711. StyledStreamWriter::hasCommentForValue( const Value &value )
  712. {
  713. return value.hasComment( commentBefore )
  714. || value.hasComment( commentAfterOnSameLine )
  715. || value.hasComment( commentAfter );
  716. }
  717. std::string
  718. StyledStreamWriter::normalizeEOL( const std::string &text )
  719. {
  720. std::string normalized;
  721. normalized.reserve( text.length() );
  722. const char *begin = text.c_str();
  723. const char *end = begin + text.length();
  724. const char *current = begin;
  725. while ( current != end )
  726. {
  727. char c = *current++;
  728. if ( c == '\r' ) // mac or dos EOL
  729. {
  730. if ( *current == '\n' ) // convert dos EOL
  731. ++current;
  732. normalized += '\n';
  733. }
  734. else // handle unix EOL & other char
  735. normalized += c;
  736. }
  737. return normalized;
  738. }
  739. std::ostream& operator<<( std::ostream &sout, const Value &root )
  740. {
  741. Json::StyledStreamWriter writer;
  742. writer.write(sout, root);
  743. return sout;
  744. }
  745. } // namespace Json