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