rippled
Loading...
Searching...
No Matches
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 <xrpl/beast/utility/instrumentation.h>
21#include <xrpl/json/json_writer.h>
22#include <iomanip>
23#include <sstream>
24#include <string>
25#include <utility>
26
27namespace Json {
28
29static bool
31{
32 return ch > 0 && ch <= 0x1F;
33}
34
35static bool
37{
38 while (*str)
39 {
40 if (isControlCharacter(*(str++)))
41 return true;
42 }
43
44 return false;
45}
46static void
47uintToString(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 XRPL_ASSERT(current >= buffer, "Json::valueToString(Int) : buffer check");
74 return current;
75}
76
79{
80 char buffer[32];
81 char* current = buffer + sizeof(buffer);
82 uintToString(value, current);
83 XRPL_ASSERT(current >= buffer, "Json::valueToString(UInt) : buffer check");
84 return current;
85}
86
88valueToString(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
107valueToString(bool value)
108{
109 return value ? "true" : "false";
110}
111
113valueToQuotedString(const char* value)
114{
115 // Not sure how to handle unicode...
116 if (strpbrk(value, "\"\\\b\f\n\r\t") == nullptr &&
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 {
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
200void
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
272StyledWriter::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
287void
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:
302 break;
303
304 case realValue:
306 break;
307
308 case stringValue:
310 break;
311
312 case booleanValue:
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
353void
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 XRPL_ASSERT(
395 childValues_.size() == size,
396 "Json::StyledWriter::writeArrayValue : child size match");
397 document_ += "[ ";
398
399 for (unsigned index = 0; index < size; ++index)
400 {
401 if (index > 0)
402 document_ += ", ";
403
404 document_ += childValues_[index];
405 }
406
407 document_ += " ]";
408 }
409 }
410}
411
412bool
414{
415 int size = value.size();
416 bool isMultiLine = size * 3 >= rightMargin_;
418
419 for (int index = 0; index < size && !isMultiLine; ++index)
420 {
421 const Value& childValue = value[index];
422 isMultiLine = isMultiLine ||
423 ((childValue.isArray() || childValue.isObject()) &&
424 childValue.size() > 0);
425 }
426
427 if (!isMultiLine) // check if line length > max line length
428 {
429 childValues_.reserve(size);
430 addChildValues_ = true;
431 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
432
433 for (int index = 0; index < size; ++index)
434 {
435 writeValue(value[index]);
436 lineLength += int(childValues_[index].length());
437 }
438
439 addChildValues_ = false;
440 isMultiLine = isMultiLine || lineLength >= rightMargin_;
441 }
442
443 return isMultiLine;
444}
445
446void
448{
449 if (addChildValues_)
450 childValues_.push_back(value);
451 else
452 document_ += value;
453}
454
455void
457{
458 if (!document_.empty())
459 {
460 char last = document_[document_.length() - 1];
461
462 if (last == ' ') // already indented
463 return;
464
465 if (last != '\n') // Comments may add new-line
466 document_ += '\n';
467 }
468
470}
471
472void
474{
475 writeIndent();
476 document_ += value;
477}
478
479void
481{
483}
484
485void
487{
488 XRPL_ASSERT(
490 "Json::StyledWriter::unindent : maximum indent size");
492}
493
494// Class StyledStreamWriter
495// //////////////////////////////////////////////////////////////////
496
498 : document_(nullptr), rightMargin_(74), indentation_(indentation)
499{
500}
501
502void
504{
505 document_ = &out;
506 addChildValues_ = false;
507 indentString_ = "";
508 writeValue(root);
509 *document_ << "\n";
510 document_ = nullptr; // Forget the stream, for safety.
511}
512
513void
515{
516 switch (value.type())
517 {
518 case nullValue:
519 pushValue("null");
520 break;
521
522 case intValue:
523 pushValue(valueToString(value.asInt()));
524 break;
525
526 case uintValue:
528 break;
529
530 case realValue:
532 break;
533
534 case stringValue:
536 break;
537
538 case booleanValue:
540 break;
541
542 case arrayValue:
543 writeArrayValue(value);
544 break;
545
546 case objectValue: {
547 Value::Members members(value.getMemberNames());
548
549 if (members.empty())
550 pushValue("{}");
551 else
552 {
553 writeWithIndent("{");
554 indent();
555 Value::Members::iterator it = members.begin();
556
557 while (true)
558 {
559 std::string const& name = *it;
560 const Value& childValue = value[name];
562 *document_ << " : ";
563 writeValue(childValue);
564
565 if (++it == members.end())
566 break;
567
568 *document_ << ",";
569 }
570
571 unindent();
572 writeWithIndent("}");
573 }
574 }
575 break;
576 }
577}
578
579void
581{
582 unsigned size = value.size();
583
584 if (size == 0)
585 pushValue("[]");
586 else
587 {
588 bool isArrayMultiLine = isMultineArray(value);
589
590 if (isArrayMultiLine)
591 {
592 writeWithIndent("[");
593 indent();
594 bool hasChildValue = !childValues_.empty();
595 unsigned index = 0;
596
597 while (true)
598 {
599 const Value& childValue = value[index];
600
601 if (hasChildValue)
603 else
604 {
605 writeIndent();
606 writeValue(childValue);
607 }
608
609 if (++index == size)
610 break;
611
612 *document_ << ",";
613 }
614
615 unindent();
616 writeWithIndent("]");
617 }
618 else // output on a single line
619 {
620 XRPL_ASSERT(
621 childValues_.size() == size,
622 "Json::StyledStreamWriter::writeArrayValue : child size match");
623 *document_ << "[ ";
624
625 for (unsigned index = 0; index < size; ++index)
626 {
627 if (index > 0)
628 *document_ << ", ";
629
630 *document_ << childValues_[index];
631 }
632
633 *document_ << " ]";
634 }
635 }
636}
637
638bool
640{
641 int size = value.size();
642 bool isMultiLine = size * 3 >= rightMargin_;
644
645 for (int index = 0; index < size && !isMultiLine; ++index)
646 {
647 const Value& childValue = value[index];
648 isMultiLine = isMultiLine ||
649 ((childValue.isArray() || childValue.isObject()) &&
650 childValue.size() > 0);
651 }
652
653 if (!isMultiLine) // check if line length > max line length
654 {
655 childValues_.reserve(size);
656 addChildValues_ = true;
657 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
658
659 for (int index = 0; index < size; ++index)
660 {
661 writeValue(value[index]);
662 lineLength += int(childValues_[index].length());
663 }
664
665 addChildValues_ = false;
666 isMultiLine = isMultiLine || lineLength >= rightMargin_;
667 }
668
669 return isMultiLine;
670}
671
672void
674{
675 if (addChildValues_)
676 childValues_.push_back(value);
677 else
678 *document_ << value;
679}
680
681void
683{
684 /*
685 Some comments in this method would have been nice. ;-)
686
687 if ( !document_.empty() )
688 {
689 char last = document_[document_.length()-1];
690 if ( last == ' ' ) // already indented
691 return;
692 if ( last != '\n' ) // Comments may add new-line
693 *document_ << '\n';
694 }
695 */
696 *document_ << '\n' << indentString_;
697}
698
699void
701{
702 writeIndent();
703 *document_ << value;
704}
705
706void
708{
710}
711
712void
714{
715 XRPL_ASSERT(
717 "Json::StyledStreamWriter::unindent : maximum indent size");
719}
720
722operator<<(std::ostream& sout, const Value& root)
723{
725 writer.write(sout, root);
726 return sout;
727}
728
729} // namespace Json
T begin(T... args)
T c_str(T... args)
void writeValue(const Value &value)
std::string write(const Value &root) override
std::string document_
Definition: json_writer.h:68
Writes a Value in JSON format in a human friendly way, to a stream rather than to a string.
Definition: json_writer.h:155
void write(std::ostream &out, const Value &root)
Serialize a Value in JSON format.
void writeValue(const Value &value)
void writeWithIndent(std::string const &value)
void writeArrayValue(const Value &value)
bool isMultineArray(const Value &value)
std::ostream * document_
Definition: json_writer.h:193
StyledStreamWriter(std::string indentation="\t")
void pushValue(std::string const &value)
void writeArrayValue(const Value &value)
ChildValues childValues_
Definition: json_writer.h:125
std::string indentString_
Definition: json_writer.h:127
void pushValue(std::string const &value)
bool isMultineArray(const Value &value)
std::string write(const Value &root) override
Serialize a Value in JSON format.
std::string document_
Definition: json_writer.h:126
void writeValue(const Value &value)
void writeWithIndent(std::string const &value)
Represents a JSON value.
Definition: json_value.h:147
bool isArray() const
const char * asCString() const
Definition: json_value.cpp:462
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
Int asInt() const
Definition: json_value.cpp:503
UInt asUInt() const
Definition: json_value.cpp:545
Members getMemberNames() const
Return a list of the member names.
Definition: json_value.cpp:959
ValueType type() const
Definition: json_value.cpp:350
bool isObject() const
bool asBool() const
Definition: json_value.cpp:619
double asDouble() const
Definition: json_value.cpp:587
T clear(T... args)
T empty(T... args)
T end(T... args)
T hex(T... args)
JSON (JavaScript Object Notation).
Definition: json_errors.h:25
static bool isControlCharacter(char ch)
Definition: json_writer.cpp:30
static void uintToString(unsigned int value, char *&current)
Definition: json_writer.cpp:47
std::string valueToString(Int value)
Definition: json_writer.cpp:59
@ booleanValue
bool value
Definition: json_value.h:41
@ nullValue
'null' value
Definition: json_value.h:36
@ stringValue
UTF-8 string value.
Definition: json_value.h:40
@ realValue
double value
Definition: json_value.h:39
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
@ intValue
signed integer value
Definition: json_value.h:37
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
@ uintValue
unsigned integer value
Definition: json_value.h:38
std::ostream & operator<<(std::ostream &, const Value &root)
Output using the StyledStreamWriter.
int Int
Definition: json_forwards.h:26
std::string valueToQuotedString(const char *value)
static bool containsControlCharacter(const char *str)
Definition: json_writer.cpp:36
unsigned int UInt
Definition: json_forwards.h:27
T push_back(T... args)
T reserve(T... args)
T resize(T... args)
T setfill(T... args)
T setw(T... args)
T size(T... args)
T str(T... args)
T uppercase(T... args)