Fix bug in stripComments
[folly.git] / folly / json.cpp
1 /*
2  * Copyright 2014 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/Range.h>
24 #include <folly/String.h>
25 #include <folly/Unicode.h>
26
27 namespace folly {
28
29 //////////////////////////////////////////////////////////////////////
30
31 namespace json {
32 namespace {
33
34 char32_t decodeUtf8(
35     const unsigned char*& p,
36     const unsigned char* const e,
37     bool skipOnError) {
38   /* The following encodings are valid, except for the 5 and 6 byte
39    * combinations:
40    * 0xxxxxxx
41    * 110xxxxx 10xxxxxx
42    * 1110xxxx 10xxxxxx 10xxxxxx
43    * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
44    * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
45    * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
46    */
47
48   auto skip = [&] { ++p; return U'\ufffd'; };
49
50   if (p >= e) {
51     if (skipOnError) return skip();
52     throw std::runtime_error("folly::decodeUtf8 empty/invalid string");
53   }
54
55   unsigned char fst = *p;
56   if (!(fst & 0x80)) {
57     // trivial case
58     return *p++;
59   }
60
61   static const uint32_t bitMask[] = {
62     (1 << 7) - 1,
63     (1 << 11) - 1,
64     (1 << 16) - 1,
65     (1 << 21) - 1
66   };
67
68   // upper control bits are masked out later
69   uint32_t d = fst;
70
71   if ((fst & 0xC0) != 0xC0) {
72     if (skipOnError) return skip();
73     throw std::runtime_error(to<std::string>("folly::decodeUtf8 i=0 d=", d));
74   }
75
76   fst <<= 1;
77
78   for (unsigned int i = 1; i != 3 && p + i < e; ++i) {
79     unsigned char tmp = p[i];
80
81     if ((tmp & 0xC0) != 0x80) {
82       if (skipOnError) return skip();
83       throw std::runtime_error(
84         to<std::string>("folly::decodeUtf8 i=", i, " tmp=", (uint32_t)tmp));
85     }
86
87     d = (d << 6) | (tmp & 0x3F);
88     fst <<= 1;
89
90     if (!(fst & 0x80)) {
91       d &= bitMask[i];
92
93       // overlong, could have been encoded with i bytes
94       if ((d & ~bitMask[i - 1]) == 0) {
95         if (skipOnError) return skip();
96         throw std::runtime_error(
97           to<std::string>("folly::decodeUtf8 i=", i, " d=", d));
98       }
99
100       // check for surrogates only needed for 3 bytes
101       if (i == 2) {
102         if ((d >= 0xD800 && d <= 0xDFFF) || d > 0x10FFFF) {
103           if (skipOnError) return skip();
104           throw std::runtime_error(
105             to<std::string>("folly::decodeUtf8 i=", i, " d=", d));
106         }
107       }
108
109       p += i + 1;
110       return d;
111     }
112   }
113
114   if (skipOnError) return skip();
115   throw std::runtime_error("folly::decodeUtf8 encoding length maxed out");
116 }
117
118 struct Printer {
119   explicit Printer(fbstring& out,
120                    unsigned* indentLevel,
121                    serialization_opts const* opts)
122     : out_(out)
123     , indentLevel_(indentLevel)
124     , opts_(*opts)
125   {}
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<fbstring>('\n', fbstring(*indentLevel_ * 2, ' '));
246     }
247   }
248
249   void mapColon() const {
250     out_ += indentLevel_ ? " : " : ":";
251   }
252
253 private:
254   fbstring& out_;
255   unsigned* const indentLevel_;
256   serialization_opts const& opts_;
257 };
258
259 // Wraps our input buffer with some helper functions.
260 struct Input {
261   explicit Input(StringPiece range, json::serialization_opts const* opts)
262       : range_(range)
263       , opts_(*opts)
264       , lineNum_(0)
265   {
266     storeCurrent();
267   }
268
269   Input(Input const&) = delete;
270   Input& operator=(Input const&) = delete;
271
272   char const* begin() const { return range_.begin(); }
273
274   // Parse ahead for as long as the supplied predicate is satisfied,
275   // returning a range of what was skipped.
276   template<class Predicate>
277   StringPiece skipWhile(const Predicate& p) {
278     std::size_t skipped = 0;
279     for (; skipped < range_.size(); ++skipped) {
280       if (!p(range_[skipped])) {
281         break;
282       }
283       if (range_[skipped] == '\n') {
284         ++lineNum_;
285       }
286     }
287     auto ret = range_.subpiece(0, skipped);
288     range_.advance(skipped);
289     storeCurrent();
290     return ret;
291   }
292
293   StringPiece skipDigits() {
294     return skipWhile([] (char c) { return c >= '0' && c <= '9'; });
295   }
296
297   StringPiece skipMinusAndDigits() {
298     bool firstChar = true;
299     return skipWhile([&firstChar] (char c) {
300         bool result = (c >= '0' && c <= '9') || (firstChar && c == '-');
301         firstChar = false;
302         return result;
303       });
304   }
305
306   void skipWhitespace() {
307     range_ = folly::skipWhitespace(range_);
308     storeCurrent();
309   }
310
311   void expect(char c) {
312     if (**this != c) {
313       throw ParseError(lineNum_, context(),
314         to<std::string>("expected '", c, '\''));
315     }
316     ++*this;
317   }
318
319   std::size_t size() const {
320     return range_.size();
321   }
322
323   int operator*() const {
324     return current_;
325   }
326
327   void operator++() {
328     range_.pop_front();
329     storeCurrent();
330   }
331
332   template<class T>
333   T extract() {
334     try {
335       return to<T>(&range_);
336     } catch (std::exception const& e) {
337       error(e.what());
338     }
339   }
340
341   bool consume(StringPiece str) {
342     if (boost::starts_with(range_, str)) {
343       range_.advance(str.size());
344       storeCurrent();
345       return true;
346     }
347     return false;
348   }
349
350   std::string context() const {
351     return range_.subpiece(0, 16 /* arbitrary */).toString();
352   }
353
354   dynamic error(char const* what) const {
355     throw ParseError(lineNum_, context(), what);
356   }
357
358   json::serialization_opts const& getOpts() {
359     return opts_;
360   }
361
362 private:
363   void storeCurrent() {
364     current_ = range_.empty() ? EOF : range_.front();
365   }
366
367 private:
368   StringPiece range_;
369   json::serialization_opts const& opts_;
370   unsigned lineNum_;
371   int current_;
372 };
373
374 dynamic parseValue(Input& in);
375 fbstring parseString(Input& in);
376 dynamic parseNumber(Input& in);
377
378 dynamic parseObject(Input& in) {
379   assert(*in == '{');
380   ++in;
381
382   dynamic ret = dynamic::object;
383
384   in.skipWhitespace();
385   if (*in == '}') {
386     ++in;
387     return ret;
388   }
389
390   for (;;) {
391     if (in.getOpts().allow_trailing_comma && *in == '}') {
392       break;
393     }
394     if (*in == '\"') { // string
395       auto key = parseString(in);
396       in.skipWhitespace();
397       in.expect(':');
398       in.skipWhitespace();
399       ret.insert(std::move(key), parseValue(in));
400     } else if (!in.getOpts().allow_non_string_keys) {
401       in.error("expected string for object key name");
402     } else {
403       auto key = parseValue(in);
404       in.skipWhitespace();
405       in.expect(':');
406       in.skipWhitespace();
407       ret.insert(std::move(key), parseValue(in));
408     }
409
410     in.skipWhitespace();
411     if (*in != ',') {
412       break;
413     }
414     ++in;
415     in.skipWhitespace();
416   }
417   in.expect('}');
418
419   return ret;
420 }
421
422 dynamic parseArray(Input& in) {
423   assert(*in == '[');
424   ++in;
425
426   dynamic ret = {};
427
428   in.skipWhitespace();
429   if (*in == ']') {
430     ++in;
431     return ret;
432   }
433
434   for (;;) {
435     if (in.getOpts().allow_trailing_comma && *in == ']') {
436       break;
437     }
438     ret.push_back(parseValue(in));
439     in.skipWhitespace();
440     if (*in != ',') {
441       break;
442     }
443     ++in;
444     in.skipWhitespace();
445   }
446   in.expect(']');
447
448   return ret;
449 }
450
451 dynamic parseNumber(Input& in) {
452   bool const negative = (*in == '-');
453   if (negative) {
454     if (in.consume("-Infinity")) {
455       return -std::numeric_limits<double>::infinity();
456     }
457   }
458
459   auto integral = in.skipMinusAndDigits();
460   if (negative && integral.size() < 2) {
461     in.error("expected digits after `-'");
462   }
463
464   auto const wasE = *in == 'e' || *in == 'E';
465   if (*in != '.' && !wasE) {
466     auto val = to<int64_t>(integral);
467     in.skipWhitespace();
468     return val;
469   }
470
471   auto end = !wasE ? (++in, in.skipDigits().end()) : in.begin();
472   if (*in == 'e' || *in == 'E') {
473     ++in;
474     if (*in == '+' || *in == '-') {
475       ++in;
476     }
477     auto expPart = in.skipDigits();
478     end = expPart.end();
479   }
480   auto fullNum = range(integral.begin(), end);
481
482   auto val = to<double>(fullNum);
483   return val;
484 }
485
486 fbstring decodeUnicodeEscape(Input& in) {
487   auto hexVal = [&] (char c) -> unsigned {
488     return c >= '0' && c <= '9' ? c - '0' :
489            c >= 'a' && c <= 'f' ? c - 'a' + 10 :
490            c >= 'A' && c <= 'F' ? c - 'A' + 10 :
491            (in.error("invalid hex digit"), 0);
492   };
493
494   auto readHex = [&]() -> uint16_t {
495     if (in.size() < 4) {
496       in.error("expected 4 hex digits");
497     }
498
499     uint16_t ret = hexVal(*in) * 4096;
500     ++in;
501     ret += hexVal(*in) * 256;
502     ++in;
503     ret += hexVal(*in) * 16;
504     ++in;
505     ret += hexVal(*in);
506     ++in;
507     return ret;
508   };
509
510   /*
511    * If the value encoded is in the surrogate pair range, we need to
512    * make sure there is another escape that we can use also.
513    */
514   uint32_t codePoint = readHex();
515   if (codePoint >= 0xd800 && codePoint <= 0xdbff) {
516     if (!in.consume("\\u")) {
517       in.error("expected another unicode escape for second half of "
518         "surrogate pair");
519     }
520     uint16_t second = readHex();
521     if (second >= 0xdc00 && second <= 0xdfff) {
522       codePoint = 0x10000 + ((codePoint & 0x3ff) << 10) +
523                   (second & 0x3ff);
524     } else {
525       in.error("second character in surrogate pair is invalid");
526     }
527   } else if (codePoint >= 0xdc00 && codePoint <= 0xdfff) {
528     in.error("invalid unicode code point (in range [0xdc00,0xdfff])");
529   }
530
531   return codePointToUtf8(codePoint);
532 }
533
534 fbstring parseString(Input& in) {
535   assert(*in == '\"');
536   ++in;
537
538   fbstring ret;
539   for (;;) {
540     auto range = in.skipWhile(
541       [] (char c) { return c != '\"' && c != '\\'; }
542     );
543     ret.append(range.begin(), range.end());
544
545     if (*in == '\"') {
546       ++in;
547       break;
548     }
549     if (*in == '\\') {
550       ++in;
551       switch (*in) {
552       case '\"':    ret.push_back('\"'); ++in; break;
553       case '\\':    ret.push_back('\\'); ++in; break;
554       case '/':     ret.push_back('/');  ++in; break;
555       case 'b':     ret.push_back('\b'); ++in; break;
556       case 'f':     ret.push_back('\f'); ++in; break;
557       case 'n':     ret.push_back('\n'); ++in; break;
558       case 'r':     ret.push_back('\r'); ++in; break;
559       case 't':     ret.push_back('\t'); ++in; break;
560       case 'u':     ++in; ret += decodeUnicodeEscape(in); break;
561       default:      in.error(to<fbstring>("unknown escape ", *in,
562                                           " in string").c_str());
563       }
564       continue;
565     }
566     if (*in == EOF) {
567       in.error("unterminated string");
568     }
569     if (!*in) {
570       /*
571        * Apparently we're actually supposed to ban all control
572        * characters from strings.  This seems unnecessarily
573        * restrictive, so we're only banning zero bytes.  (Since the
574        * string is presumed to be UTF-8 encoded it's fine to just
575        * check this way.)
576        */
577       in.error("null byte in string");
578     }
579
580     ret.push_back(*in);
581     ++in;
582   }
583
584   return ret;
585 }
586
587 dynamic parseValue(Input& in) {
588   in.skipWhitespace();
589   return *in == '[' ? parseArray(in) :
590          *in == '{' ? parseObject(in) :
591          *in == '\"' ? parseString(in) :
592          (*in == '-' || (*in >= '0' && *in <= '9')) ? parseNumber(in) :
593          in.consume("true") ? true :
594          in.consume("false") ? false :
595          in.consume("null") ? nullptr :
596          in.consume("Infinity") ? std::numeric_limits<double>::infinity() :
597          in.consume("NaN") ? std::numeric_limits<double>::quiet_NaN() :
598          in.error("expected json value");
599 }
600
601 }
602
603 //////////////////////////////////////////////////////////////////////
604
605 fbstring serialize(dynamic const& dyn, serialization_opts const& opts) {
606   fbstring ret;
607   unsigned indentLevel = 0;
608   Printer p(ret, opts.pretty_formatting ? &indentLevel : nullptr, &opts);
609   p(dyn);
610   return ret;
611 }
612
613 // Escape a string so that it is legal to print it in JSON text.
614 void escapeString(StringPiece input,
615                   fbstring& out,
616                   const serialization_opts& opts) {
617   auto hexDigit = [] (int c) -> char {
618     return c < 10 ? c + '0' : c - 10 + 'a';
619   };
620
621   out.reserve(out.size() + input.size() + 2);
622   out.push_back('\"');
623
624   auto* p = reinterpret_cast<const unsigned char*>(input.begin());
625   auto* q = reinterpret_cast<const unsigned char*>(input.begin());
626   auto* e = reinterpret_cast<const unsigned char*>(input.end());
627
628   while (p < e) {
629     // Since non-ascii encoding inherently does utf8 validation
630     // we explicitly validate utf8 only if non-ascii encoding is disabled.
631     if ((opts.validate_utf8 || opts.skip_invalid_utf8)
632         && !opts.encode_non_ascii) {
633       // to achieve better spatial and temporal coherence
634       // we do utf8 validation progressively along with the
635       // string-escaping instead of two separate passes
636
637       // as the encoding progresses, q will stay at or ahead of p
638       CHECK(q >= p);
639
640       // as p catches up with q, move q forward
641       if (q == p) {
642         // calling utf8_decode has the side effect of
643         // checking that utf8 encodings are valid
644         char32_t v = decodeUtf8(q, e, opts.skip_invalid_utf8);
645         if (opts.skip_invalid_utf8 && v == U'\ufffd') {
646           out.append("\ufffd");
647           p = q;
648           continue;
649         }
650       }
651     }
652     if (opts.encode_non_ascii && (*p & 0x80)) {
653       // note that this if condition captures utf8 chars
654       // with value > 127, so size > 1 byte
655       char32_t v = decodeUtf8(p, e, opts.skip_invalid_utf8);
656       out.append("\\u");
657       out.push_back(hexDigit(v >> 12));
658       out.push_back(hexDigit((v >> 8) & 0x0f));
659       out.push_back(hexDigit((v >> 4) & 0x0f));
660       out.push_back(hexDigit(v & 0x0f));
661     } else if (*p == '\\' || *p == '\"') {
662       out.push_back('\\');
663       out.push_back(*p++);
664     } else if (*p <= 0x1f) {
665       switch (*p) {
666         case '\b': out.append("\\b"); p++; break;
667         case '\f': out.append("\\f"); p++; break;
668         case '\n': out.append("\\n"); p++; break;
669         case '\r': out.append("\\r"); p++; break;
670         case '\t': out.append("\\t"); p++; break;
671         default:
672           // note that this if condition captures non readable chars
673           // with value < 32, so size = 1 byte (e.g control chars).
674           out.append("\\u00");
675           out.push_back(hexDigit((*p & 0xf0) >> 4));
676           out.push_back(hexDigit(*p & 0xf));
677           p++;
678       }
679     } else {
680       out.push_back(*p++);
681     }
682   }
683
684   out.push_back('\"');
685 }
686
687 fbstring stripComments(StringPiece jsonC) {
688   fbstring result;
689   enum class State {
690     None,
691     InString,
692     InlineComment,
693     LineComment
694   } state = State::None;
695
696   for (size_t i = 0; i < jsonC.size(); ++i) {
697     auto s = jsonC.subpiece(i);
698     switch (state) {
699       case State::None:
700         if (s.startsWith("/*")) {
701           state = State::InlineComment;
702           ++i;
703           continue;
704         } else if (s.startsWith("//")) {
705           state = State::LineComment;
706           ++i;
707           continue;
708         } else if (s[0] == '\"') {
709           state = State::InString;
710         }
711         result.push_back(s[0]);
712         break;
713       case State::InString:
714         if (s[0] == '\\') {
715           if (UNLIKELY(s.size() == 1)) {
716             throw std::logic_error("Invalid JSONC: string is not terminated");
717           }
718           result.push_back(s[0]);
719           result.push_back(s[1]);
720           ++i;
721           continue;
722         } else if (s[0] == '\"') {
723           state = State::None;
724         }
725         result.push_back(s[0]);
726         break;
727       case State::InlineComment:
728         if (s.startsWith("*/")) {
729           state = State::None;
730           ++i;
731         }
732         break;
733       case State::LineComment:
734         if (s[0] == '\n') {
735           // skip the line break. It doesn't matter.
736           state = State::None;
737         }
738         break;
739       default:
740         throw std::logic_error("Unknown comment state");
741     }
742   }
743   return result;
744 }
745
746 }
747
748 //////////////////////////////////////////////////////////////////////
749
750 dynamic parseJson(StringPiece range) {
751   return parseJson(range, json::serialization_opts());
752 }
753
754 dynamic parseJson(
755     StringPiece range,
756     json::serialization_opts const& opts) {
757
758   json::Input in(range, &opts);
759
760   auto ret = parseValue(in);
761   in.skipWhitespace();
762   if (in.size() && *in != '\0') {
763     in.error("parsing didn't consume all input");
764   }
765   return ret;
766 }
767
768 fbstring toJson(dynamic const& dyn) {
769   return json::serialize(dyn, json::serialization_opts());
770 }
771
772 fbstring toPrettyJson(dynamic const& dyn) {
773   json::serialization_opts opts;
774   opts.pretty_formatting = true;
775   return json::serialize(dyn, opts);
776 }
777
778 //////////////////////////////////////////////////////////////////////
779 // dynamic::print_as_pseudo_json() is implemented here for header
780 // ordering reasons (most of the dynamic implementation is in
781 // dynamic-inl.h, which we don't want to include json.h).
782
783 void dynamic::print_as_pseudo_json(std::ostream& out) const {
784   json::serialization_opts opts;
785   opts.allow_non_string_keys = true;
786   opts.allow_nan_inf = true;
787   out << json::serialize(*this, opts);
788 }
789
790 //////////////////////////////////////////////////////////////////////
791
792 }