1 /* Copyright (c) 2013 Dropbox, Inc.
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 static const int max_depth
= 200;
36 using std::make_shared
;
37 using std::initializer_list
;
40 /* Helper for representing null - just a do-nothing struct, plus comparison
41 * operators so the helpers in JsonValue work. We can't use nullptr_t because
42 * it may not be orderable.
45 bool operator==(NullStruct
) const { return true; }
46 bool operator<(NullStruct
) const { return false; }
49 /* * * * * * * * * * * * * * * * * * * *
53 static void dump(NullStruct
, string
&out
) {
57 static void dump(double value
, string
&out
) {
58 if (std::isfinite(value
)) {
60 snprintf(buf
, sizeof buf
, "%.17g", value
);
67 static void dump(int value
, string
&out
) {
69 snprintf(buf
, sizeof buf
, "%d", value
);
73 static void dump(bool value
, string
&out
) {
74 out
+= value
? "true" : "false";
77 static void dump(const string
&value
, string
&out
) {
79 for (size_t i
= 0; i
< value
.length(); i
++) {
80 const char ch
= value
[i
];
83 } else if (ch
== '"') {
85 } else if (ch
== '\b') {
87 } else if (ch
== '\f') {
89 } else if (ch
== '\n') {
91 } else if (ch
== '\r') {
93 } else if (ch
== '\t') {
95 } else if (static_cast<uint8_t>(ch
) <= 0x1f) {
97 snprintf(buf
, sizeof buf
, "\\u%04x", ch
);
99 } else if (static_cast<uint8_t>(ch
) == 0xe2 && static_cast<uint8_t>(value
[i
+1]) == 0x80
100 && static_cast<uint8_t>(value
[i
+2]) == 0xa8) {
103 } else if (static_cast<uint8_t>(ch
) == 0xe2 && static_cast<uint8_t>(value
[i
+1]) == 0x80
104 && static_cast<uint8_t>(value
[i
+2]) == 0xa9) {
114 static void dump(const Json::array
&values
, string
&out
) {
117 for (const auto &value
: values
) {
126 static void dump(const Json::object
&values
, string
&out
) {
129 for (const auto &kv
: values
) {
140 void Json::dump(string
&out
) const {
144 /* * * * * * * * * * * * * * * * * * * *
148 template <Json::Type tag
, typename T
>
149 class Value
: public JsonValue
{
153 explicit Value(const T
&value
) : m_value(value
) {}
154 explicit Value(T
&&value
) : m_value(move(value
)) {}
157 Json::Type
type() const override
{
162 bool equals(const JsonValue
* other
) const override
{
163 return m_value
== static_cast<const Value
<tag
, T
> *>(other
)->m_value
;
165 bool less(const JsonValue
* other
) const override
{
166 return m_value
< static_cast<const Value
<tag
, T
> *>(other
)->m_value
;
170 void dump(string
&out
) const override
{ json11::dump(m_value
, out
); }
173 class JsonDouble final
: public Value
<Json::NUMBER
, double> {
174 double number_value() const override
{ return m_value
; }
175 int int_value() const override
{ return static_cast<int>(m_value
); }
176 bool equals(const JsonValue
* other
) const override
{ return m_value
== other
->number_value(); }
177 bool less(const JsonValue
* other
) const override
{ return m_value
< other
->number_value(); }
179 explicit JsonDouble(double value
) : Value(value
) {}
182 class JsonInt final
: public Value
<Json::NUMBER
, int> {
183 double number_value() const override
{ return m_value
; }
184 int int_value() const override
{ return m_value
; }
185 bool equals(const JsonValue
* other
) const override
{ return m_value
== other
->number_value(); }
186 bool less(const JsonValue
* other
) const override
{ return m_value
< other
->number_value(); }
188 explicit JsonInt(int value
) : Value(value
) {}
191 class JsonBoolean final
: public Value
<Json::BOOL
, bool> {
192 bool bool_value() const override
{ return m_value
; }
194 explicit JsonBoolean(bool value
) : Value(value
) {}
197 class JsonString final
: public Value
<Json::STRING
, string
> {
198 const string
&string_value() const override
{ return m_value
; }
200 explicit JsonString(const string
&value
) : Value(value
) {}
201 explicit JsonString(string
&&value
) : Value(move(value
)) {}
204 class JsonArray final
: public Value
<Json::ARRAY
, Json::array
> {
205 const Json::array
&array_items() const override
{ return m_value
; }
206 const Json
& operator[](size_t i
) const override
;
208 explicit JsonArray(const Json::array
&value
) : Value(value
) {}
209 explicit JsonArray(Json::array
&&value
) : Value(move(value
)) {}
212 class JsonObject final
: public Value
<Json::OBJECT
, Json::object
> {
213 const Json::object
&object_items() const override
{ return m_value
; }
214 const Json
& operator[](const string
&key
) const override
;
216 explicit JsonObject(const Json::object
&value
) : Value(value
) {}
217 explicit JsonObject(Json::object
&&value
) : Value(move(value
)) {}
220 class JsonNull final
: public Value
<Json::NUL
, NullStruct
> {
222 JsonNull() : Value({}) {}
225 /* * * * * * * * * * * * * * * * * * * *
226 * Static globals - static-init-safe
229 const std::shared_ptr
<JsonValue
> null
= make_shared
<JsonNull
>();
230 const std::shared_ptr
<JsonValue
> t
= make_shared
<JsonBoolean
>(true);
231 const std::shared_ptr
<JsonValue
> f
= make_shared
<JsonBoolean
>(false);
232 const string empty_string
;
233 const vector
<Json
> empty_vector
;
234 const map
<string
, Json
> empty_map
;
238 static const Statics
& statics() {
239 static const Statics s
{};
243 static const Json
& static_null() {
244 // This has to be separate, not in Statics, because Json() accesses statics().null.
245 static const Json json_null
;
249 /* * * * * * * * * * * * * * * * * * * *
253 Json::Json() noexcept
: m_ptr(statics().null
) {}
254 Json::Json(std::nullptr_t
) noexcept
: m_ptr(statics().null
) {}
255 Json::Json(double value
) : m_ptr(make_shared
<JsonDouble
>(value
)) {}
256 Json::Json(int value
) : m_ptr(make_shared
<JsonInt
>(value
)) {}
257 Json::Json(bool value
) : m_ptr(value
? statics().t
: statics().f
) {}
258 Json::Json(const string
&value
) : m_ptr(make_shared
<JsonString
>(value
)) {}
259 Json::Json(string
&&value
) : m_ptr(make_shared
<JsonString
>(move(value
))) {}
260 Json::Json(const char * value
) : m_ptr(make_shared
<JsonString
>(value
)) {}
261 Json::Json(const Json::array
&values
) : m_ptr(make_shared
<JsonArray
>(values
)) {}
262 Json::Json(Json::array
&&values
) : m_ptr(make_shared
<JsonArray
>(move(values
))) {}
263 Json::Json(const Json::object
&values
) : m_ptr(make_shared
<JsonObject
>(values
)) {}
264 Json::Json(Json::object
&&values
) : m_ptr(make_shared
<JsonObject
>(move(values
))) {}
266 /* * * * * * * * * * * * * * * * * * * *
270 Json::Type
Json::type() const { return m_ptr
->type(); }
271 double Json::number_value() const { return m_ptr
->number_value(); }
272 int Json::int_value() const { return m_ptr
->int_value(); }
273 bool Json::bool_value() const { return m_ptr
->bool_value(); }
274 const string
& Json::string_value() const { return m_ptr
->string_value(); }
275 const vector
<Json
> & Json::array_items() const { return m_ptr
->array_items(); }
276 const map
<string
, Json
> & Json::object_items() const { return m_ptr
->object_items(); }
277 const Json
& Json::operator[] (size_t i
) const { return (*m_ptr
)[i
]; }
278 const Json
& Json::operator[] (const string
&key
) const { return (*m_ptr
)[key
]; }
280 double JsonValue::number_value() const { return 0; }
281 int JsonValue::int_value() const { return 0; }
282 bool JsonValue::bool_value() const { return false; }
283 const string
& JsonValue::string_value() const { return statics().empty_string
; }
284 const vector
<Json
> & JsonValue::array_items() const { return statics().empty_vector
; }
285 const map
<string
, Json
> & JsonValue::object_items() const { return statics().empty_map
; }
286 const Json
& JsonValue::operator[] (size_t) const { return static_null(); }
287 const Json
& JsonValue::operator[] (const string
&) const { return static_null(); }
289 const Json
& JsonObject::operator[] (const string
&key
) const {
290 auto iter
= m_value
.find(key
);
291 return (iter
== m_value
.end()) ? static_null() : iter
->second
;
293 const Json
& JsonArray::operator[] (size_t i
) const {
294 if (i
>= m_value
.size()) return static_null();
295 else return m_value
[i
];
298 /* * * * * * * * * * * * * * * * * * * *
302 bool Json::operator== (const Json
&other
) const {
303 if (m_ptr
== other
.m_ptr
)
305 if (m_ptr
->type() != other
.m_ptr
->type())
308 return m_ptr
->equals(other
.m_ptr
.get());
311 bool Json::operator< (const Json
&other
) const {
312 if (m_ptr
== other
.m_ptr
)
314 if (m_ptr
->type() != other
.m_ptr
->type())
315 return m_ptr
->type() < other
.m_ptr
->type();
317 return m_ptr
->less(other
.m_ptr
.get());
320 /* * * * * * * * * * * * * * * * * * * *
326 * Format char c suitable for printing in an error message.
328 static inline string
esc(char c
) {
330 if (static_cast<uint8_t>(c
) >= 0x20 && static_cast<uint8_t>(c
) <= 0x7f) {
331 snprintf(buf
, sizeof buf
, "'%c' (%d)", c
, c
);
333 snprintf(buf
, sizeof buf
, "(%d)", c
);
338 static inline bool in_range(long x
, long lower
, long upper
) {
339 return (x
>= lower
&& x
<= upper
);
345 * Object that tracks all state of an in-progress parse.
347 struct JsonParser final
{
355 const JsonParse strategy
;
357 /* fail(msg, err_ret = Json())
359 * Mark this parse as failed.
361 Json
fail(string
&&msg
) {
362 return fail(move(msg
), Json());
365 template <typename T
>
366 T
fail(string
&&msg
, const T err_ret
) {
368 err
= std::move(msg
);
373 /* consume_whitespace()
375 * Advance until the current character is non-whitespace.
377 void consume_whitespace() {
378 while (str
[i
] == ' ' || str
[i
] == '\r' || str
[i
] == '\n' || str
[i
] == '\t')
384 * Advance comments (c-style inline and multiline).
386 bool consume_comment() {
387 bool comment_found
= false;
391 return fail("unexpected end of input after start of comment", false);
392 if (str
[i
] == '/') { // inline comment
394 // advance until next line, or end of input
395 while (i
< str
.size() && str
[i
] != '\n') {
398 comment_found
= true;
400 else if (str
[i
] == '*') { // multiline comment
402 if (i
> str
.size()-2)
403 return fail("unexpected end of input inside multi-line comment", false);
404 // advance until closing tokens
405 while (!(str
[i
] == '*' && str
[i
+1] == '/')) {
407 if (i
> str
.size()-2)
409 "unexpected end of input inside multi-line comment", false);
412 comment_found
= true;
415 return fail("malformed comment", false);
417 return comment_found
;
422 * Advance until the current character is non-whitespace and non-comment.
424 void consume_garbage() {
425 consume_whitespace();
426 if(strategy
== JsonParse::COMMENTS
) {
427 bool comment_found
= false;
429 comment_found
= consume_comment();
431 consume_whitespace();
433 while(comment_found
);
439 * Return the next non-whitespace character. If the end of the input is reached,
440 * flag an error and return 0.
442 char get_next_token() {
444 if (failed
) return static_cast<char>(0);
446 return fail("unexpected end of input", static_cast<char>(0));
451 /* encode_utf8(pt, out)
453 * Encode pt as UTF-8 and add it to out.
455 void encode_utf8(long pt
, string
& out
) {
460 out
+= static_cast<char>(pt
);
461 } else if (pt
< 0x800) {
462 out
+= static_cast<char>((pt
>> 6) | 0xC0);
463 out
+= static_cast<char>((pt
& 0x3F) | 0x80);
464 } else if (pt
< 0x10000) {
465 out
+= static_cast<char>((pt
>> 12) | 0xE0);
466 out
+= static_cast<char>(((pt
>> 6) & 0x3F) | 0x80);
467 out
+= static_cast<char>((pt
& 0x3F) | 0x80);
469 out
+= static_cast<char>((pt
>> 18) | 0xF0);
470 out
+= static_cast<char>(((pt
>> 12) & 0x3F) | 0x80);
471 out
+= static_cast<char>(((pt
>> 6) & 0x3F) | 0x80);
472 out
+= static_cast<char>((pt
& 0x3F) | 0x80);
478 * Parse a string, starting at the current position.
480 string
parse_string() {
482 long last_escaped_codepoint
= -1;
485 return fail("unexpected end of input in string", "");
490 encode_utf8(last_escaped_codepoint
, out
);
494 if (in_range(ch
, 0, 0x1f))
495 return fail("unescaped " + esc(ch
) + " in string", "");
497 // The usual case: non-escaped characters
499 encode_utf8(last_escaped_codepoint
, out
);
500 last_escaped_codepoint
= -1;
507 return fail("unexpected end of input in string", "");
512 // Extract 4-byte escape sequence
513 string esc
= str
.substr(i
, 4);
514 // Explicitly check length of the substring. The following loop
515 // relies on std::string returning the terminating NUL when
516 // accessing str[length]. Checking here reduces brittleness.
517 if (esc
.length() < 4) {
518 return fail("bad \\u escape: " + esc
, "");
520 for (size_t j
= 0; j
< 4; j
++) {
521 if (!in_range(esc
[j
], 'a', 'f') && !in_range(esc
[j
], 'A', 'F')
522 && !in_range(esc
[j
], '0', '9'))
523 return fail("bad \\u escape: " + esc
, "");
526 long codepoint
= strtol(esc
.data(), nullptr, 16);
528 // JSON specifies that characters outside the BMP shall be encoded as a pair
529 // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
530 // whether we're in the middle of such a beast: the previous codepoint was an
531 // escaped lead (high) surrogate, and this is a trail (low) surrogate.
532 if (in_range(last_escaped_codepoint
, 0xD800, 0xDBFF)
533 && in_range(codepoint
, 0xDC00, 0xDFFF)) {
534 // Reassemble the two surrogate pairs into one astral-plane character, per
535 // the UTF-16 algorithm.
536 encode_utf8((((last_escaped_codepoint
- 0xD800) << 10)
537 | (codepoint
- 0xDC00)) + 0x10000, out
);
538 last_escaped_codepoint
= -1;
540 encode_utf8(last_escaped_codepoint
, out
);
541 last_escaped_codepoint
= codepoint
;
548 encode_utf8(last_escaped_codepoint
, out
);
549 last_escaped_codepoint
= -1;
553 } else if (ch
== 'f') {
555 } else if (ch
== 'n') {
557 } else if (ch
== 'r') {
559 } else if (ch
== 't') {
561 } else if (ch
== '"' || ch
== '\\' || ch
== '/') {
564 return fail("invalid escape character " + esc(ch
), "");
573 Json
parse_number() {
574 size_t start_pos
= i
;
582 if (in_range(str
[i
], '0', '9'))
583 return fail("leading 0s not permitted in numbers");
584 } else if (in_range(str
[i
], '1', '9')) {
586 while (in_range(str
[i
], '0', '9'))
589 return fail("invalid " + esc(str
[i
]) + " in number");
592 if (str
[i
] != '.' && str
[i
] != 'e' && str
[i
] != 'E'
593 && (i
- start_pos
) <= static_cast<size_t>(std::numeric_limits
<int>::digits10
)) {
594 return std::atoi(str
.c_str() + start_pos
);
600 if (!in_range(str
[i
], '0', '9'))
601 return fail("at least one digit required in fractional part");
603 while (in_range(str
[i
], '0', '9'))
608 if (str
[i
] == 'e' || str
[i
] == 'E') {
611 if (str
[i
] == '+' || str
[i
] == '-')
614 if (!in_range(str
[i
], '0', '9'))
615 return fail("at least one digit required in exponent");
617 while (in_range(str
[i
], '0', '9'))
621 return std::strtod(str
.c_str() + start_pos
, nullptr);
626 * Expect that 'str' starts at the character that was just read. If it does, advance
627 * the input and return res. If not, flag an error.
629 Json
expect(const string
&expected
, Json res
) {
632 if (str
.compare(i
, expected
.length(), expected
) == 0) {
633 i
+= expected
.length();
636 return fail("parse error: expected " + expected
+ ", got " + str
.substr(i
, expected
.length()));
642 * Parse a JSON object.
644 Json
parse_json(int depth
) {
645 if (depth
> max_depth
) {
646 return fail("exceeded maximum nesting depth");
649 char ch
= get_next_token();
653 if (ch
== '-' || (ch
>= '0' && ch
<= '9')) {
655 return parse_number();
659 return expect("true", true);
662 return expect("false", false);
665 return expect("null", Json());
668 return parse_string();
671 map
<string
, Json
> data
;
672 ch
= get_next_token();
678 return fail("expected '\"' in object, got " + esc(ch
));
680 string key
= parse_string();
684 ch
= get_next_token();
686 return fail("expected ':' in object, got " + esc(ch
));
688 data
[std::move(key
)] = parse_json(depth
+ 1);
692 ch
= get_next_token();
696 return fail("expected ',' in object, got " + esc(ch
));
698 ch
= get_next_token();
705 ch
= get_next_token();
711 data
.push_back(parse_json(depth
+ 1));
715 ch
= get_next_token();
719 return fail("expected ',' in list, got " + esc(ch
));
721 ch
= get_next_token();
727 return fail("expected value, got " + esc(ch
));
732 Json
Json::parse(const string
&in
, string
&err
, JsonParse strategy
) {
733 JsonParser parser
{ in
, 0, err
, false, strategy
};
734 Json result
= parser
.parse_json(0);
736 // Check for any trailing garbage
737 parser
.consume_garbage();
740 if (parser
.i
!= in
.size())
741 return parser
.fail("unexpected trailing " + esc(in
[parser
.i
]));
746 // Documented in json11.hpp
747 vector
<Json
> Json::parse_multi(const string
&in
,
748 std::string::size_type
&parser_stop_pos
,
750 JsonParse strategy
) {
751 JsonParser parser
{ in
, 0, err
, false, strategy
};
753 vector
<Json
> json_vec
;
754 while (parser
.i
!= in
.size() && !parser
.failed
) {
755 json_vec
.push_back(parser
.parse_json(0));
759 // Check for another object
760 parser
.consume_garbage();
763 parser_stop_pos
= parser
.i
;
768 /* * * * * * * * * * * * * * * * * * * *
772 bool Json::has_shape(const shape
& types
, string
& err
) const {
774 err
= "expected JSON object, got " + dump();
778 for (auto & item
: types
) {
779 if ((*this)[item
.first
].type() != item
.second
) {
780 err
= "bad type for " + item
.first
+ " in " + dump();
788 } // namespace json11