@@ -33,11 +33,35 @@ std::string Escape(const std::string& text);
3333
3434namespace JSON
3535{
36- inline std::wstring UTF (int charCode)
36+ template <typename C>
37+ std::basic_string<C> Escape (std::basic_string<C> text)
3738 {
38- return { (wchar_t )charCode };
39+ int oldSize = text.size ();
40+ text.resize (text.size () + std::count_if (text.begin (), text.end (), [](auto ch) { return ch == ' \n ' || ch == ' \r ' || ch == ' \t ' || ch == ' \\ ' || ch == ' "' ; }));
41+ auto out = text.rbegin ();
42+ for (int i = oldSize - 1 ; i >= 0 ; --i)
43+ {
44+ if (text[i] == ' \n ' ) *out++ = ' n' ;
45+ else if (text[i] == ' \t ' ) *out++ = ' t' ;
46+ else if (text[i] == ' \r ' ) *out++ = ' r' ;
47+ else if (text[i] == ' \\ ' || text[i] == ' "' ) *out++ = text[i];
48+ else
49+ {
50+ *out++ = text[i];
51+ continue ;
52+ }
53+ *out++ = ' \\ ' ;
54+ }
55+ text.erase (std::remove_if (text.begin (), text.end (), [](uint64_t ch) { return ch < 0x20 || ch == 0x7f ; }), text.end ());
56+ return text;
3957 }
4058
59+ template <typename C> struct UTF {};
60+ template <> struct UTF <wchar_t >
61+ {
62+ inline static std::wstring FromCodepoint (int codepoint) { return { (wchar_t )codepoint }; } // TODO: surrogate pairs
63+ };
64+
4165 template <typename C>
4266 std::pair<std::basic_string<C>, int > Unescape (std::basic_string_view<C> text)
4367 {
@@ -53,7 +77,7 @@ namespace JSON
5377 if (ch == ' u' && isxdigit (text[i + 2 ]) && isxdigit (text[i + 3 ]) && isxdigit (text[i + 4 ]) && isxdigit (text[i + 5 ]))
5478 {
5579 char charCode[] = { text[i + 2 ], text[i + 3 ], text[i + 4 ], text[i + 5 ], 0 };
56- unescaped += UTF (strtol (charCode, nullptr , 16 ));
80+ unescaped += UTF<C>:: FromCodepoint (strtol (charCode, nullptr , 16 ));
5781 i += 5 ;
5882 continue ;
5983 }
@@ -70,29 +94,6 @@ namespace JSON
7094 return { unescaped, i };
7195 }
7296
73- template <typename C>
74- std::basic_string<C> Escape (std::basic_string<C> text)
75- {
76- int oldSize = text.size ();
77- text.resize (text.size () + std::count_if (text.begin (), text.end (), [](auto ch) { return ch == ' \n ' || ch == ' \r ' || ch == ' \t ' || ch == ' \\ ' || ch == ' "' ; }));
78- auto out = text.rbegin ();
79- for (int i = oldSize - 1 ; i >= 0 ; --i)
80- {
81- if (text[i] == ' \n ' ) *out++ = ' n' ;
82- else if (text[i] == ' \t ' ) *out++ = ' t' ;
83- else if (text[i] == ' \r ' ) *out++ = ' r' ;
84- else if (text[i] == ' \\ ' || text[i] == ' "' ) *out++ = text[i];
85- else
86- {
87- *out++ = text[i];
88- continue ;
89- }
90- *out++ = ' \\ ' ;
91- }
92- text.erase (std::remove_if (text.begin (), text.end (), [](uint64_t ch) { return ch < 0x20 || ch == 0x7f ; }), text.end ());
93- return text;
94- }
95-
9697 template <typename C>
9798 struct Value : private std ::variant<std::monostate, std::nullopt_t , bool , double , std::basic_string<C>, std::vector<Value<C>>, std::unordered_map<std::basic_string<C>, Value<C>>>
9899 {
@@ -119,10 +120,10 @@ namespace JSON
119120 }
120121 };
121122
122- template <typename C>
123+ template <typename C, int maxDepth = 25 >
123124 Value<C> Parse (std::basic_string_view<C> text, int64_t & i, int depth)
124125 {
125- if (depth > 25 ) return {};
126+ if (depth > maxDepth ) return {};
126127 C ch;
127128 auto SkipWhitespace = [&]
128129 {
@@ -169,7 +170,7 @@ namespace JSON
169170 i += 1 ;
170171 if (SkipWhitespace ()) return {};
171172 if (ch == ' ]' ) return i += 1 , Value<C>(array);
172- if (!array.emplace_back (Parse (text, i, depth + 1 ))) return {};
173+ if (!array.emplace_back (Parse<C, maxDepth> (text, i, depth + 1 ))) return {};
173174 if (SkipWhitespace ()) return {};
174175 if (ch == ' ]' ) return i += 1 , Value<C>(array);
175176 if (ch != ' ,' ) return {};
@@ -188,7 +189,7 @@ namespace JSON
188189 auto key = ExtractString ();
189190 if (SkipWhitespace () || ch != ' :' ) return {};
190191 i += 1 ;
191- if (!(object[std::move (key)] = Parse (text, i, depth + 1 ))) return {};
192+ if (!(object[std::move (key)] = Parse<C, maxDepth> (text, i, depth + 1 ))) return {};
192193 if (SkipWhitespace ()) return {};
193194 if (ch == ' }' ) return i += 1 , Value<C>(object);
194195 if (ch != ' ,' ) return {};
0 commit comments