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 LUMEJSON_H
17 #define LUMEJSON_H
18 
19 #if defined __has_include
20 #if __has_include(<charconv>)
21 #define HAS_CHARCONV 1
22 #include <charconv>
23 #endif
24 #endif
25 
26 #ifndef JSON_STRING_TYPE
27 #include <string_view>
28 #endif // JSON_STRING_TYPE
29 #ifndef JSON_ARRAY_TYPE
30 #include <vector>
31 #endif // JSON_ARRAY_TYPE
32 
33 #include <string>
34 
35 namespace json {
36 #ifndef JSON_STRING_TYPE
37 using string_t = std::string_view;
38 #else
39 using string_t = JSON_STRING_TYPE;
40 #endif
41 
42 #ifndef JSON_ARRAY_TYPE
43 template<typename T>
44 using array_t = std::vector<T>;
45 #else
46 template<typename T>
47 using array_t = JSON_ARRAY_TYPE<T>;
48 #endif
49 
50 /// simple json parser parser
51 enum class type : char {
52     uninitialized = 0,
53     object,
54     array,
55     string,
56     number,
57     boolean,
58     null,
59 };
60 
61 struct value;
62 
63 // parses 'data' and writes the corresponding JSON structure to 'value'
64 char* parse_value(char* data, value& value);
65 
66 // parses 'data' and return JSON structure. the value::type will be 'uninitialized' if parsing failed.
67 value parse(char* data);
68 
69 std::string to_string(const value& value);
70 
71 struct pair;
72 
73 struct null {};
74 using object = array_t<pair>;
75 using array = array_t<value>;
76 using string = string_t;
77 
78 struct value {
79     type type{ type::uninitialized };
80     union {
81         object object_;
82         array array_;
83         string string_;
84         double number_;
85         bool boolean_;
86     };
87 
valuevalue88     value() : type{ type::uninitialized } {}
valuevalue89     value(object&& value) : type{ type::object }, object_(std::move(value)) {}
valuevalue90     value(array&& value) : type{ type::array }, array_(std::move(value)) {}
valuevalue91     value(string value) : type{ type::string }, string_(value) {}
valuevalue92     value(double value) : type{ type::number }, number_(value) {}
valuevalue93     explicit value(bool value) : type{ type::boolean }, boolean_(value) {}
valuevalue94     value(null value) : type{ type::null } {}
95 
96     template<typename T, std::enable_if_t<!std::is_same_v<T, bool> && std::is_arithmetic_v<T>, bool> = true>
valuevalue97     value(T value) : type{ type::number }, number_(static_cast<double>(value))
98     {}
99 
100     template<typename T>
valuevalue101     value(array_t<T> values) : type{ type::array }, array_(array{})
102     {
103         array_.reserve(values.size());
104         for (const auto& value : values) {
105             array_.push_back({ value });
106         }
107     }
108 
109     template<typename T, size_t N>
valuevalue110     value(T (&value)[N]) : type{ type::array }, array_(array{})
111     {
112         array_.reserve(N);
113         for (size_t i = 0; i < N; ++i) {
114             array_.push_back({ value[i] });
115         }
116     }
117 
valuevalue118     value(value&& rhs) : type{ std::exchange(rhs.type, type::uninitialized) }
119     {
120         switch (type) {
121             case type::uninitialized:
122                 break;
123             case type::object:
124                 new (&object_) object(std::move(rhs.object_));
125                 break;
126             case type::array:
127                 new (&array_) array(std::move(rhs.array_));
128                 break;
129             case type::string:
130                 new (&string_) string_t(std::move(rhs.string_));
131                 break;
132             case type::number:
133                 number_ = rhs.number_;
134                 break;
135             case type::boolean:
136                 boolean_ = rhs.boolean_;
137                 break;
138             case type::null:
139                 break;
140             default:
141                 break;
142         }
143     }
144 
145     value& operator=(value&& rhs)
146     {
147         if (this != &rhs) {
148             cleanup();
149             type = std::exchange(rhs.type, type::uninitialized);
150             switch (type) {
151                 case type::uninitialized:
152                     break;
153                 case type::object:
154                     new (&object_) object(std::move(rhs.object_));
155                     break;
156                 case type::array:
157                     new (&array_) array(std::move(rhs.array_));
158                     break;
159                 case type::string:
160                     new (&string_) string_t(std::move(rhs.string_));
161                     break;
162                 case type::number:
163                     number_ = rhs.number_;
164                     break;
165                 case type::boolean:
166                     boolean_ = rhs.boolean_;
167                     break;
168                 case type::null:
169                     break;
170                 default:
171                     break;
172             }
173         }
174         return *this;
175     }
176 
~valuevalue177     ~value()
178     {
179         cleanup();
180     }
181 
cleanupvalue182     void cleanup()
183     {
184         switch (type) {
185             case type::uninitialized:
186                 break;
187             case type::object:
188                 object_.~vector();
189                 break;
190             case type::array:
191                 array_.~vector();
192                 break;
193             case type::string:
194                 break;
195             case type::number:
196                 break;
197             case type::boolean:
198                 break;
199             case type::null:
200                 break;
201             default:
202                 break;
203         }
204     }
205 
is_objectvalue206     inline bool is_object() const noexcept
207     {
208         return type == type::object;
209     }
is_arrayvalue210     inline bool is_array() const noexcept
211     {
212         return type == type::array;
213     }
is_stringvalue214     inline bool is_string() const noexcept
215     {
216         return type == type::string;
217     }
is_numbervalue218     inline bool is_number() const noexcept
219     {
220         return type == type::number;
221     }
is_booleanvalue222     inline bool is_boolean() const noexcept
223     {
224         return type == type::boolean;
225     }
is_nullvalue226     inline bool is_null() const noexcept
227     {
228         return type == type::null;
229     }
230 
emptyvalue231     inline bool empty() const noexcept
232     {
233         if (is_object()) {
234             return object_.empty();
235         } else if (is_array()) {
236             return array_.empty();
237         }
238         return true;
239     }
240 
241     const value* find(string_t key) const noexcept;
242 
243     value& operator[](const string_t& key);
244 };
245 
246 struct pair {
247     string_t key;
248     value value;
249 };
250 
find(string_t key)251 inline const value* value::find(string_t key) const noexcept
252 {
253     if (type == type::object) {
254         for (auto& t : object_) {
255             if (t.key == key) {
256                 return &t.value;
257             }
258         }
259     }
260     return nullptr;
261 }
262 
263 inline value& value::operator[](const string_t& key)
264 {
265     if (type == type::object) {
266         for (auto& t : object_) {
267             if (t.key == key) {
268                 return t.value;
269             }
270         }
271         object_.push_back({ key, value{} });
272         return object_.back().value;
273     }
274     return *this;
275 }
276 
HasKey(const value & object,const string_t key)277 inline bool HasKey(const value& object, const string_t key)
278 {
279     if (object.type == type::object) {
280         for (auto& t : object.object_) {
281             if (t.key == key) {
282                 return true;
283             }
284         }
285     }
286     return false;
287 }
288 
GetKey(const value & object,const string_t key)289 inline const value& GetKey(const value& object, const string_t key)
290 {
291     static value dummy;
292     if (object.type == type::object) {
293         for (auto& t : object.object_) {
294             if (t.key == key) {
295                 return t.value;
296             }
297         }
298     }
299     return dummy;
300 }
301 
302 #ifdef JSON_IMPL
303 char* parse_value(char* data, value& value);
304 char* parse_number(char* data, value&);
305 char* parse_string(char* data, value&);
306 
isWhite(char data)307 inline bool isWhite(char data)
308 {
309     return ((data == ' ') || (data == '\n') || (data == '\r') || (data == '\t'));
310 }
311 
isSign(char data)312 inline bool isSign(char data)
313 {
314     return ((data == '+') || (data == '-'));
315 }
316 
isDigit(char data)317 inline bool isDigit(char data)
318 {
319     return ((data >= '0') && (data <= '9'));
320 }
321 
isHex(char data)322 inline bool isHex(char data)
323 {
324     return ((data >= '0') && (data <= '9')) || ((data >= 'a') && (data <= 'f')) || ((data >= 'A') && (data <= 'F'));
325 }
326 
trim(char * data)327 inline char* trim(char* data)
328 {
329     while (*data && isWhite(*data)) {
330         data++;
331     }
332     return data;
333 }
334 
parse_object(char * data,value & res)335 char* parse_object(char* data, value& res)
336 {
337     data = trim(data);
338     if (*data == '}') {
339         // handle empty object.
340         res = value(object{});
341         return data + 1;
342     }
343     object values;
344     for (; *data != 0;) {
345         if (*data != '"') {
346             // invalid json
347             *data = 0;
348             return data;
349         }
350 
351         pair& pair = values.emplace_back();
352         value key;
353         data = trim(parse_string(data + 1, key));
354         pair.key = key.string_;
355         if (*data == ':') {
356             data++;
357         } else {
358             // invalid json
359             *data = 0;
360             return data;
361         }
362         data = trim(data);
363         data = trim(parse_value(data, pair.value));
364         if (*data == '}') {
365             // handle end
366             res = value(std::move(values));
367             return data + 1;
368         } else if (*data == ',') {
369             data = trim(data + 1);
370         } else {
371             // invalid json
372             *data = 0;
373             return data;
374         }
375     }
376     return data;
377 }
378 
parse_array(char * data,value & res)379 char* parse_array(char* data, value& res)
380 {
381     data = trim(data);
382     if (*data == ']') {
383         // empty array.
384         res = value(array{});
385         return data + 1;
386     }
387     array values;
388     for (; *data != 0;) {
389         value tmp;
390         data = trim(parse_value(data, tmp));
391         values.push_back(std::move(tmp));
392         if (*data == ',') {
393             data = trim(data + 1);
394         } else if (*data == ']') {
395             res = value(std::move(values));
396             return data + 1;
397         } else {
398             // invalid json
399             *data = 0;
400             return data;
401         }
402     }
403     return data;
404 }
405 
406 // values
parse_string(char * data,value & res)407 char* parse_string(char* data, value& res)
408 {
409     char* start = data;
410     for (; *data != 0; data++) {
411         if (*data == '\\' && data[1]) {
412             // escape.. (parse just enough to not stop too early)
413             if (data[1] == '\\' || data[1] == '"' || data[1] == '/' || data[1] == 'b' || data[1] == 'f' ||
414                 data[1] == 'n' || data[1] == 'r' || data[1] == 't') {
415                 ++data;
416                 continue;
417             } else if (data[1] == 'u') {
418                 data += 2;
419                 for (char* end = data + 4; data != end; ++data) {
420                     if (*data == 0 || !isHex(*data)) {
421                         *data = 0;
422                         return data;
423                     }
424                 }
425                 --data;
426             } else {
427                 // invalid json
428                 *data = 0;
429                 return data;
430             }
431         } else if (*data == '"') {
432             res = value(string_t{ start, (size_t)(data - start) });
433             return data + 1;
434         } else if (static_cast<unsigned char>(*data) < 0x20) {
435             // invalid json
436             *data = 0;
437             return data;
438         }
439     }
440     return data;
441 }
442 
parse_number(char * data,value & res)443 char* parse_number(char* data, value& res)
444 {
445     char* beg = data;
446     if (*data == '-') {
447         // is neg..
448         data++;
449         if (!isDigit(*data)) {
450             *data = 0;
451             return data;
452         }
453     }
454     bool fraction = false;
455     bool exponent = false;
456 
457     if (*data == '0') {
458         ++data;
459         // after leading zero only '.', 'e' and 'E' allowed
460         if (*data == '.') {
461             ++data;
462             fraction = true;
463         } else if (*data == 'e' || *data == 'E') {
464             ++data;
465             exponent = true;
466         }
467     } else {
468         for (; *data != 0; data++) {
469             if (isDigit(*data))
470                 continue;
471             if (*data == '.') {
472                 ++data;
473                 fraction = true;
474             } else if (*data == 'e' || *data == 'E') {
475                 ++data;
476                 exponent = true;
477             }
478             break;
479         }
480     }
481 
482     if (fraction) {
483         // exponent must start with a digit
484         if (isDigit(*data)) {
485             ++data;
486         } else {
487             // invalid json
488             *data = 0;
489             return data;
490         }
491         // fraction may contain digits up to begining of exponent ('e' or 'E')
492         for (; *data != 0; data++) {
493             if (isDigit(*data))
494                 continue;
495             if (*data == 'e' || *data == 'E') {
496                 ++data;
497                 exponent = true;
498             }
499             break;
500         }
501     }
502     if (exponent) {
503         // exponent must start with '-' or '+' followed by a digit, or digit
504         if (*data == '-' || *data == '+') {
505             ++data;
506         }
507         if (isDigit(*data)) {
508             ++data;
509         } else {
510             // invalid json
511             *data = 0;
512             return data;
513         }
514         for (; *data != 0; data++) {
515             if (isDigit(*data))
516                 continue;
517             break;
518         }
519     }
520     if (data != beg) {
521         char* end = data - 1;
522         res = value(strtod(beg, &end));
523         return data;
524     }
525     *data = 0;
526     return data;
527 }
528 
parse_boolean(char * data,value & res)529 char* parse_boolean(char* data, value& res)
530 {
531     if (*data == 't') {
532         ++data;
533         const char rue[] = { 'r', 'u', 'e' };
534         for (unsigned i = 0u; i < sizeof(rue); ++i) {
535             if (data[i] == 0 || data[i] != rue[i]) {
536                 *data = 0;
537                 return data;
538             }
539         }
540 
541         res = value(true);
542         data += sizeof(rue);
543     } else if (*data == 'f') {
544         ++data;
545         const char alse[] = { 'a', 'l', 's', 'e' };
546         for (unsigned i = 0u; i < sizeof(alse); ++i) {
547             if (data[i] == 0 || data[i] != alse[i]) {
548                 *data = 0;
549                 return data;
550             }
551         }
552         res = value(false);
553         data += sizeof(alse);
554     } else {
555         // invalid json
556         *data = 0;
557         return data;
558     }
559     return data;
560 }
561 
parse_null(char * data,value & res)562 char* parse_null(char* data, value& res)
563 {
564     if (*data == 'n') {
565         ++data;
566         const char ull[] = { 'u', 'l', 'l' };
567         for (unsigned i = 0u; i < sizeof(ull); ++i) {
568             if (data[i] == 0 || data[i] != ull[i]) {
569                 *data = 0;
570                 return data;
571             }
572         }
573         res = value(null{});
574         data += sizeof(ull);
575     } else {
576         // invalid json
577         *data = 0;
578         return data;
579     }
580     return data;
581 }
582 
parse_value(char * data,value & value)583 char* parse_value(char* data, value& value)
584 {
585     data = trim(data);
586     if (*data == '{') {
587         data = trim(parse_object(data + 1, value));
588     } else if (*data == '[') {
589         data = trim(parse_array(data + 1, value));
590     } else if (*data == '"') {
591         data = trim(parse_string(data + 1, value));
592     } else if (isSign(*data) || isDigit(*data)) {
593         data = trim(parse_number(data, value));
594     } else if ((*data == 't') || (*data == 'f')) {
595         data = trim(parse_boolean(data, value));
596     } else if (*data == 'n') {
597         data = trim(parse_null(data, value));
598     } else {
599         // invalid json
600         *data = 0;
601         return data;
602     }
603     return data;
604 }
605 
add(value & v,value && value)606 void add(value& v, value&& value)
607 {
608     switch (v.type) {
609         case type::uninitialized:
610             v = std::move(value);
611             break;
612         case type::object:
613             v.object_.back().value = std::move(value);
614             break;
615         case type::array:
616             v.array_.push_back(std::move(value));
617             break;
618         case type::string:
619         case type::number:
620         case type::boolean:
621         case type::null:
622         default:
623             break;
624     }
625 }
626 
parse(char * data)627 value parse(char* data)
628 {
629     array stack;
630     // push an uninitialized value which will get the final value during parsing
631     stack.push_back(value{});
632 
633     bool acceptValue = true;
634     while (*data) {
635         data = trim(data);
636         if (*data == '{') {
637             // start of an object
638             if (!acceptValue) {
639                 return {};
640             }
641             data = trim(data + 1);
642             if (*data == '}') {
643                 data = trim(data + 1);
644                 // handle empty object.
645                 add(stack.back(), value(object{}));
646                 acceptValue = false;
647             } else if (*data == '"') {
648                 // try to read the key
649                 value key;
650                 data = trim(parse_string(data + 1, key));
651 
652                 if (*data != ':') {
653                     // invalid json
654                     return {};
655                 }
656                 data = trim(data + 1);
657                 // push the object with key and missing value on the stack and hope to find a value next
658                 stack.push_back(value(object{}));
659                 stack.back().object_.push_back(pair{ key.string_, value{} });
660                 acceptValue = true;
661             } else {
662                 // invalid json
663                 return {};
664             }
665         } else if (*data == '}') {
666             // end of an object
667             if (stack.back().type != type::object) {
668                 // invalid json
669                 return {};
670             }
671             // check are we missing a value ('{"":}', '{"":"",}' )
672             if (acceptValue) {
673                 return {};
674             }
675             data = trim(data + 1);
676             // move this object to the next in the stack
677             auto value = std::move(stack.back());
678             stack.pop_back();
679             if (stack.empty()) {
680                 // invalid json
681                 return {};
682             }
683             add(stack.back(), std::move(value));
684             acceptValue = false;
685         } else if (*data == '[') {
686             // start of an array
687             if (!acceptValue) {
688                 return {};
689             }
690             data = trim(data + 1);
691             if (*data == ']') {
692                 data = trim(data + 1);
693                 // handle empty array.
694                 add(stack.back(), value(array{}));
695                 acceptValue = false;
696             } else {
697                 // push the empty array on the stack and hope to find values
698                 stack.push_back(value(array{}));
699                 acceptValue = true;
700             }
701         } else if (*data == ']') {
702             // end of an array
703             if (stack.back().type != type::array) {
704                 // invalid json
705                 return {};
706             }
707             // check are we missing a value ('[1,]' '[1]]')
708             if (acceptValue) {
709                 // invalid json
710                 return {};
711             }
712             data = trim(data + 1);
713 
714             auto value = std::move(stack.back());
715             stack.pop_back();
716             if (stack.empty()) {
717                 // invalid json
718                 return {};
719             }
720             add(stack.back(), std::move(value));
721             acceptValue = false;
722         } else if (*data == ',') {
723             // comma is allowed when the previous value was complete and we have an incomplete object or array on the
724             // stack.
725             if (!acceptValue && stack.back().type == type::object) {
726                 data = trim(data + 1);
727                 if (*data != '"') {
728                     // invalid json
729                     return {};
730                 }
731                 // try to read the key
732                 value key;
733                 data = trim(parse_string(data + 1, key));
734 
735                 if (*data != ':') {
736                     // invalid json
737                     return {};
738                 }
739                 data = trim(data + 1);
740                 stack.back().object_.push_back(pair{ key.string_, value{} });
741                 acceptValue = true;
742             } else if (!acceptValue && stack.back().type == type::array) {
743                 data = trim(data + 1);
744                 acceptValue = true;
745             } else {
746                 // invalid json
747                 return {};
748             }
749         } else if (*data == '"') {
750             value value;
751             data = trim(parse_string(data + 1, value));
752             if (acceptValue && value.type == type::string) {
753                 add(stack.back(), std::move(value));
754                 acceptValue = false;
755             } else {
756                 // invalid json
757                 return {};
758             }
759         } else if (isSign(*data) || isDigit(*data)) {
760             value value;
761             data = trim(parse_number(data, value));
762             if (acceptValue && value.type == type::number) {
763                 add(stack.back(), std::move(value));
764                 acceptValue = false;
765             } else {
766                 // invalid json
767                 return {};
768             }
769         } else if ((*data == 't') || (*data == 'f')) {
770             value value;
771             data = trim(parse_boolean(data, value));
772             if (acceptValue && value.type == type::boolean) {
773                 add(stack.back(), std::move(value));
774                 acceptValue = false;
775             } else {
776                 // invalid json
777                 return {};
778             }
779         } else if (*data == 'n') {
780             value value;
781             data = trim(parse_null(data, value));
782             if (acceptValue && value.type == type::null) {
783                 add(stack.back(), std::move(value));
784                 acceptValue = false;
785             } else {
786                 // invalid json
787                 return {};
788             }
789         } else {
790             // invalid json
791             return {};
792         }
793     }
794     // check if we are missing a value ('{"":' '[')
795     if (acceptValue) {
796         return {};
797     }
798 
799     auto value = std::move(stack.front());
800     return value;
801 }
802 
803 // end of parser
804 
to_string(const value & value)805 std::string to_string(const value& value)
806 {
807     std::string out;
808     switch (value.type) {
809         case type::uninitialized:
810             break;
811 
812         case type::object: {
813             out += '{';
814             int count = 0;
815             for (const auto& v : value.object_) {
816                 if (count++) {
817                     out += ',';
818                 }
819                 out += '"';
820                 out.append(v.key.data(), v.key.size());
821                 out += '"';
822                 out += ':';
823                 out += to_string(v.value);
824             }
825             out += '}';
826             break;
827         }
828 
829         case type::array: {
830             out += '[';
831             int count = 0;
832             for (const auto& v : value.array_) {
833                 if (count++) {
834                     out += ',';
835                 }
836                 out += to_string(v);
837             }
838             out += ']';
839             break;
840         }
841 
842         case type::string:
843             out += '"';
844             out.append(value.string_.data(), value.string_.size());
845             out += '"';
846             break;
847 
848         case type::number:
849             if (value.number_ == static_cast<int64_t>(value.number_)) {
850                 out += std::to_string(static_cast<int64_t>(value.number_));
851             } else {
852 #if defined(HAS_CHARCONV) && !defined(__linux__) && !defined(__APPLE__)
853                 char asStr[64]{};
854                 if (auto result = std::to_chars(std::begin(asStr), std::end(asStr), value.number_);
855                     result.ec == std::errc()) {
856                     out.append(asStr, static_cast<size_t>(result.ptr - asStr));
857                 }
858 #else
859                 out += std::to_string(value.number_).data();
860 #endif
861             }
862             break;
863 
864         case type::boolean:
865             if (value.boolean_) {
866                 out += "true";
867             } else {
868                 out += "false";
869             }
870             break;
871 
872         case type::null:
873             out += "null";
874             break;
875 
876         default:
877             break;
878     }
879     return out;
880 }
881 #endif // JSON_IMPL
882 } // namespace json
883 #endif // !LUMEJSON_H
884