OILS / vendor / souffle / utility / json11.h View on Github | oilshell.org

1122 lines, 647 significant
1/* json11
2 *
3 * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
4 *
5 * The core object provided by the library is json11::Json. A Json object represents any JSON
6 * value: null, bool, number (int or double), string (std::string), array (std::vector), or
7 * object (std::map).
8 *
9 * Json objects act like values: they can be assigned, copied, moved, compared for equality or
10 * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and
11 * Json::parse (static) to parse a std::string as a Json object.
12 *
13 * Internally, the various types of Json object are represented by the JsonValue class
14 * hierarchy.
15 *
16 * A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
17 * so some JSON implementations distinguish between integers and floating-point numbers, while
18 * some don't. In json11, we choose the latter. Because some JSON implementations (namely
19 * Javascript itself) treat all numbers as the same type, distinguishing the two leads
20 * to JSON that will be *silently* changed by a round-trip through those implementations.
21 * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
22 * provides integer helpers.
23 *
24 * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the
25 * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64
26 * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch
27 * will be exact for +/- 275 years.)
28 */
29
30/* Copyright (c) 2013 Dropbox, Inc.
31 *
32 * Permission is hereby granted, free of charge, to any person obtaining a copy
33 * of this software and associated documentation files (the "Software"), to deal
34 * in the Software without restriction, including without limitation the rights
35 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36 * copies of the Software, and to permit persons to whom the Software is
37 * furnished to do so, subject to the following conditions:
38 *
39 * The above copyright notice and this permission notice shall be included in
40 * all copies or substantial portions of the Software.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48 * THE SOFTWARE.
49 */
50
51#pragma once
52
53#include <cassert>
54#include <cmath>
55#include <cstdint>
56#include <cstdio>
57#include <cstdlib>
58#include <initializer_list>
59#include <iosfwd>
60#include <limits>
61#include <map>
62#include <memory>
63#include <string>
64#include <type_traits>
65#include <utility>
66#include <vector>
67
68#ifdef _MSC_VER
69#pragma warning(push)
70#pragma warning(disable : 4244)
71#if _MSC_VER <= 1800 // VS 2013
72#ifndef noexcept
73#define noexcept throw()
74#endif
75
76#ifndef snprintf
77#define snprintf _snprintf_s
78#endif
79#endif
80#endif
81
82#if defined(__GNUC__) && (__GNUC__ >= 7)
83#pragma GCC diagnostic push
84#pragma GCC diagnostic ignored "-Woverloaded-virtual"
85#endif
86
87namespace json11 {
88
89enum JsonParse { STANDARD, COMMENTS };
90
91class JsonValue;
92
93class Json final {
94public:
95 // Types
96 enum Type { NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT };
97
98 // Array and object typedefs
99 using array = std::vector<Json>;
100 using object = std::map<std::string, Json>;
101
102 // Constructors for the various types of JSON value.
103 Json() noexcept; // NUL
104 Json(std::nullptr_t) noexcept; // NUL
105 Json(double value); // NUMBER
106 Json(long long value); // NUMBER
107 Json(bool value); // BOOL
108 Json(const std::string& value); // STRING
109 Json(std::string&& value); // STRING
110 Json(const char* value); // STRING
111 Json(const array& values); // ARRAY
112 Json(array&& values); // ARRAY
113 Json(const object& values); // OBJECT
114 Json(object&& values); // OBJECT
115
116 // Implicit constructor: anything with a to_json() function.
117 template <class T, class = decltype(&T::to_json)>
118 Json(const T& t) : Json(t.to_json()) {}
119
120 // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
121 template <class M,
122 typename std::enable_if<
123 std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value &&
124 std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
125 int>::type = 0>
126 Json(const M& m) : Json(object(m.begin(), m.end())) {}
127
128 // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
129 template <class V,
130 typename std::enable_if<std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
131 int>::type = 0>
132 Json(const V& v) : Json(array(v.begin(), v.end())) {}
133
134 // This prevents Json(some_pointer) from accidentally producing a bool. Use
135 // Json(bool(some_pointer)) if that behavior is desired.
136 Json(void*) = delete;
137
138 // Accessors
139 Type type() const;
140
141 bool is_null() const {
142 return type() == NUL;
143 }
144 bool is_number() const {
145 return type() == NUMBER;
146 }
147 bool is_bool() const {
148 return type() == BOOL;
149 }
150 bool is_string() const {
151 return type() == STRING;
152 }
153 bool is_array() const {
154 return type() == ARRAY;
155 }
156 bool is_object() const {
157 return type() == OBJECT;
158 }
159
160 // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
161 // distinguish between integer and non-integer numbers - number_value() and int_value()
162 // can both be applied to a NUMBER-typed object.
163 double number_value() const;
164 int int_value() const;
165 long long long_value() const;
166
167 // Return the enclosed value if this is a boolean, false otherwise.
168 bool bool_value() const;
169 // Return the enclosed string if this is a string, "" otherwise.
170 const std::string& string_value() const;
171 // Return the enclosed std::vector if this is an array, or an empty vector otherwise.
172 const array& array_items() const;
173 // Return the enclosed std::map if this is an object, or an empty map otherwise.
174 const object& object_items() const;
175
176 // Return a reference to arr[i] if this is an array, Json() otherwise.
177 const Json& operator[](std::size_t i) const;
178 // Return a reference to obj[key] if this is an object, Json() otherwise.
179 const Json& operator[](const std::string& key) const;
180
181 // Serialize.
182 void dump(std::string& out) const;
183 std::string dump() const {
184 std::string out;
185 dump(out);
186 return out;
187 }
188
189 // Parse. If parse fails, return Json() and assign an error message to err.
190 static Json parse(const std::string& in, std::string& err, JsonParse strategy = JsonParse::STANDARD);
191
192 static Json parse(const char* in, std::string& err, JsonParse strategy = JsonParse::STANDARD) {
193 if (in == nullptr) {
194 err = "null input";
195 return nullptr;
196 }
197 return parse(std::string(in), err, strategy);
198 }
199 // Parse multiple objects, concatenated or separated by whitespace
200 static std::vector<Json> parse_multi(const std::string& in, std::string::size_type& parser_stop_pos,
201 std::string& err, JsonParse strategy = JsonParse::STANDARD);
202
203 static inline std::vector<Json> parse_multi(
204 const std::string& in, std::string& err, JsonParse strategy = JsonParse::STANDARD) {
205 std::string::size_type parser_stop_pos;
206 return parse_multi(in, parser_stop_pos, err, strategy);
207 }
208
209 bool operator==(const Json& rhs) const;
210 bool operator<(const Json& rhs) const;
211 bool operator!=(const Json& rhs) const {
212 return !(*this == rhs);
213 }
214 bool operator<=(const Json& rhs) const {
215 return !(rhs < *this);
216 }
217 bool operator>(const Json& rhs) const {
218 return (rhs < *this);
219 }
220 bool operator>=(const Json& rhs) const {
221 return !(*this < rhs);
222 }
223
224 /* has_shape(types, err)
225 *
226 * Return true if this is a JSON object and, for each item in types, has a field of
227 * the given type. If not, return false and set err to a descriptive message.
228 */
229 using shape = std::initializer_list<std::pair<std::string, Type>>;
230 bool has_shape(const shape& types, std::string& err) const {
231 if (!is_object()) {
232 err = "expected JSON object, got " + dump();
233 return false;
234 }
235
236 for (auto& item : types) {
237 if ((*this)[item.first].type() != item.second) {
238 err = "bad type for " + item.first + " in " + dump();
239 return false;
240 }
241 }
242
243 return true;
244 }
245
246private:
247 std::shared_ptr<JsonValue> m_ptr;
248};
249
250// Internal class hierarchy - JsonValue objects are not exposed to users of this API.
251class JsonValue {
252protected:
253 friend class Json;
254 friend class JsonInt;
255 friend class JsonDouble;
256 virtual Json::Type type() const = 0;
257 virtual bool equals(const JsonValue* other) const = 0;
258 virtual bool less(const JsonValue* other) const = 0;
259 virtual void dump(std::string& out) const = 0;
260 virtual double number_value() const;
261 virtual int int_value() const;
262 virtual long long long_value() const;
263 virtual bool bool_value() const;
264 virtual const std::string& string_value() const;
265 virtual const Json::array& array_items() const;
266 virtual const Json& operator[](std::size_t i) const;
267 virtual const Json::object& object_items() const;
268 virtual const Json& operator[](const std::string& key) const;
269 virtual ~JsonValue() = default;
270};
271
272static const int max_depth = 200;
273
274/* Helper for representing null - just a do-nothing struct, plus comparison
275 * operators so the helpers in JsonValue work. We can't use nullptr_t because
276 * it may not be orderable.
277 */
278struct NullStruct {
279 bool operator==(NullStruct) const {
280 return true;
281 }
282 bool operator<(NullStruct) const {
283 return false;
284 }
285};
286
287/* * * * * * * * * * * * * * * * * * * *
288 * Serialization
289 */
290
291static void dump(NullStruct, std::string& out) {
292 out += "null";
293}
294
295static void dump(double value, std::string& out) {
296 if (std::isfinite(value)) {
297 char buf[32];
298 snprintf(buf, sizeof buf, "%.17g", value);
299 out += buf;
300 } else {
301 out += "null";
302 }
303}
304
305static void dump(long long value, std::string& out) {
306 char buf[32];
307 snprintf(buf, sizeof buf, "%lld", value);
308 out += buf;
309}
310
311static void dump(bool value, std::string& out) {
312 out += value ? "true" : "false";
313}
314
315static void dump(const std::string& value, std::string& out) {
316 out += '"';
317 for (std::size_t i = 0; i < value.length(); i++) {
318 const char ch = value[i];
319 if (ch == '\\') {
320 out += "\\\\";
321 } else if (ch == '"') {
322 out += "\\\"";
323 } else if (ch == '\b') {
324 out += "\\b";
325 } else if (ch == '\f') {
326 out += "\\f";
327 } else if (ch == '\n') {
328 out += "\\n";
329 } else if (ch == '\r') {
330 out += "\\r";
331 } else if (ch == '\t') {
332 out += "\\t";
333 } else if (static_cast<uint8_t>(ch) <= 0x1f) {
334 char buf[8];
335 snprintf(buf, sizeof buf, "\\u%04x", ch);
336 out += buf;
337 } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i + 1]) == 0x80 &&
338 static_cast<uint8_t>(value[i + 2]) == 0xa8) {
339 out += "\\u2028";
340 i += 2;
341 } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i + 1]) == 0x80 &&
342 static_cast<uint8_t>(value[i + 2]) == 0xa9) {
343 out += "\\u2029";
344 i += 2;
345 } else {
346 out += ch;
347 }
348 }
349 out += '"';
350}
351
352static void dump(const Json::array& values, std::string& out) {
353 bool first = true;
354 out += "[";
355 for (const auto& value : values) {
356 if (!first) out += ", ";
357 value.dump(out);
358 first = false;
359 }
360 out += "]";
361}
362
363static void dump(const Json::object& values, std::string& out) {
364 bool first = true;
365 out += "{";
366 for (const auto& kv : values) {
367 if (!first) out += ", ";
368 dump(kv.first, out);
369 out += ": ";
370 kv.second.dump(out);
371 first = false;
372 }
373 out += "}";
374}
375
376inline void Json::dump(std::string& out) const {
377 m_ptr->dump(out);
378}
379
380/* * * * * * * * * * * * * * * * * * * *
381 * Value wrappers
382 */
383
384template <Json::Type tag, typename T>
385class Value : public JsonValue {
386protected:
387 // Constructors
388 explicit Value(T value) : m_value(std::move(value)) {}
389
390 // Get type tag
391 Json::Type type() const override {
392 return tag;
393 }
394
395 // Comparisons
396 bool equals(const JsonValue* other) const override {
397 return m_value == static_cast<const Value<tag, T>*>(other)->m_value;
398 }
399 bool less(const JsonValue* other) const override {
400 return m_value < static_cast<const Value<tag, T>*>(other)->m_value;
401 }
402
403 const T m_value;
404 void dump(std::string& out) const override {
405 json11::dump(m_value, out);
406 }
407};
408
409class JsonDouble final : public Value<Json::NUMBER, double> {
410 double number_value() const override {
411 return m_value;
412 }
413 int int_value() const override {
414 return static_cast<int>(m_value);
415 }
416 long long long_value() const override {
417 return static_cast<long long>(m_value);
418 }
419 bool equals(const JsonValue* other) const override {
420 return m_value == other->number_value();
421 }
422 bool less(const JsonValue* other) const override {
423 return m_value < other->number_value();
424 }
425
426public:
427 explicit JsonDouble(double value) : Value(value) {}
428};
429
430class JsonInt final : public Value<Json::NUMBER, long long> {
431 double number_value() const override {
432 return m_value;
433 }
434 int int_value() const override {
435 return m_value;
436 }
437 long long long_value() const override {
438 return static_cast<long long>(m_value);
439 }
440 bool equals(const JsonValue* other) const override {
441 return m_value == other->number_value();
442 }
443 bool less(const JsonValue* other) const override {
444 return m_value < other->number_value();
445 }
446
447public:
448 explicit JsonInt(int value) : Value(value) {}
449};
450
451class JsonBoolean final : public Value<Json::BOOL, bool> {
452 bool bool_value() const override {
453 return m_value;
454 }
455
456public:
457 explicit JsonBoolean(bool value) : Value(value) {}
458};
459
460class JsonString final : public Value<Json::STRING, std::string> {
461 const std::string& string_value() const override {
462 return m_value;
463 }
464
465public:
466 explicit JsonString(const std::string& value) : Value(value) {}
467 explicit JsonString(std::string&& value) : Value(std::move(value)) {}
468};
469
470class JsonArray final : public Value<Json::ARRAY, Json::array> {
471 const Json::array& array_items() const override {
472 return m_value;
473 }
474 const Json& operator[](std::size_t i) const override;
475
476public:
477 explicit JsonArray(const Json::array& value) : Value(value) {}
478 explicit JsonArray(Json::array&& value) : Value(std::move(value)) {}
479};
480
481class JsonObject final : public Value<Json::OBJECT, Json::object> {
482 const Json::object& object_items() const override {
483 return m_value;
484 }
485 const Json& operator[](const std::string& key) const override;
486
487public:
488 explicit JsonObject(const Json::object& value) : Value(value) {}
489 explicit JsonObject(Json::object&& value) : Value(std::move(value)) {}
490};
491
492class JsonNull final : public Value<Json::NUL, NullStruct> {
493public:
494 JsonNull() : Value({}) {}
495};
496
497/* * * * * * * * * * * * * * * * * * * *
498 * Static globals - static-init-safe
499 */
500struct Statics {
501 const std::shared_ptr<JsonValue> null = std::make_shared<JsonNull>();
502 const std::shared_ptr<JsonValue> t = std::make_shared<JsonBoolean>(true);
503 const std::shared_ptr<JsonValue> f = std::make_shared<JsonBoolean>(false);
504 const std::string empty_string{};
505 const std::vector<Json> empty_vector{};
506 const std::map<std::string, Json> empty_map{};
507 Statics() = default;
508};
509
510static const Statics& statics() {
511 static const Statics s{};
512 return s;
513}
514
515static const Json& static_null() {
516 // This has to be separate, not in Statics, because Json() accesses statics().null.
517 static const Json json_null;
518 return json_null;
519}
520
521/* * * * * * * * * * * * * * * * * * * *
522 * Constructors
523 */
524
525inline Json::Json() noexcept : m_ptr(statics().null) {}
526inline Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
527inline Json::Json(double value) : m_ptr(std::make_shared<JsonDouble>(value)) {}
528inline Json::Json(long long value) : m_ptr(std::make_shared<JsonInt>(value)) {}
529inline Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
530inline Json::Json(const std::string& value) : m_ptr(std::make_shared<JsonString>(value)) {}
531inline Json::Json(std::string&& value) : m_ptr(std::make_shared<JsonString>(std::move(value))) {}
532inline Json::Json(const char* value) : m_ptr(std::make_shared<JsonString>(value)) {}
533inline Json::Json(const Json::array& values) : m_ptr(std::make_shared<JsonArray>(values)) {}
534inline Json::Json(Json::array&& values) : m_ptr(std::make_shared<JsonArray>(std::move(values))) {}
535inline Json::Json(const Json::object& values) : m_ptr(std::make_shared<JsonObject>(values)) {}
536inline Json::Json(Json::object&& values) : m_ptr(std::make_shared<JsonObject>(std::move(values))) {}
537
538/* * * * * * * * * * * * * * * * * * * *
539 * Accessors
540 */
541
542inline Json::Type Json::type() const {
543 return m_ptr->type();
544}
545inline double Json::number_value() const {
546 return m_ptr->number_value();
547}
548inline int Json::int_value() const {
549 return m_ptr->int_value();
550}
551inline long long Json::long_value() const {
552 return m_ptr->long_value();
553}
554inline bool Json::bool_value() const {
555 return m_ptr->bool_value();
556}
557inline const std::string& Json::string_value() const {
558 return m_ptr->string_value();
559}
560inline const std::vector<Json>& Json::array_items() const {
561 return m_ptr->array_items();
562}
563inline const std::map<std::string, Json>& Json::object_items() const {
564 return m_ptr->object_items();
565}
566inline const Json& Json::operator[](std::size_t i) const {
567 return (*m_ptr)[i];
568}
569inline const Json& Json::operator[](const std::string& key) const {
570 return (*m_ptr)[key];
571}
572
573inline double JsonValue::number_value() const {
574 return 0;
575}
576inline int JsonValue::int_value() const {
577 return 0;
578}
579inline long long JsonValue::long_value() const {
580 return 0;
581}
582inline bool JsonValue::bool_value() const {
583 return false;
584}
585inline const std::string& JsonValue::string_value() const {
586 return statics().empty_string;
587}
588inline const std::vector<Json>& JsonValue::array_items() const {
589 return statics().empty_vector;
590}
591inline const std::map<std::string, Json>& JsonValue::object_items() const {
592 return statics().empty_map;
593}
594inline const Json& JsonValue::operator[](std::size_t) const {
595 return static_null();
596}
597inline const Json& JsonValue::operator[](const std::string&) const {
598 return static_null();
599}
600
601inline const Json& JsonObject::operator[](const std::string& key) const {
602 auto iter = m_value.find(key);
603 return (iter == m_value.end()) ? static_null() : iter->second;
604}
605inline const Json& JsonArray::operator[](std::size_t i) const {
606 if (i >= m_value.size()) {
607 return static_null();
608 }
609 return m_value[i];
610}
611
612/* * * * * * * * * * * * * * * * * * * *
613 * Comparison
614 */
615
616inline bool Json::operator==(const Json& other) const {
617 if (m_ptr == other.m_ptr) {
618 return true;
619 }
620 if (m_ptr->type() != other.m_ptr->type()) {
621 return false;
622 }
623
624 return m_ptr->equals(other.m_ptr.get());
625}
626
627inline bool Json::operator<(const Json& other) const {
628 if (m_ptr == other.m_ptr) {
629 return false;
630 }
631 if (m_ptr->type() != other.m_ptr->type()) {
632 return m_ptr->type() < other.m_ptr->type();
633 }
634
635 return m_ptr->less(other.m_ptr.get());
636}
637
638/* * * * * * * * * * * * * * * * * * * *
639 * Parsing
640 */
641
642/* esc(c)
643 *
644 * Format char c suitable for printing in an error message.
645 */
646static inline std::string esc(char c) {
647 char buf[12];
648 if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
649 snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
650 } else {
651 snprintf(buf, sizeof buf, "(%d)", c);
652 }
653 return std::string(buf);
654}
655
656static inline bool in_range(long x, long lower, long upper) {
657 return (x >= lower && x <= upper);
658}
659
660namespace {
661/* JsonParser
662 *
663 * Object that tracks all state of an in-progress parse.
664 */
665struct JsonParser final {
666 /* State
667 */
668 const std::string& str;
669 std::size_t i;
670 std::string& err;
671 bool failed;
672 const JsonParse strategy;
673
674 /* fail(msg, err_ret = Json())
675 *
676 * Mark this parse as failed.
677 */
678 Json fail(std::string&& msg) {
679 return fail(std::move(msg), Json());
680 }
681
682 template <typename T>
683 T fail(std::string&& msg, T err_ret) {
684 if (!failed) {
685 err = std::move(msg);
686 }
687 failed = true;
688 return err_ret;
689 }
690
691 /* consume_whitespace()
692 *
693 * Advance until the current character is non-whitespace.
694 */
695 void consume_whitespace() {
696 while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') {
697 i++;
698 }
699 }
700
701 /* consume_comment()
702 *
703 * Advance comments (c-style inline and multiline).
704 */
705 bool consume_comment() {
706 bool comment_found = false;
707 if (str[i] == '/') {
708 i++;
709 if (i == str.size()) {
710 return fail("unexpected end of input after start of comment", false);
711 }
712 if (str[i] == '/') { // inline comment
713 i++;
714 // advance until next line, or end of input
715 while (i < str.size() && str[i] != '\n') {
716 i++;
717 }
718 comment_found = true;
719 } else if (str[i] == '*') { // multiline comment
720 i++;
721 if (i > str.size() - 2)
722 return fail("unexpected end of input inside multi-line comment", false);
723 // advance until closing tokens
724 while (!(str[i] == '*' && str[i + 1] == '/')) {
725 i++;
726 if (i > str.size() - 2)
727 return fail("unexpected end of input inside multi-line comment", false);
728 }
729 i += 2;
730 comment_found = true;
731 } else {
732 return fail("malformed comment", false);
733 }
734 }
735 return comment_found;
736 }
737
738 /* consume_garbage()
739 *
740 * Advance until the current character is non-whitespace and non-comment.
741 */
742 void consume_garbage() {
743 consume_whitespace();
744 if (strategy == JsonParse::COMMENTS) {
745 bool comment_found = false;
746 do {
747 comment_found = consume_comment();
748 if (failed) {
749 return;
750 }
751 consume_whitespace();
752 } while (comment_found);
753 }
754 }
755
756 /* get_next_token()
757 *
758 * Return the next non-whitespace character. If the end of the input is reached,
759 * flag an error and return 0.
760 */
761 char get_next_token() {
762 consume_garbage();
763 if (failed) {
764 return static_cast<char>(0);
765 }
766 if (i == str.size()) {
767 return fail("unexpected end of input", static_cast<char>(0));
768 }
769
770 return str[i++];
771 }
772
773 /* encode_utf8(pt, out)
774 *
775 * Encode pt as UTF-8 and add it to out.
776 */
777 void encode_utf8(long pt, std::string& out) {
778 if (pt < 0) {
779 return;
780 }
781
782 if (pt < 0x80) {
783 out += static_cast<char>(pt);
784 } else if (pt < 0x800) {
785 out += static_cast<char>((pt >> 6) | 0xC0);
786 out += static_cast<char>((pt & 0x3F) | 0x80);
787 } else if (pt < 0x10000) {
788 out += static_cast<char>((pt >> 12) | 0xE0);
789 out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
790 out += static_cast<char>((pt & 0x3F) | 0x80);
791 } else {
792 out += static_cast<char>((pt >> 18) | 0xF0);
793 out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
794 out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
795 out += static_cast<char>((pt & 0x3F) | 0x80);
796 }
797 }
798
799 /* parse_string()
800 *
801 * Parse a std::string, starting at the current position.
802 */
803 std::string parse_string() {
804 std::string out;
805 long last_escaped_codepoint = -1;
806 while (true) {
807 if (i == str.size()) return fail("unexpected end of input in std::string", "");
808
809 char ch = str[i++];
810
811 if (ch == '"') {
812 encode_utf8(last_escaped_codepoint, out);
813 return out;
814 }
815
816 if (in_range(ch, 0, 0x1f)) {
817 return fail("unescaped " + esc(ch) + " in std::string", "");
818 }
819
820 // The usual case: non-escaped characters
821 if (ch != '\\') {
822 encode_utf8(last_escaped_codepoint, out);
823 last_escaped_codepoint = -1;
824 out += ch;
825 continue;
826 }
827
828 // Handle escapes
829 if (i == str.size()) {
830 return fail("unexpected end of input in std::string", "");
831 }
832
833 ch = str[i++];
834
835 if (ch == 'u') {
836 // Extract 4-byte escape sequence
837 std::string esc = str.substr(i, 4);
838 // Explicitly check length of the substring. The following loop
839 // relies on std::string returning the terminating NUL when
840 // accessing str[length]. Checking here reduces brittleness.
841 if (esc.length() < 4) {
842 return fail("bad \\u escape: " + esc, "");
843 }
844 for (std::size_t j = 0; j < 4; j++) {
845 if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') &&
846 !in_range(esc[j], '0', '9'))
847 return fail("bad \\u escape: " + esc, "");
848 }
849
850 long codepoint = strtol(esc.data(), nullptr, 16);
851
852 // JSON specifies that characters outside the BMP shall be encoded as a pair
853 // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
854 // whether we're in the middle of such a beast: the previous codepoint was an
855 // escaped lead (high) surrogate, and this is a trail (low) surrogate.
856 if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && in_range(codepoint, 0xDC00, 0xDFFF)) {
857 // Reassemble the two surrogate pairs into one astral-plane character, per
858 // the UTF-16 algorithm.
859 encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | (codepoint - 0xDC00)) + 0x10000,
860 out);
861 last_escaped_codepoint = -1;
862 } else {
863 encode_utf8(last_escaped_codepoint, out);
864 last_escaped_codepoint = codepoint;
865 }
866
867 i += 4;
868 continue;
869 }
870
871 encode_utf8(last_escaped_codepoint, out);
872 last_escaped_codepoint = -1;
873
874 if (ch == 'b') {
875 out += '\b';
876 } else if (ch == 'f') {
877 out += '\f';
878 } else if (ch == 'n') {
879 out += '\n';
880 } else if (ch == 'r') {
881 out += '\r';
882 } else if (ch == 't') {
883 out += '\t';
884 } else if (ch == '"' || ch == '\\' || ch == '/') {
885 out += ch;
886 } else {
887 return fail("invalid escape character " + esc(ch), "");
888 }
889 }
890 }
891
892 /* parse_number()
893 *
894 * Parse a double.
895 */
896 Json parse_number() {
897 std::size_t start_pos = i;
898
899 if (str[i] == '-') {
900 i++;
901 }
902
903 // Integer part
904 if (str[i] == '0') {
905 i++;
906 if (in_range(str[i], '0', '9')) {
907 return fail("leading 0s not permitted in numbers");
908 }
909 } else if (in_range(str[i], '1', '9')) {
910 i++;
911 while (in_range(str[i], '0', '9')) {
912 i++;
913 }
914 } else {
915 return fail("invalid " + esc(str[i]) + " in number");
916 }
917
918 if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' &&
919 (i - start_pos) <= static_cast<std::size_t>(std::numeric_limits<int>::digits10)) {
920 return std::atoll(str.c_str() + start_pos);
921 }
922
923 // Decimal part
924 if (str[i] == '.') {
925 i++;
926 if (!in_range(str[i], '0', '9')) {
927 return fail("at least one digit required in fractional part");
928 }
929
930 while (in_range(str[i], '0', '9')) {
931 i++;
932 }
933 }
934
935 // Exponent part
936 if (str[i] == 'e' || str[i] == 'E') {
937 i++;
938
939 if (str[i] == '+' || str[i] == '-') {
940 i++;
941 }
942
943 if (!in_range(str[i], '0', '9')) {
944 return fail("at least one digit required in exponent");
945 }
946
947 while (in_range(str[i], '0', '9')) {
948 i++;
949 }
950 }
951
952 return std::strtod(str.c_str() + start_pos, nullptr);
953 }
954
955 /* expect(str, res)
956 *
957 * Expect that 'str' starts at the character that was just read. If it does, advance
958 * the input and return res. If not, flag an error.
959 */
960 Json expect(const std::string& expected, Json res) {
961 assert(i != 0);
962 i--;
963 if (str.compare(i, expected.length(), expected) == 0) {
964 i += expected.length();
965 return res;
966 } else {
967 return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
968 }
969 }
970
971 /* parse_json()
972 *
973 * Parse a JSON object.
974 */
975 Json parse_json(int depth) {
976 if (depth > max_depth) {
977 return fail("exceeded maximum nesting depth");
978 }
979
980 char ch = get_next_token();
981 if (failed) {
982 return Json();
983 }
984
985 if (ch == '-' || (ch >= '0' && ch <= '9')) {
986 i--;
987 return parse_number();
988 }
989
990 if (ch == 't') {
991 return expect("true", true);
992 }
993
994 if (ch == 'f') {
995 return expect("false", false);
996 }
997
998 if (ch == 'n') {
999 return expect("null", Json());
1000 }
1001
1002 if (ch == '"') {
1003 return parse_string();
1004 }
1005
1006 if (ch == '{') {
1007 std::map<std::string, Json> data;
1008 ch = get_next_token();
1009 if (ch == '}') {
1010 return data;
1011 }
1012
1013 while (true) {
1014 if (ch != '"') return fail("expected '\"' in object, got " + esc(ch));
1015
1016 std::string key = parse_string();
1017 if (failed) {
1018 return Json();
1019 }
1020
1021 ch = get_next_token();
1022 if (ch != ':') {
1023 return fail("expected ':' in object, got " + esc(ch));
1024 }
1025
1026 data[std::move(key)] = parse_json(depth + 1);
1027 if (failed) {
1028 return Json();
1029 }
1030
1031 ch = get_next_token();
1032 if (ch == '}') {
1033 break;
1034 }
1035 if (ch != ',') {
1036 return fail("expected ',' in object, got " + esc(ch));
1037 }
1038
1039 ch = get_next_token();
1040 }
1041 return data;
1042 }
1043
1044 if (ch == '[') {
1045 std::vector<Json> data;
1046 ch = get_next_token();
1047 if (ch == ']') {
1048 return data;
1049 }
1050
1051 while (true) {
1052 i--;
1053 data.push_back(parse_json(depth + 1));
1054 if (failed) {
1055 return Json();
1056 }
1057
1058 ch = get_next_token();
1059 if (ch == ']') {
1060 break;
1061 }
1062 if (ch != ',') {
1063 return fail("expected ',' in list, got " + esc(ch));
1064 }
1065
1066 ch = get_next_token();
1067 (void)ch;
1068 }
1069 return data;
1070 }
1071
1072 return fail("expected value, got " + esc(ch));
1073 }
1074};
1075} // namespace
1076
1077inline Json Json::parse(const std::string& in, std::string& err, JsonParse strategy) {
1078 JsonParser parser{in, 0, err, false, strategy};
1079 Json result = parser.parse_json(0);
1080
1081 // Check for any trailing garbage
1082 parser.consume_garbage();
1083 if (parser.failed) {
1084 return Json();
1085 }
1086 if (parser.i != in.size()) {
1087 return parser.fail("unexpected trailing " + esc(in[parser.i]));
1088 }
1089
1090 return result;
1091}
1092
1093inline std::vector<Json> parse_multi(const std::string& in, std::string::size_type& parser_stop_pos,
1094 std::string& err, JsonParse strategy) {
1095 JsonParser parser{in, 0, err, false, strategy};
1096 parser_stop_pos = 0;
1097 std::vector<Json> json_vec;
1098 while (parser.i != in.size() && !parser.failed) {
1099 json_vec.push_back(parser.parse_json(0));
1100 if (parser.failed) {
1101 break;
1102 }
1103
1104 // Check for another object
1105 parser.consume_garbage();
1106 if (parser.failed) {
1107 break;
1108 }
1109 parser_stop_pos = parser.i;
1110 }
1111 return json_vec;
1112}
1113
1114#ifdef _MSC_VER
1115#pragma warning(pop)
1116#endif // _MSC_VER
1117
1118} // namespace json11
1119
1120#if defined(__GNUC__) && (__GNUC__ >= 7)
1121#pragma GCC diagnostic pop
1122#endif