fix flaky ConnectTFOTimeout and ConnectTFOFallbackTimeout tests
[folly.git] / folly / json.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/json.h>
18 #include <cassert>
19 #include <boost/next_prior.hpp>
20 #include <boost/algorithm/string.hpp>
21
22 #include <folly/Conv.h>
23 #include <folly/Portability.h>
24 #include <folly/Range.h>
25 #include <folly/String.h>
26 #include <folly/Unicode.h>
27 #include <folly/portability/Constexpr.h>
28
29 namespace folly {
30
31 //////////////////////////////////////////////////////////////////////
32
33 namespace json {
34 namespace {
35
36 char32_t decodeUtf8(
37     const unsigned char*& p,
38     const unsigned char* const e,
39     bool skipOnError) {
40   /* The following encodings are valid, except for the 5 and 6 byte
41    * combinations:
42    * 0xxxxxxx
43    * 110xxxxx 10xxxxxx
44    * 1110xxxx 10xxxxxx 10xxxxxx
45    * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
46    * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
47    * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
48    */
49
50   auto skip = [&] { ++p; return U'\ufffd'; };
51
52   if (p >= e) {
53     if (skipOnError) return skip();
54     throw std::runtime_error("folly::decodeUtf8 empty/invalid string");
55   }
56
57   unsigned char fst = *p;
58   if (!(fst & 0x80)) {
59     // trivial case
60     return *p++;
61   }
62
63   static const uint32_t bitMask[] = {
64     (1 << 7) - 1,
65     (1 << 11) - 1,
66     (1 << 16) - 1,
67     (1 << 21) - 1
68   };
69
70   // upper control bits are masked out later
71   uint32_t d = fst;
72
73   if ((fst & 0xC0) != 0xC0) {
74     if (skipOnError) return skip();
75     throw std::runtime_error(to<std::string>("folly::decodeUtf8 i=0 d=", d));
76   }
77
78   fst <<= 1;
79
80   for (unsigned int i = 1; i != 3 && p + i < e; ++i) {
81     unsigned char tmp = p[i];
82
83     if ((tmp & 0xC0) != 0x80) {
84       if (skipOnError) return skip();
85       throw std::runtime_error(
86         to<std::string>("folly::decodeUtf8 i=", i, " tmp=", (uint32_t)tmp));
87     }
88
89     d = (d << 6) | (tmp & 0x3F);
90     fst <<= 1;
91
92     if (!(fst & 0x80)) {
93       d &= bitMask[i];
94
95       // overlong, could have been encoded with i bytes
96       if ((d & ~bitMask[i - 1]) == 0) {
97         if (skipOnError) return skip();
98         throw std::runtime_error(
99           to<std::string>("folly::decodeUtf8 i=", i, " d=", d));
100       }
101
102       // check for surrogates only needed for 3 bytes
103       if (i == 2) {
104         if ((d >= 0xD800 && d <= 0xDFFF) || d > 0x10FFFF) {
105           if (skipOnError) return skip();
106           throw std::runtime_error(
107             to<std::string>("folly::decodeUtf8 i=", i, " d=", d));
108         }
109       }
110
111       p += i + 1;
112       return d;
113     }
114   }
115
116   if (skipOnError) return skip();
117   throw std::runtime_error("folly::decodeUtf8 encoding length maxed out");
118 }
119
120 struct Printer {
121   explicit Printer(
122       std::string& out,
123       unsigned* indentLevel,
124       serialization_opts const* opts)
125       : out_(out), indentLevel_(indentLevel), opts_(*opts) {}
126
127   void operator()(dynamic const& v) const {
128     switch (v.type()) {
129     case dynamic::DOUBLE:
130       if (!opts_.allow_nan_inf &&
131           (std::isnan(v.asDouble()) || std::isinf(v.asDouble()))) {
132         throw std::runtime_error("folly::toJson: JSON object value was a "
133           "NaN or INF");
134       }
135       toAppend(v.asDouble(), &out_, opts_.double_mode, opts_.double_num_digits);
136       break;
137     case dynamic::INT64: {
138       auto intval = v.asInt();
139       if (opts_.javascript_safe) {
140         // Use folly::to to check that this integer can be represented
141         // as a double without loss of precision.
142         intval = int64_t(to<double>(intval));
143       }
144       toAppend(intval, &out_);
145       break;
146     }
147     case dynamic::BOOL:
148       out_ += v.asBool() ? "true" : "false";
149       break;
150     case dynamic::NULLT:
151       out_ += "null";
152       break;
153     case dynamic::STRING:
154       escapeString(v.asString(), out_, opts_);
155       break;
156     case dynamic::OBJECT:
157       printObject(v);
158       break;
159     case dynamic::ARRAY:
160       printArray(v);
161       break;
162     default:
163       CHECK(0) << "Bad type " << v.type();
164     }
165   }
166
167 private:
168   void printKV(const std::pair<const dynamic, dynamic>& p) const {
169     if (!opts_.allow_non_string_keys && !p.first.isString()) {
170       throw std::runtime_error("folly::toJson: JSON object key was not a "
171         "string");
172     }
173     (*this)(p.first);
174     mapColon();
175     (*this)(p.second);
176   }
177
178   template <typename Iterator>
179   void printKVPairs(Iterator begin, Iterator end) const {
180     printKV(*begin);
181     for (++begin; begin != end; ++begin) {
182       out_ += ',';
183       newline();
184       printKV(*begin);
185     }
186   }
187
188   void printObject(dynamic const& o) const {
189     if (o.empty()) {
190       out_ += "{}";
191       return;
192     }
193
194     out_ += '{';
195     indent();
196     newline();
197     if (opts_.sort_keys) {
198       std::vector<std::pair<dynamic, dynamic>> items(
199         o.items().begin(), o.items().end());
200       std::sort(items.begin(), items.end());
201       printKVPairs(items.begin(), items.end());
202     } else {
203       printKVPairs(o.items().begin(), o.items().end());
204     }
205     outdent();
206     newline();
207     out_ += '}';
208   }
209
210   void printArray(dynamic const& a) const {
211     if (a.empty()) {
212       out_ += "[]";
213       return;
214     }
215
216     out_ += '[';
217     indent();
218     newline();
219     (*this)(a[0]);
220     for (auto& val : range(boost::next(a.begin()), a.end())) {
221       out_ += ',';
222       newline();
223       (*this)(val);
224     }
225     outdent();
226     newline();
227     out_ += ']';
228   }
229
230 private:
231   void outdent() const {
232     if (indentLevel_) {
233       --*indentLevel_;
234     }
235   }
236
237   void indent() const {
238     if (indentLevel_) {
239       ++*indentLevel_;
240     }
241   }
242
243   void newline() const {
244     if (indentLevel_) {
245       out_ += to<std::string>('\n', std::string(*indentLevel_ * 2, ' '));
246     }
247   }
248
249   void mapColon() const {
250     out_ += indentLevel_ ? " : " : ":";
251   }
252
253 private:
254  std::string& out_;
255  unsigned* const indentLevel_;
256  serialization_opts const& opts_;
257 };
258
259   //////////////////////////////////////////////////////////////////////
260
261   struct ParseError : std::runtime_error {
262     explicit ParseError(int line)
263       : std::runtime_error(to<std::string>("json parse error on line ", line))
264     {}
265
266     explicit ParseError(int line, std::string const& context,
267         std::string const& expected)
268       : std::runtime_error(to<std::string>("json parse error on line ", line,
269           !context.empty() ? to<std::string>(" near `", context, '\'')
270                           : "",
271           ": ", expected))
272     {}
273
274     explicit ParseError(std::string const& msg)
275       : std::runtime_error("json parse error: " + msg)
276     {}
277   };
278
279 // Wraps our input buffer with some helper functions.
280 struct Input {
281   explicit Input(StringPiece range, json::serialization_opts const* opts)
282       : range_(range)
283       , opts_(*opts)
284       , lineNum_(0)
285   {
286     storeCurrent();
287   }
288
289   Input(Input const&) = delete;
290   Input& operator=(Input const&) = delete;
291
292   char const* begin() const { return range_.begin(); }
293
294   // Parse ahead for as long as the supplied predicate is satisfied,
295   // returning a range of what was skipped.
296   template<class Predicate>
297   StringPiece skipWhile(const Predicate& p) {
298     std::size_t skipped = 0;
299     for (; skipped < range_.size(); ++skipped) {
300       if (!p(range_[skipped])) {
301         break;
302       }
303       if (range_[skipped] == '\n') {
304         ++lineNum_;
305       }
306     }
307     auto ret = range_.subpiece(0, skipped);
308     range_.advance(skipped);
309     storeCurrent();
310     return ret;
311   }
312
313   StringPiece skipDigits() {
314     return skipWhile([] (char c) { return c >= '0' && c <= '9'; });
315   }
316
317   StringPiece skipMinusAndDigits() {
318     bool firstChar = true;
319     return skipWhile([&firstChar] (char c) {
320         bool result = (c >= '0' && c <= '9') || (firstChar && c == '-');
321         firstChar = false;
322         return result;
323       });
324   }
325
326   void skipWhitespace() {
327     range_ = folly::skipWhitespace(range_);
328     storeCurrent();
329   }
330
331   void expect(char c) {
332     if (**this != c) {
333       throw ParseError(lineNum_, context(),
334         to<std::string>("expected '", c, '\''));
335     }
336     ++*this;
337   }
338
339   std::size_t size() const {
340     return range_.size();
341   }
342
343   int operator*() const {
344     return current_;
345   }
346
347   void operator++() {
348     range_.pop_front();
349     storeCurrent();
350   }
351
352   template<class T>
353   T extract() {
354     try {
355       return to<T>(&range_);
356     } catch (std::exception const& e) {
357       error(e.what());
358     }
359   }
360
361   bool consume(StringPiece str) {
362     if (boost::starts_with(range_, str)) {
363       range_.advance(str.size());
364       storeCurrent();
365       return true;
366     }
367     return false;
368   }
369
370   std::string context() const {
371     return range_.subpiece(0, 16 /* arbitrary */).toString();
372   }
373
374   dynamic error(char const* what) const {
375     throw ParseError(lineNum_, context(), what);
376   }
377
378   json::serialization_opts const& getOpts() {
379     return opts_;
380   }
381
382   void incrementRecursionLevel() {
383     if (currentRecursionLevel_ > opts_.recursion_limit) {
384       error("recursion limit exceeded");
385     }
386     currentRecursionLevel_++;
387   }
388
389   void decrementRecursionLevel() {
390     currentRecursionLevel_--;
391   }
392
393  private:
394   void storeCurrent() {
395     current_ = range_.empty() ? EOF : range_.front();
396   }
397
398 private:
399   StringPiece range_;
400   json::serialization_opts const& opts_;
401   unsigned lineNum_;
402   int current_;
403   unsigned int currentRecursionLevel_{0};
404 };
405
406 class RecursionGuard {
407  public:
408   explicit RecursionGuard(Input& in) : in_(in) {
409     in_.incrementRecursionLevel();
410   }
411
412   ~RecursionGuard() {
413     in_.decrementRecursionLevel();
414   }
415
416  private:
417   Input& in_;
418 };
419
420 dynamic parseValue(Input& in);
421 std::string parseString(Input& in);
422 dynamic parseNumber(Input& in);
423
424 dynamic parseObject(Input& in) {
425   assert(*in == '{');
426   ++in;
427
428   dynamic ret = dynamic::object;
429
430   in.skipWhitespace();
431   if (*in == '}') {
432     ++in;
433     return ret;
434   }
435
436   for (;;) {
437     if (in.getOpts().allow_trailing_comma && *in == '}') {
438       break;
439     }
440     if (*in == '\"') { // string
441       auto key = parseString(in);
442       in.skipWhitespace();
443       in.expect(':');
444       in.skipWhitespace();
445       ret.insert(std::move(key), parseValue(in));
446     } else if (!in.getOpts().allow_non_string_keys) {
447       in.error("expected string for object key name");
448     } else {
449       auto key = parseValue(in);
450       in.skipWhitespace();
451       in.expect(':');
452       in.skipWhitespace();
453       ret.insert(std::move(key), parseValue(in));
454     }
455
456     in.skipWhitespace();
457     if (*in != ',') {
458       break;
459     }
460     ++in;
461     in.skipWhitespace();
462   }
463   in.expect('}');
464
465   return ret;
466 }
467
468 dynamic parseArray(Input& in) {
469   assert(*in == '[');
470   ++in;
471
472   dynamic ret = dynamic::array;
473
474   in.skipWhitespace();
475   if (*in == ']') {
476     ++in;
477     return ret;
478   }
479
480   for (;;) {
481     if (in.getOpts().allow_trailing_comma && *in == ']') {
482       break;
483     }
484     ret.push_back(parseValue(in));
485     in.skipWhitespace();
486     if (*in != ',') {
487       break;
488     }
489     ++in;
490     in.skipWhitespace();
491   }
492   in.expect(']');
493
494   return ret;
495 }
496
497 dynamic parseNumber(Input& in) {
498   bool const negative = (*in == '-');
499   if (negative && in.consume("-Infinity")) {
500     if (in.getOpts().parse_numbers_as_strings) {
501       return "-Infinity";
502     } else {
503       return -std::numeric_limits<double>::infinity();
504     }
505   }
506
507   auto integral = in.skipMinusAndDigits();
508   if (negative && integral.size() < 2) {
509     in.error("expected digits after `-'");
510   }
511
512   auto const wasE = *in == 'e' || *in == 'E';
513
514   constexpr const char* maxInt = "9223372036854775807";
515   constexpr const char* minInt = "-9223372036854775808";
516   constexpr auto maxIntLen = constexpr_strlen(maxInt);
517   constexpr auto minIntLen = constexpr_strlen(minInt);
518
519   if (*in != '.' && !wasE && in.getOpts().parse_numbers_as_strings) {
520     return integral;
521   }
522
523   if (*in != '.' && !wasE) {
524     if (LIKELY(!in.getOpts().double_fallback || integral.size() < maxIntLen) ||
525         (!negative && integral.size() == maxIntLen && integral <= maxInt) ||
526         (negative && integral.size() == minIntLen && integral <= minInt)) {
527       auto val = to<int64_t>(integral);
528       in.skipWhitespace();
529       return val;
530     } else {
531       auto val = to<double>(integral);
532       in.skipWhitespace();
533       return val;
534     }
535   }
536
537   auto end = !wasE ? (++in, in.skipDigits().end()) : in.begin();
538   if (*in == 'e' || *in == 'E') {
539     ++in;
540     if (*in == '+' || *in == '-') {
541       ++in;
542     }
543     auto expPart = in.skipDigits();
544     end = expPart.end();
545   }
546   auto fullNum = range(integral.begin(), end);
547   if (in.getOpts().parse_numbers_as_strings) {
548     return fullNum;
549   }
550   auto val = to<double>(fullNum);
551   return val;
552 }
553
554 std::string decodeUnicodeEscape(Input& in) {
555   auto hexVal = [&] (char c) -> unsigned {
556     return c >= '0' && c <= '9' ? c - '0' :
557            c >= 'a' && c <= 'f' ? c - 'a' + 10 :
558            c >= 'A' && c <= 'F' ? c - 'A' + 10 :
559            (in.error("invalid hex digit"), 0);
560   };
561
562   auto readHex = [&]() -> uint16_t {
563     if (in.size() < 4) {
564       in.error("expected 4 hex digits");
565     }
566
567     uint16_t ret = hexVal(*in) * 4096;
568     ++in;
569     ret += hexVal(*in) * 256;
570     ++in;
571     ret += hexVal(*in) * 16;
572     ++in;
573     ret += hexVal(*in);
574     ++in;
575     return ret;
576   };
577
578   /*
579    * If the value encoded is in the surrogate pair range, we need to
580    * make sure there is another escape that we can use also.
581    */
582   uint32_t codePoint = readHex();
583   if (codePoint >= 0xd800 && codePoint <= 0xdbff) {
584     if (!in.consume("\\u")) {
585       in.error("expected another unicode escape for second half of "
586         "surrogate pair");
587     }
588     uint16_t second = readHex();
589     if (second >= 0xdc00 && second <= 0xdfff) {
590       codePoint = 0x10000 + ((codePoint & 0x3ff) << 10) +
591                   (second & 0x3ff);
592     } else {
593       in.error("second character in surrogate pair is invalid");
594     }
595   } else if (codePoint >= 0xdc00 && codePoint <= 0xdfff) {
596     in.error("invalid unicode code point (in range [0xdc00,0xdfff])");
597   }
598
599   return codePointToUtf8(codePoint);
600 }
601
602 std::string parseString(Input& in) {
603   assert(*in == '\"');
604   ++in;
605
606   std::string ret;
607   for (;;) {
608     auto range = in.skipWhile(
609       [] (char c) { return c != '\"' && c != '\\'; }
610     );
611     ret.append(range.begin(), range.end());
612
613     if (*in == '\"') {
614       ++in;
615       break;
616     }
617     if (*in == '\\') {
618       ++in;
619       switch (*in) {
620       case '\"':    ret.push_back('\"'); ++in; break;
621       case '\\':    ret.push_back('\\'); ++in; break;
622       case '/':     ret.push_back('/');  ++in; break;
623       case 'b':     ret.push_back('\b'); ++in; break;
624       case 'f':     ret.push_back('\f'); ++in; break;
625       case 'n':     ret.push_back('\n'); ++in; break;
626       case 'r':     ret.push_back('\r'); ++in; break;
627       case 't':     ret.push_back('\t'); ++in; break;
628       case 'u':     ++in; ret += decodeUnicodeEscape(in); break;
629       default:
630         in.error(to<std::string>("unknown escape ", *in, " in string").c_str());
631       }
632       continue;
633     }
634     if (*in == EOF) {
635       in.error("unterminated string");
636     }
637     if (!*in) {
638       /*
639        * Apparently we're actually supposed to ban all control
640        * characters from strings.  This seems unnecessarily
641        * restrictive, so we're only banning zero bytes.  (Since the
642        * string is presumed to be UTF-8 encoded it's fine to just
643        * check this way.)
644        */
645       in.error("null byte in string");
646     }
647
648     ret.push_back(*in);
649     ++in;
650   }
651
652   return ret;
653 }
654
655 dynamic parseValue(Input& in) {
656   RecursionGuard guard(in);
657
658   in.skipWhitespace();
659   return *in == '[' ? parseArray(in) :
660          *in == '{' ? parseObject(in) :
661          *in == '\"' ? parseString(in) :
662          (*in == '-' || (*in >= '0' && *in <= '9')) ? parseNumber(in) :
663          in.consume("true") ? true :
664          in.consume("false") ? false :
665          in.consume("null") ? nullptr :
666          in.consume("Infinity") ?
667           (in.getOpts().parse_numbers_as_strings ? (dynamic)"Infinity" :
668             (dynamic)std::numeric_limits<double>::infinity()) :
669          in.consume("NaN") ?
670            (in.getOpts().parse_numbers_as_strings ? (dynamic)"NaN" :
671              (dynamic)std::numeric_limits<double>::quiet_NaN()) :
672          in.error("expected json value");
673 }
674
675 }
676
677 //////////////////////////////////////////////////////////////////////
678
679 std::string serialize(dynamic const& dyn, serialization_opts const& opts) {
680   std::string ret;
681   unsigned indentLevel = 0;
682   Printer p(ret, opts.pretty_formatting ? &indentLevel : nullptr, &opts);
683   p(dyn);
684   return ret;
685 }
686
687 // Escape a string so that it is legal to print it in JSON text.
688 void escapeString(
689     StringPiece input,
690     std::string& out,
691     const serialization_opts& opts) {
692   auto hexDigit = [] (int c) -> char {
693     return c < 10 ? c + '0' : c - 10 + 'a';
694   };
695
696   out.reserve(out.size() + input.size() + 2);
697   out.push_back('\"');
698
699   auto* p = reinterpret_cast<const unsigned char*>(input.begin());
700   auto* q = reinterpret_cast<const unsigned char*>(input.begin());
701   auto* e = reinterpret_cast<const unsigned char*>(input.end());
702
703   while (p < e) {
704     // Since non-ascii encoding inherently does utf8 validation
705     // we explicitly validate utf8 only if non-ascii encoding is disabled.
706     if ((opts.validate_utf8 || opts.skip_invalid_utf8)
707         && !opts.encode_non_ascii) {
708       // to achieve better spatial and temporal coherence
709       // we do utf8 validation progressively along with the
710       // string-escaping instead of two separate passes
711
712       // as the encoding progresses, q will stay at or ahead of p
713       CHECK(q >= p);
714
715       // as p catches up with q, move q forward
716       if (q == p) {
717         // calling utf8_decode has the side effect of
718         // checking that utf8 encodings are valid
719         char32_t v = decodeUtf8(q, e, opts.skip_invalid_utf8);
720         if (opts.skip_invalid_utf8 && v == U'\ufffd') {
721           out.append(u8"\ufffd");
722           p = q;
723           continue;
724         }
725       }
726     }
727     if (opts.encode_non_ascii && (*p & 0x80)) {
728       // note that this if condition captures utf8 chars
729       // with value > 127, so size > 1 byte
730       char32_t v = decodeUtf8(p, e, opts.skip_invalid_utf8);
731       out.append("\\u");
732       out.push_back(hexDigit(v >> 12));
733       out.push_back(hexDigit((v >> 8) & 0x0f));
734       out.push_back(hexDigit((v >> 4) & 0x0f));
735       out.push_back(hexDigit(v & 0x0f));
736     } else if (*p == '\\' || *p == '\"') {
737       out.push_back('\\');
738       out.push_back(*p++);
739     } else if (*p <= 0x1f) {
740       switch (*p) {
741         case '\b': out.append("\\b"); p++; break;
742         case '\f': out.append("\\f"); p++; break;
743         case '\n': out.append("\\n"); p++; break;
744         case '\r': out.append("\\r"); p++; break;
745         case '\t': out.append("\\t"); p++; break;
746         default:
747           // note that this if condition captures non readable chars
748           // with value < 32, so size = 1 byte (e.g control chars).
749           out.append("\\u00");
750           out.push_back(hexDigit((*p & 0xf0) >> 4));
751           out.push_back(hexDigit(*p & 0xf));
752           p++;
753       }
754     } else {
755       out.push_back(*p++);
756     }
757   }
758
759   out.push_back('\"');
760 }
761
762 std::string stripComments(StringPiece jsonC) {
763   std::string result;
764   enum class State {
765     None,
766     InString,
767     InlineComment,
768     LineComment
769   } state = State::None;
770
771   for (size_t i = 0; i < jsonC.size(); ++i) {
772     auto s = jsonC.subpiece(i);
773     switch (state) {
774       case State::None:
775         if (s.startsWith("/*")) {
776           state = State::InlineComment;
777           ++i;
778           continue;
779         } else if (s.startsWith("//")) {
780           state = State::LineComment;
781           ++i;
782           continue;
783         } else if (s[0] == '\"') {
784           state = State::InString;
785         }
786         result.push_back(s[0]);
787         break;
788       case State::InString:
789         if (s[0] == '\\') {
790           if (UNLIKELY(s.size() == 1)) {
791             throw std::logic_error("Invalid JSONC: string is not terminated");
792           }
793           result.push_back(s[0]);
794           result.push_back(s[1]);
795           ++i;
796           continue;
797         } else if (s[0] == '\"') {
798           state = State::None;
799         }
800         result.push_back(s[0]);
801         break;
802       case State::InlineComment:
803         if (s.startsWith("*/")) {
804           state = State::None;
805           ++i;
806         }
807         break;
808       case State::LineComment:
809         if (s[0] == '\n') {
810           // skip the line break. It doesn't matter.
811           state = State::None;
812         }
813         break;
814       default:
815         throw std::logic_error("Unknown comment state");
816     }
817   }
818   return result;
819 }
820
821 }
822
823 //////////////////////////////////////////////////////////////////////
824
825 dynamic parseJson(StringPiece range) {
826   return parseJson(range, json::serialization_opts());
827 }
828
829 dynamic parseJson(
830     StringPiece range,
831     json::serialization_opts const& opts) {
832
833   json::Input in(range, &opts);
834
835   auto ret = parseValue(in);
836   in.skipWhitespace();
837   if (in.size() && *in != '\0') {
838     in.error("parsing didn't consume all input");
839   }
840   return ret;
841 }
842
843 std::string toJson(dynamic const& dyn) {
844   return json::serialize(dyn, json::serialization_opts());
845 }
846
847 std::string toPrettyJson(dynamic const& dyn) {
848   json::serialization_opts opts;
849   opts.pretty_formatting = true;
850   return json::serialize(dyn, opts);
851 }
852
853 //////////////////////////////////////////////////////////////////////
854 // dynamic::print_as_pseudo_json() is implemented here for header
855 // ordering reasons (most of the dynamic implementation is in
856 // dynamic-inl.h, which we don't want to include json.h).
857
858 void dynamic::print_as_pseudo_json(std::ostream& out) const {
859   json::serialization_opts opts;
860   opts.allow_non_string_keys = true;
861   opts.allow_nan_inf = true;
862   out << json::serialize(*this, opts);
863 }
864
865 void PrintTo(const dynamic& dyn, std::ostream* os) {
866   json::serialization_opts opts;
867   opts.allow_nan_inf = true;
868   opts.allow_non_string_keys = true;
869   opts.pretty_formatting = true;
870   opts.sort_keys = true;
871   *os << json::serialize(dyn, opts);
872 }
873
874 //////////////////////////////////////////////////////////////////////
875
876 }