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