1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef API_CORE_JSON_JSON_H
17 #define API_CORE_JSON_JSON_H
18
19 #include <cstdint>
20 #include <cstdio>
21 #include <securec.h>
22
23 #include <base/containers/fixed_string.h>
24 #include <base/containers/string.h>
25 #include <base/containers/string_view.h>
26 #include <base/containers/vector.h>
27 #include <base/util/uid.h>
28 #include <core/namespace.h>
29
CORE_BEGIN_NAMESPACE()30 CORE_BEGIN_NAMESPACE()
31 namespace json {
32 using readonly_string_t = BASE_NS::string_view;
33 using writable_string_t = BASE_NS::string;
34 template<typename T>
35 using array_t = BASE_NS::vector<T>;
36
37 /** Type of a JSON value. */
38 enum class type : uint8_t {
39 uninitialized = 0,
40 object,
41 array,
42 string,
43 floating_point,
44 signed_int,
45 unsigned_int,
46 boolean,
47 null,
48 };
49
50 /** Tag for JSON values which contain read-only strings. The source JSON string must be kept alive until the parsing
51 * results are not used. */
52 struct readonly_tag {};
53
54 /** Tag for JSON values which contain writable strings. Life time of the parsing results doens't depend on the source
55 * JSON string. */
56 struct writable_tag {};
57
58 template<typename T = readonly_tag>
59 struct value_t;
60
61 /** JSON structure which contains read-only strings. The source JSON string must be kept alive until the parsing
62 * results are not used. */
63 using value = value_t<readonly_tag>;
64
65 /** JSON structure which contains writable strings. String values can be modified and if the instance was generated by
66 * the parser, the source string doesn't need to be stored while the instance is used. */
67 using standalone_value = value_t<writable_tag>;
68
69 /** Parses 'data' and returns JSON structure. the value::type will be 'uninitialized' if parsing failed.
70 * @param data JSON as a null terminated string.
71 * @return Parsed JSON structure.
72 */
73 template<typename T = readonly_tag>
74 value_t<T> parse(const char* data);
75
76 /** Converts a JSON structure into a string.
77 * @param value JSON structure.
78 * @return JSON as string.
79 */
80 template<typename T = readonly_tag>
81 BASE_NS::string to_string(const value_t<T>& value);
82
83 BASE_NS::string unescape(BASE_NS::string_view str);
84 /** JSON value. */
85 template<typename Tag>
86 struct value_t {
87 /** Type used for JSON strings and JSON object keys. */
88 using string =
89 typename BASE_NS::conditional_t<BASE_NS::is_same_v<Tag, writable_tag>, writable_string_t, readonly_string_t>;
90
91 /** Type used for JSON null */
92 struct null {};
93
94 /** Type used for key-value pairs inside JSON objects. */
95 struct pair {
96 pair(string&& k, value_t&& v) : key(BASE_NS::forward<string>(k)), value(BASE_NS::forward<value_t>(v)) {}
97 string key;
98 value_t value;
99 };
100
101 /** Type used for JSON objects. */
102 using object = array_t<pair>;
103
104 /** Type used for JSON arrays. */
105 using array = array_t<value_t>;
106
107 /** Type of this JSON value. */
108 type type { type::uninitialized };
109 union {
110 object object_;
111 array array_;
112 string string_;
113 double float_;
114 int64_t signed_;
115 uint64_t unsigned_;
116 bool boolean_;
117 };
118
119 value_t() noexcept : type { type::uninitialized } {}
120
121 value_t(object&& value) noexcept : type { type::object }, object_(BASE_NS::move(value)) {}
122
123 value_t(array&& value) noexcept : type { type::array }, array_(BASE_NS::move(value)) {}
124
125 value_t(string value) noexcept : type { type::string }, string_(value) {}
126
127 value_t(const char* value) noexcept : value_t(string(value)) {}
128
129 explicit value_t(bool value) noexcept : type { type::boolean }, boolean_(value) {}
130
131 value_t(null value) noexcept : type { type::null } {}
132
133 template<typename Number, BASE_NS::enable_if_t<BASE_NS::is_floating_point_v<Number>, bool> = true>
134 value_t(Number value) noexcept : type { type::floating_point }, float_(static_cast<double>(value))
135 {}
136
137 template<typename Number,
138 BASE_NS::enable_if_t<!BASE_NS::is_floating_point_v<Number> && BASE_NS::is_signed_v<Number>, bool> = true>
139 value_t(Number value) noexcept : type { type::signed_int }, signed_(static_cast<int64_t>(value))
140 {}
141
142 template<typename Number, BASE_NS::enable_if_t<BASE_NS::is_unsigned_v<Number>, bool> = true>
143 value_t(Number value) noexcept : type { type::unsigned_int }, unsigned_(static_cast<uint64_t>(value))
144 {}
145
146 template<typename Value>
147 value_t(array_t<Value> values) noexcept : type { type::array }, array_(array {})
148 {
149 array_.reserve(values.size());
150 for (const auto& value : values) {
151 array_.emplace_back(value);
152 }
153 }
154
155 template<typename Value, size_t N>
156 value_t(Value (&value)[N]) : type { type::array }, array_(array {})
157 {
158 array_.reserve(N);
159 for (size_t i = 0; i < N; ++i) {
160 array_.emplace_back(value[i]);
161 }
162 }
163
164 template<typename OtherT>
165 value_t(const value_t<OtherT>& other) : type(other.type)
166 {
167 switch (type) {
168 case type::uninitialized:
169 break;
170 case type::object:
171 new (&object_) object(BASE_NS::default_allocator());
172 object_.reserve(other.object_.size());
173 for (const auto& p : other.object_) {
174 object_.push_back({ string(p.key), p.value });
175 }
176 break;
177 case type::array:
178 new (&array_) array(BASE_NS::default_allocator());
179 array_.reserve(other.array_.size());
180 for (const auto& v : other.array_) {
181 array_.emplace_back(v);
182 }
183 break;
184 case type::string:
185 new (&string_) string;
186 string_ = other.string_;
187 break;
188 case type::floating_point:
189 float_ = other.float_;
190 break;
191 case type::signed_int:
192 signed_ = other.signed_;
193 break;
194 case type::unsigned_int:
195 unsigned_ = other.unsigned_;
196 break;
197 case type::boolean:
198 boolean_ = other.boolean_;
199 break;
200 case type::null:
201 break;
202 default:
203 break;
204 }
205 }
206
207 value_t(value_t&& rhs) : type { BASE_NS::exchange(rhs.type, type::uninitialized) }
208 {
209 switch (type) {
210 case type::uninitialized:
211 break;
212 case type::object:
213 new (&object_) object(BASE_NS::move(rhs.object_));
214 break;
215 case type::array:
216 new (&array_) array(BASE_NS::move(rhs.array_));
217 break;
218 case type::string:
219 new (&string_) string(BASE_NS::move(rhs.string_));
220 break;
221 case type::floating_point:
222 float_ = rhs.float_;
223 break;
224 case type::signed_int:
225 signed_ = rhs.signed_;
226 break;
227 case type::unsigned_int:
228 unsigned_ = rhs.unsigned_;
229 break;
230 case type::boolean:
231 boolean_ = rhs.boolean_;
232 break;
233 case type::null:
234 break;
235 default:
236 break;
237 }
238 }
239
240 value_t& operator=(value_t&& rhs)
241 {
242 if (this != &rhs) {
243 cleanup();
244 type = BASE_NS::exchange(rhs.type, type::uninitialized);
245 switch (type) {
246 case type::uninitialized:
247 break;
248 case type::object:
249 new (&object_) object(BASE_NS::move(rhs.object_));
250 break;
251 case type::array:
252 new (&array_) array(BASE_NS::move(rhs.array_));
253 break;
254 case type::string:
255 new (&string_) string(BASE_NS::move(rhs.string_));
256 break;
257 case type::floating_point:
258 float_ = rhs.float_;
259 break;
260 case type::signed_int:
261 signed_ = rhs.signed_;
262 break;
263 case type::unsigned_int:
264 unsigned_ = rhs.unsigned_;
265 break;
266 case type::boolean:
267 boolean_ = rhs.boolean_;
268 break;
269 case type::null:
270 break;
271 default:
272 break;
273 }
274 }
275 return *this;
276 }
277
278 #if _MSC_VER
279 #pragma warning(push)
280 #pragma warning(disable : 4583)
281 #endif
282 ~value_t()
283 {
284 cleanup();
285 }
286 #if _MSC_VER
287 #pragma warning(pop)
288 #endif
289 template<typename T>
290 inline void destroy(T& t)
291 {
292 t.~T();
293 }
294
295 void cleanup()
296 {
297 switch (type) {
298 case type::uninitialized:
299 break;
300 case type::object:
301 destroy(object_);
302 break;
303 case type::array:
304 destroy(array_);
305 break;
306 case type::string:
307 destroy(string_);
308 break;
309 case type::floating_point:
310 break;
311 case type::signed_int:
312 break;
313 case type::unsigned_int:
314 break;
315 case type::boolean:
316 break;
317 case type::null:
318 break;
319 default:
320 break;
321 }
322 }
323
324 explicit operator bool() const noexcept
325 {
326 return type != type::uninitialized;
327 }
328
329 bool is_object() const noexcept
330 {
331 return type == type::object;
332 }
333
334 bool is_array() const noexcept
335 {
336 return type == type::array;
337 }
338
339 bool is_string() const noexcept
340 {
341 return type == type::string;
342 }
343
344 bool is_floating_point() const noexcept
345 {
346 return type == type::floating_point;
347 }
348
349 bool is_signed_int() const noexcept
350 {
351 return type == type::signed_int;
352 }
353
354 bool is_unsigned_int() const noexcept
355 {
356 return type == type::unsigned_int;
357 }
358
359 bool is_number() const noexcept
360 {
361 return type == type::floating_point || type == type::signed_int || type == type::unsigned_int;
362 }
363
364 bool is_boolean() const noexcept
365 {
366 return type == type::boolean;
367 }
368
369 bool is_null() const noexcept
370 {
371 return type == type::null;
372 }
373
374 bool empty() const noexcept
375 {
376 if (is_object()) {
377 return object_.empty();
378 } else if (is_array()) {
379 return array_.empty();
380 }
381 return true;
382 }
383
384 template<typename T>
385 T as_number() const
386 {
387 switch (type) {
388 case type::floating_point:
389 return static_cast<T>(float_);
390 case type::signed_int:
391 return static_cast<T>(signed_);
392 case type::unsigned_int:
393 return static_cast<T>(unsigned_);
394 default:
395 return 0;
396 }
397 }
398
399 const value_t* find(BASE_NS::string_view key) const noexcept
400 {
401 if (type == type::object) {
402 for (auto& t : object_) {
403 if (t.key == key) {
404 return &t.value;
405 }
406 }
407 }
408 return nullptr;
409 }
410
411 value_t& operator[](const BASE_NS::string_view& key)
412 {
413 if (type == type::object) {
414 for (auto& t : object_) {
415 if (t.key == key) {
416 return t.value;
417 }
418 }
419 object_.emplace_back(value_t<Tag>::string(key), value_t<Tag> {});
420 return object_.back().value;
421 }
422 return *this;
423 }
424 };
425
426 #ifdef JSON_IMPL
427 inline bool isWhite(char data)
428 {
429 return ((data == ' ') || (data == '\n') || (data == '\r') || (data == '\t'));
430 }
431
432 inline bool isSign(char data)
433 {
434 return ((data == '+') || (data == '-'));
435 }
436
437 inline bool isDigit(char data)
438 {
439 return ((data >= '0') && (data <= '9'));
440 }
441
442 inline bool isHex(char data)
443 {
444 return ((data >= '0') && (data <= '9')) || ((data >= 'a') && (data <= 'f')) || ((data >= 'A') && (data <= 'F'));
445 }
446
447 inline const char* trim(const char* data)
448 {
449 while (*data && isWhite(*data)) {
450 data++;
451 }
452 return data;
453 }
454
455 // values
456 template<typename T>
457 const char* parse_string(const char* data, value_t<T>& res)
458 {
459 const char* start = data;
460 for (; *data != 0; data++) {
461 if (*data == '\\' && data[1]) {
462 // escape.. (parse just enough to not stop too early)
463 if (data[1] == '\\' || data[1] == '"' || data[1] == '/' || data[1] == 'b' || data[1] == 'f' ||
464 data[1] == 'n' || data[1] == 'r' || data[1] == 't') {
465 ++data;
466 continue;
467 } else if (data[1] == 'u') {
468 data += 2;
469 for (const char* end = data + 4; data != end; ++data) {
470 if (*data == 0 || !isHex(*data)) {
471 // invalid Unicode
472 return data;
473 }
474 }
475 --data;
476 } else {
477 // invalid escape
478 return data;
479 }
480 } else if (*data == '"') {
481 res = value_t<T> { typename value_t<T>::string { start, static_cast<size_t>(data - start) } };
482 return data + 1;
483 } else if (static_cast<unsigned char>(*data) < 0x20) {
484 // unescaped control
485 return data;
486 }
487 }
488 return data;
489 }
490
491 template<typename T>
492 const char* parse_number(const char* data, value_t<T>& res)
493 {
494 bool negative = false;
495 const char* beg = data;
496 if (*data == '-') {
497 negative = true;
498 data++;
499 if (!isDigit(*data)) {
500 // no digits after '-'
501 return data;
502 }
503 }
504 bool fraction = false;
505 bool exponent = false;
506
507 if (*data == '0') {
508 ++data;
509 // after leading zero only '.', 'e' and 'E' allowed
510 if (*data == '.') {
511 ++data;
512 fraction = true;
513 } else if (*data == 'e' || *data == 'E') {
514 ++data;
515 exponent = true;
516 }
517 } else {
518 while (isDigit(*data)) {
519 ++data;
520 }
521 if (*data == '.') {
522 ++data;
523 fraction = true;
524 } else if (*data == 'e' || *data == 'E') {
525 ++data;
526 exponent = true;
527 }
528 }
529
530 if (fraction) {
531 // fraction must start with a digit
532 if (isDigit(*data)) {
533 ++data;
534 } else {
535 // fraction missing first digit
536 return data;
537 }
538 // fraction may contain digits up to begining of exponent ('e' or 'E')
539 while (isDigit(*data)) {
540 ++data;
541 }
542 if (*data == 'e' || *data == 'E') {
543 ++data;
544 exponent = true;
545 }
546 }
547 if (exponent) {
548 // exponent must start with '-' or '+' followed by a digit, or digit
549 if (*data == '-' || *data == '+') {
550 ++data;
551 }
552 if (isDigit(*data)) {
553 ++data;
554 } else {
555 // exponent missing first digit
556 return data;
557 }
558 while (isDigit(*data)) {
559 ++data;
560 }
561 }
562 if (data != beg) {
563 char* end;
564 if (fraction || exponent) {
565 res = value(strtod(beg, &end));
566 } else if (negative) {
567 res = value(strtoll(beg, &end, 10));
568 } else {
569 res = value(strtoull(beg, &end, 10));
570 }
571 return data;
572 }
573 // invalid json
574 return data;
575 }
576
577 template<typename T>
578 const char* parse_boolean(const char* data, value_t<T>& res)
579 {
580 if (*data == 't') {
581 ++data;
582 const char rue[] = { 'r', 'u', 'e' };
583 for (unsigned i = 0u; i < sizeof(rue); ++i) {
584 if (data[i] == 0 || data[i] != rue[i]) {
585 // non-string starting with 't' but != "true"
586 return data;
587 }
588 }
589
590 res = value(true);
591 data += sizeof(rue);
592 } else if (*data == 'f') {
593 ++data;
594 const char alse[] = { 'a', 'l', 's', 'e' };
595 for (unsigned i = 0u; i < sizeof(alse); ++i) {
596 if (data[i] == 0 || data[i] != alse[i]) {
597 // non-string starting with 'f' but != "false"
598 return data;
599 }
600 }
601 res = value(false);
602 data += sizeof(alse);
603 } else {
604 // non-string not starting with 'f' or 't'
605 return data;
606 }
607 return data;
608 }
609
610 template<typename T>
611 const char* parse_null(const char* data, value_t<T>& res)
612 {
613 if (*data == 'n') {
614 ++data;
615 const char ull[] = { 'u', 'l', 'l' };
616 for (unsigned i = 0u; i < sizeof(ull); ++i) {
617 if (data[i] == 0 || data[i] != ull[i]) {
618 // non-string starting with 'n' but != "null"
619 return data;
620 }
621 }
622 res = value(value::null {});
623 data += sizeof(ull);
624 } else {
625 // invalid json
626 return data;
627 }
628 return data;
629 }
630
631 template<typename T>
632 void add(value_t<T>& v, value_t<T>&& value)
633 {
634 switch (v.type) {
635 case type::uninitialized:
636 v = BASE_NS::move(value);
637 break;
638 case type::object:
639 v.object_.back().value = BASE_NS::move(value);
640 break;
641 case type::array:
642 v.array_.push_back(BASE_NS::move(value));
643 break;
644 case type::string:
645 case type::floating_point:
646 case type::signed_int:
647 case type::unsigned_int:
648 case type::boolean:
649 case type::null:
650 default:
651 break;
652 }
653 }
654
655 template<typename T>
656 value_t<T> parse(const char* data)
657 {
658 if (!data) {
659 return {};
660 }
661 using jsonValue = value_t<T>;
662 typename jsonValue::array stack;
663 // push an uninitialized value which will get the final value during parsing
664 stack.emplace_back();
665
666 bool acceptValue = true;
667 while (*data) {
668 data = trim(data);
669 if (*data == '{') {
670 // start of an object
671 if (!acceptValue) {
672 return {};
673 }
674 data = trim(data + 1);
675 if (*data == '}') {
676 data = trim(data + 1);
677 // handle empty object.
678 add(stack.back(), jsonValue(typename jsonValue::object {}));
679 acceptValue = false;
680 } else if (*data == '"') {
681 // try to read the key
682 jsonValue key;
683 data = trim(parse_string(data + 1, key));
684
685 if (*data != ':') {
686 // missing : after key
687 return {};
688 }
689 data = trim(data + 1);
690 // push the object with key and missing value on the stack and hope to find a value next
691 stack.emplace_back(typename jsonValue::object {})
692 .object_.emplace_back(BASE_NS::move(key.string_), jsonValue {});
693 acceptValue = true;
694 } else {
695 // missing start of key or end of object
696 return {};
697 }
698 } else if (*data == '}') {
699 // end of an object
700 if (stack.back().type != type::object) {
701 // unexpected }
702 return {};
703 }
704 // check are we missing a value ('{"":}', '{"":"",}' )
705 if (acceptValue) {
706 return {};
707 }
708 data = trim(data + 1);
709 // move this object to the next in the stack
710 auto value = BASE_NS::move(stack.back());
711 stack.pop_back();
712 if (stack.empty()) {
713 // invalid json
714 return {};
715 }
716 add(stack.back(), BASE_NS::move(value));
717 acceptValue = false;
718 } else if (*data == '[') {
719 // start of an array
720 if (!acceptValue) {
721 // unexpected [
722 return {};
723 }
724 data = trim(data + 1);
725 if (*data == ']') {
726 data = trim(data + 1);
727 // handle empty array.
728 add(stack.back(), jsonValue(typename jsonValue::array {}));
729 acceptValue = false;
730 } else {
731 // push the empty array on the stack and hope to find values
732 stack.emplace_back(typename jsonValue::array {});
733 acceptValue = true;
734 }
735 } else if (*data == ']') {
736 // end of an array
737 if (stack.back().type != type::array) {
738 // unexpected ]
739 return {};
740 }
741 // check are we missing a value ('[1,]' '[1]]')
742 if (acceptValue) {
743 // unexpected ]
744 return {};
745 }
746 data = trim(data + 1);
747
748 auto value = BASE_NS::move(stack.back());
749 stack.pop_back();
750 if (stack.empty()) {
751 // invalid json
752 return {};
753 }
754 add(stack.back(), BASE_NS::move(value));
755 acceptValue = false;
756 } else if (*data == ',') {
757 // comma is allowed when the previous value was complete and we have an incomplete object or array on the
758 // stack.
759 if (!acceptValue && stack.back().type == type::object) {
760 data = trim(data + 1);
761 if (*data != '"') {
762 // missing key for next object
763 return {};
764 }
765 // try to read the key
766 jsonValue key;
767 data = trim(parse_string(data + 1, key));
768
769 if (*data != ':') {
770 // missing value for next object
771 return {};
772 }
773 data = trim(data + 1);
774 stack.back().object_.emplace_back(BASE_NS::move(key.string_), jsonValue {});
775 acceptValue = true;
776 } else if (!acceptValue && stack.back().type == type::array) {
777 data = trim(data + 1);
778 acceptValue = true;
779 } else {
780 // comma allowed only between objects and values inside an array
781 return {};
782 }
783 } else if (*data == '"') {
784 jsonValue value;
785 data = trim(parse_string(data + 1, value));
786 if (acceptValue && value.type == type::string) {
787 add(stack.back(), BASE_NS::move(value));
788 acceptValue = false;
789 } else {
790 // unexpected "
791 return {};
792 }
793 } else if (isSign(*data) || isDigit(*data)) {
794 jsonValue value;
795 data = trim(parse_number(data, value));
796 if (acceptValue && value.type != type::uninitialized) {
797 add(stack.back(), BASE_NS::move(value));
798 acceptValue = false;
799 } else {
800 // failed parsing number
801 return {};
802 }
803 } else if ((*data == 't') || (*data == 'f')) {
804 jsonValue value;
805 data = trim(parse_boolean(data, value));
806 if (acceptValue && value.type == type::boolean) {
807 add(stack.back(), BASE_NS::move(value));
808 acceptValue = false;
809 } else {
810 // failed parsing boolean
811 return {};
812 }
813 } else if (*data == 'n') {
814 jsonValue value;
815 data = trim(parse_null(data, value));
816 if (acceptValue && value.type == type::null) {
817 add(stack.back(), BASE_NS::move(value));
818 acceptValue = false;
819 } else {
820 // failed parsing null
821 return {};
822 }
823 } else {
824 // unexpected character
825 return {};
826 }
827 }
828 // check if we are missing a value ('{"":' '[')
829 if (acceptValue) {
830 return {};
831 }
832
833 auto value = BASE_NS::move(stack.front());
834 return value;
835 }
836
837 template value parse(const char*);
838 template standalone_value parse(const char*);
839 // end of parser
840 template<typename T>
841 void append(BASE_NS::string& out, const typename value_t<T>::object& object)
842 {
843 out += '{';
844 int count = 0;
845 for (const auto& v : object) {
846 if (count++) {
847 out += ',';
848 }
849 out += '"';
850 out.append(v.key.data(), v.key.size());
851 out += '"';
852 out += ':';
853 out += to_string(v.value);
854 }
855 out += '}';
856 }
857
858 template<typename T>
859 void append(BASE_NS::string& out, const typename value_t<T>::array& array)
860 {
861 out += '[';
862 int count = 0;
863 for (const auto& v : array) {
864 if (count++) {
865 out += ',';
866 }
867 out += to_string(v);
868 }
869 out += ']';
870 }
871
872 template<typename T>
873 void append(BASE_NS::string& out, const typename value_t<T>::string& string)
874 {
875 out += '"';
876 out.append(string.data(), string.size());
877 out += '"';
878 }
879
880 template<typename T>
881 void append(BASE_NS::string& out, const double floatingPoint)
882 {
883 const char* FLOATING_FORMAT_STR = "%.17g";
884 // use snprintf to calculate the required size (not supported by the _s variant)
885 const int size = snprintf(nullptr, 0, FLOATING_FORMAT_STR, floatingPoint);
886 const size_t oldSize = out.size();
887 out.resize(oldSize + size);
888 const size_t newSize = out.size();
889 // "At most bufsz - 1 characters are written." string has size() characters + 1 for null so use size() +
890 // 1 as the total size. If resize() failed string size() hasn't changed, buffer will point to the null
891 // character and bufsz will be 1 i.e. only the null character will be written.
892 int ret = snprintf_s(out.data() + oldSize, newSize + 1 - oldSize, size, FLOATING_FORMAT_STR, floatingPoint);
893 if (ret < 0) {
894 return;
895 }
896 }
897
898 template<typename T>
899 BASE_NS::string to_string(const value_t<T>& value)
900 {
901 BASE_NS::string out;
902 switch (value.type) {
903 case type::uninitialized:
904 break;
905
906 case type::object:
907 append<T>(out, value.object_);
908 break;
909
910 case type::array:
911 append<T>(out, value.array_);
912 break;
913
914 case type::string:
915 append<T>(out, value.string_);
916 break;
917
918 case type::floating_point:
919 append<T>(out, value.float_);
920 break;
921
922 case type::signed_int:
923 out += BASE_NS::to_string(value.signed_);
924 break;
925
926 case type::unsigned_int:
927 out += BASE_NS::to_string(value.unsigned_);
928 break;
929
930 case type::boolean:
931 if (value.boolean_) {
932 out += "true";
933 } else {
934 out += "false";
935 }
936 break;
937
938 case type::null:
939 out += "null";
940 break;
941
942 default:
943 break;
944 }
945 return out;
946 }
947
948 template BASE_NS::string to_string(const value& value);
949 template BASE_NS::string to_string(const standalone_value& value);
950
951 int codepoint(BASE_NS::string_view str)
952 {
953 int code = 0;
954 for (size_t u = 0; u < 4; ++u) {
955 const char chr = str[u];
956 code <<= 4U;
957 code += BASE_NS::HexToDec(chr);
958 }
959 return code;
960 }
961
962 BASE_NS::string unescape(BASE_NS::string_view str)
963 {
964 BASE_NS::string unescaped;
965 unescaped.reserve(str.size());
966 for (size_t i = 0; i < str.size();) {
967 auto chr = str[i];
968 if (chr == '\\') {
969 ++i;
970 chr = str[i];
971 if (chr == '"') {
972 unescaped += '"'; // Quotation mark
973 } else if (chr == '\\') {
974 unescaped += '\\'; // Reverse solidus
975 } else if (chr == '/') {
976 unescaped += '/'; // Solidus.. we do unescape this..
977 } else if (chr == 'b') {
978 unescaped += '\b'; // Backspace
979 } else if (chr == 'f') {
980 unescaped += '\f'; // Formfeed
981 } else if (chr == 'n') {
982 unescaped += '\n'; // Linefeed
983 } else if (chr == 'r') {
984 unescaped += '\r'; // Carriage return
985 } else if (chr == 't') {
986 unescaped += '\t'; // Horizontal tab
987 } else if (chr == 'u') { // Unicode character
988 if ((i + 4U) < str.size()) { // Expecting 4 hexadecimal values
989 // Read the Unicode code point.
990 int code = codepoint(str.substr(i + 1, 4U));
991 i += 4U;
992 // Codepoints U+010000 to U+10FFFF are encoded as UTF-16 surrogate pairs. High surrogate between
993 // 0xD800-0xDBFF and low between 0xDC00-0xDFFF.
994 if (code >= 0xd800 && code <= 0xdbff) {
995 // See if there's an other \uXXXX value in the correct range.
996 if ((i + 6U) < str.size()) {
997 auto next = str.substr(i + 1, 6U);
998 if (next[0] == '\\' && next[1] == 'u') {
999 next.remove_prefix(2);
1000 int low = codepoint(next);
1001 i += 6U;
1002 if (low >= 0xdc00 && low <= 0xdfff) {
1003 // Surragete pair encoding: 0x10000 + (Hi - 0xD800) * 0x400 + (Lo - 0xDC00)
1004 code = (static_cast<unsigned>(code) << 10U) + static_cast<unsigned>(low) -
1005 ((0xd800 << 10U) + 0xdc00U - 0x10000U);
1006 }
1007 }
1008 }
1009 }
1010 // Convert code point to UTF-8.
1011 if (code < 0x80) {
1012 // 1-byte characters: 0xxxxxxx (ASCII)
1013 unescaped += static_cast<char>(code);
1014 } else if (code < 0x7ff) {
1015 // 2-byte characters: 110xxxxx 10xxxxxx
1016 unescaped += static_cast<char>(0xc0U | (static_cast<unsigned int>(code) >> 6U));
1017 unescaped += static_cast<char>(0x80U | (static_cast<unsigned int>(code) & 0x3fU));
1018 } else if (code <= 0xffff) {
1019 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
1020 unescaped += static_cast<char>(0xe0U | (static_cast<unsigned int>(code) >> 12u));
1021 unescaped += static_cast<char>(0x80U | ((static_cast<unsigned int>(code) >> 6U) & 0x3FU));
1022 unescaped += static_cast<char>(0x80U | (static_cast<unsigned int>(code) & 0x3Fu));
1023 } else {
1024 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1025 unescaped += (static_cast<char>(0xf0U | (static_cast<unsigned int>(code) >> 18U)));
1026 unescaped += (static_cast<char>(0x80U | ((static_cast<unsigned int>(code) >> 12U) & 0x3fU)));
1027 unescaped += (static_cast<char>(0x80U | ((static_cast<unsigned int>(code) >> 6U) & 0x3fU)));
1028 unescaped += (static_cast<char>(0x80U | (static_cast<unsigned int>(code) & 0x3fU)));
1029 }
1030 }
1031 } else {
1032 }
1033 ++i;
1034 } else {
1035 unescaped += chr;
1036 ++i;
1037 }
1038 }
1039 return unescaped;
1040 }
1041 #endif // JSON_IMPL
1042 } // namespace json
1043 CORE_END_NAMESPACE()
1044
1045 #endif // !API_CORE_JSON_JSON_H
1046