json_writer.cpp 20 KB

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