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