Line data Source code
1 : /**
2 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_DATA_SPDATADECODESERENITY_H_
25 : #define STAPPLER_DATA_SPDATADECODESERENITY_H_
26 :
27 : #include "SPDataDecodeJson.h"
28 : #include "SPDataValue.h"
29 :
30 : namespace STAPPLER_VERSIONIZED stappler::data::serenity {
31 :
32 : template <typename Interface>
33 : struct Decoder : public Interface::AllocBaseType {
34 : using InterfaceType = Interface;
35 : using ValueType = ValueTemplate<Interface>;
36 : using StringType = typename InterfaceType::StringType;
37 : using BytesType = typename InterfaceType::BytesType;
38 :
39 : enum BackType {
40 : BackIsPlain,
41 : BackIsPlainList,
42 : BackIsPlainStop,
43 : BackIsArray,
44 : BackIsDict,
45 : BackIsGeneric,
46 : };
47 :
48 775 : Decoder(StringView &r) : backType(BackIsGeneric), r(r), back(nullptr) {
49 775 : stack.reserve(10);
50 775 : }
51 :
52 : inline void parseBufferString(StringType &ref);
53 : inline void parseNumber(StringView &token, ValueType &ref) SPINLINE;
54 :
55 : inline void parsePlainToken(ValueType ¤t, StringView v);
56 :
57 : inline void transformToDict(ValueType ¤t);
58 :
59 : void parse(ValueType &val);
60 :
61 2300 : inline void push(BackType t, ValueType *v) {
62 2300 : if (t != BackIsPlain && t != BackIsGeneric) {
63 0 : ++ r;
64 : }
65 2300 : back = v;
66 2300 : stack.push_back(pair(t, v));
67 2300 : backType = t;
68 2300 : }
69 :
70 3025 : inline void pop() {
71 3025 : if (backType != BackIsPlain && backType != BackIsPlainList && backType != BackIsPlainStop) {
72 1250 : r ++;
73 : }
74 3025 : stack.pop_back();
75 3025 : if (stack.empty()) {
76 725 : back = nullptr;
77 725 : backType = BackIsGeneric;
78 : } else {
79 2300 : back = stack.back().second;
80 2300 : backType = stack.back().first;
81 : }
82 3025 : }
83 :
84 : bool stop = false;
85 : BackType backType;
86 : StringView r;
87 : ValueType *back;
88 : typename InterfaceType::template ArrayType<Pair<BackType, ValueType *>> stack;
89 : };
90 :
91 : template <typename Interface>
92 : inline void Decoder<Interface>::parseNumber(StringView &token, ValueType &result) {
93 650 : bool isFloat = false;
94 650 : if (token == "+inf") {
95 0 : result._type = ValueType::Type::DOUBLE;
96 0 : result.doubleVal = NumericLimits<double>::infinity();
97 650 : } else if (token == "-inf") {
98 0 : result._type = ValueType::Type::DOUBLE;
99 0 : result.doubleVal = - NumericLimits<double>::infinity();
100 : } else {
101 650 : auto data = token.data();
102 650 : auto size = token.size();
103 650 : auto value = json::decodeNumber(token, isFloat);
104 650 : if (value.empty()) {
105 0 : return;
106 650 : } else if (value.size() != size) {
107 250 : result._type = ValueType::Type::CHARSTRING;
108 250 : result.strVal = new StringType(data, size);
109 : } else {
110 400 : if (isFloat) {
111 0 : value.readDouble().unwrap([&] (double v) {
112 0 : result._type = ValueType::Type::DOUBLE;
113 0 : result.doubleVal = v;
114 : });
115 : } else {
116 800 : value.readInteger().unwrap([&] (int64_t v) {
117 400 : result._type = ValueType::Type::INTEGER;
118 400 : result.intVal = v;
119 : });
120 : }
121 : }
122 : }
123 : }
124 :
125 : template <typename Interface>
126 3525 : inline void Decoder<Interface>::parsePlainToken(ValueType ¤t, StringView token) {
127 3525 : switch (token[0]) {
128 650 : case '0': case '1': case '2': case '3': case '4': case '5': case '6':
129 : case '7': case '8': case '9': case '+': case '-':
130 : parseNumber(token, current);
131 650 : return;
132 : break;
133 450 : case 't':
134 450 : if (token == "true") {
135 0 : current._type = ValueType::Type::BOOLEAN;
136 0 : current.boolVal = true;
137 0 : return;
138 : }
139 450 : break;
140 0 : case 'f':
141 0 : if (token == "false") {
142 0 : current._type = ValueType::Type::BOOLEAN;
143 0 : current.boolVal = false;
144 0 : return;
145 : }
146 0 : break;
147 0 : case 'n':
148 0 : if (token == "nan") {
149 0 : current._type = ValueType::Type::DOUBLE;
150 0 : current.doubleVal = nan();
151 0 : return;
152 0 : } else if (token == "null") {
153 0 : current._type = ValueType::Type::EMPTY;
154 0 : return;
155 : }
156 0 : break;
157 425 : case 'i':
158 425 : if (token == "inf") {
159 0 : current._type = ValueType::Type::DOUBLE;
160 0 : current.doubleVal = NumericLimits<double>::infinity();
161 0 : return;
162 : }
163 425 : break;
164 0 : case '~':
165 0 : current._type = ValueType::Type::BYTESTRING;
166 0 : current.bytesVal = new BytesType();
167 0 : string::urldecode(*current.bytesVal, token);
168 0 : return;
169 : break;
170 : }
171 2875 : current._type = ValueType::Type::CHARSTRING;
172 5750 : current.strVal = new StringType();
173 2875 : string::urldecode(*current.strVal, token);
174 : }
175 :
176 : template <typename Interface>
177 25 : inline void Decoder<Interface>::transformToDict(ValueType ¤t) {
178 25 : typename ValueType::DictionaryType dict;
179 75 : for (auto &it : *current.arrayVal) {
180 50 : auto str = it.asString();
181 50 : if (!str.empty()) {
182 50 : dict.emplace(move(str), ValueType(true));
183 : } else {
184 0 : log::error("DataSerenityDecoder", "Invalid token within SubArray");
185 : }
186 : }
187 25 : current = ValueType(move(dict));
188 25 : }
189 :
190 : using TokenSpecials = StringView::Chars<'/', '?', '@', '-', '.', '_', '!', '$', '\'', '*', '+', '%'>;
191 :
192 : template <typename Interface>
193 775 : void Decoder<Interface>::parse(ValueType &val) {
194 775 : backType = BackIsGeneric;
195 775 : back = &val;
196 775 : stack.push_back(pair(backType, back));
197 :
198 775 : StringType key;
199 : do {
200 7500 : r.skipUntil<TokenSpecials, StringView::Chars<'(', '~', ';', ')', ','>, StringView::CharGroup<CharGroupId::Alphanumeric>, chars::UniChar>();
201 7500 : switch (backType) {
202 1775 : case BackIsPlain:
203 1775 : if (r.is(')') || r.is(';')) {
204 0 : pop();
205 1775 : } else if (r.is(',')) {
206 0 : typename ValueType::ArrayType arr;
207 0 : arr.emplace_back(move(back));
208 0 : *back = ValueType(move(arr));
209 0 : backType = stack.back().first = BackIsPlainList;
210 1775 : } else if (r.is('(') || r.is("~(")) {
211 0 : backType = stack.back().first = BackIsPlainStop;
212 0 : push(BackIsGeneric, back);
213 : } else {
214 1775 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
215 1775 : StringView token = r.readUntil<StringView::Chars<'~', ',', ';', '(', ')'>, StringView::CharGroup<CharGroupId::WhiteSpace>>();
216 1775 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
217 1775 : if (r.is(':')) {
218 0 : log::error("DataSerenityDecoder", "Colon sequence within plain list is invalid");
219 0 : stop = true;
220 0 : break;
221 1775 : } else if (token.empty()) {
222 : // do nothing
223 1775 : } else if (r.is('(') || r.is("~(")) {
224 0 : key.clear(); string::urldecode(key, token);
225 0 : back->_type = ValueType::Type::DICTIONARY;
226 0 : back->dictVal = new typename ValueType::DictionaryType();
227 0 : backType = stack.back().first = BackIsPlainList;
228 0 : push(BackIsGeneric, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
229 1775 : } else if (r.is(',')) {
230 475 : back->_type = ValueType::Type::ARRAY;
231 950 : back->arrayVal = new typename ValueType::ArrayType();
232 475 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
233 475 : backType = stack.back().first = BackIsPlainList;
234 475 : parsePlainToken(back->arrayVal->back(), token);
235 1300 : } else if (r.empty() || r.is(')') || r.is(';')) {
236 1300 : parsePlainToken(*back, token);
237 1300 : pop();
238 : }
239 : }
240 1775 : break;
241 2100 : case BackIsPlainList:
242 2100 : if (r.is(')') || r.is(';')) {
243 475 : pop();
244 475 : continue;
245 1625 : } else if (r.is('(') || r.is("~(") || r.is(",~(") || r.is(",(")) {
246 25 : if (r.is(',')) {
247 25 : ++ r;
248 : }
249 25 : if (back->_type == ValueType::Type::ARRAY) {
250 25 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
251 25 : push(BackIsGeneric, &back->arrayVal->back());
252 : } else {
253 0 : log::error("DataSerenityDecoder", "Generic value can not be used as key");
254 0 : stop = true;
255 0 : break;
256 : }
257 25 : break;
258 1600 : } else if (r.is(',') || r.is<TokenSpecials>() || r.is<CharGroupId::Alphanumeric>()) {
259 1600 : if (r.is(',')) {
260 1600 : ++ r;
261 1600 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
262 : }
263 :
264 1600 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
265 1600 : StringView token = r.readUntil<StringView::Chars<'~', ':', ',', ';', '(', ')'>, StringView::CharGroup<CharGroupId::WhiteSpace>>();
266 1600 : if (r.is(':')) {
267 0 : auto tmp = token; tmp.skipChars<StringView::CharGroup<CharGroupId::Numbers>>();
268 0 : if (tmp.empty()) {
269 0 : tmp = r.readUntil<StringView::Chars<'~', ',', ';', '(', ')'>, StringView::CharGroup<CharGroupId::WhiteSpace>>();
270 0 : token = StringView(token.data(), token.size() + tmp.size());
271 : }
272 : }
273 1600 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
274 1600 : if (r.is(':')) {
275 0 : pop();
276 0 : if (backType == BackIsDict) {
277 0 : push(BackIsPlain, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
278 : } else {
279 0 : log::error("DataSerenityDecoder", "Colon sequence within plain list is invalid");
280 0 : stop = true;
281 0 : break;
282 : }
283 1600 : } else if (token.empty()) {
284 : // do nothing
285 : }
286 1600 : if (back->_type == ValueType::Type::ARRAY) {
287 1600 : if (r.is('(')) {
288 0 : key.clear(); string::urldecode(key, token);
289 0 : transformToDict(*back);
290 0 : push(BackIsGeneric, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
291 1600 : } else if (r.is("~(")) {
292 0 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
293 0 : push(BackIsGeneric, &back->arrayVal->back());
294 : } else {
295 1600 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
296 1600 : parsePlainToken(back->arrayVal->back(), token);
297 : }
298 : } else {
299 0 : key.clear(); string::urldecode(key, token);
300 0 : if (r.is('(') || r.is("~(")) {
301 0 : push(BackIsGeneric, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
302 : } else {
303 0 : back->dictVal->emplace(key, ValueType(true));
304 : }
305 : }
306 : } else {
307 0 : log::error("DataSerenityDecoder", "Invalid token in plain list");
308 0 : stop = true;
309 0 : break;
310 : }
311 1600 : break;
312 0 : case BackIsPlainStop:
313 0 : if (r.is(')') || r.is(';')) {
314 0 : pop();
315 0 : continue;
316 0 : } else if (r.is(',') || r.is("~(")) {
317 0 : typename ValueType::ArrayType arr;
318 0 : arr.emplace_back(move(*back));
319 0 : *back = ValueType(move(arr));
320 0 : backType = stack.back().first = BackIsPlainList;
321 0 : } else if (r.is<TokenSpecials>() || r.is<CharGroupId::Alphanumeric>()) {
322 0 : pop();
323 0 : continue;
324 : } else {
325 0 : log::error("DataSerenityDecoder", "Invalid token in plain stop");
326 0 : stop = true;
327 : }
328 0 : break;
329 100 : case BackIsArray:
330 100 : if (!r.is(')')) {
331 75 : if (r.is(';') || r.is(',')) {
332 75 : ++ r;
333 75 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
334 : }
335 75 : if (r.is('(')) {
336 0 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
337 0 : backType = stack.back().first = BackIsArray;
338 0 : push(BackIsGeneric, &back->arrayVal->back());
339 : } else {
340 75 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
341 75 : StringView token = r.readUntil<StringView::Chars<'~', ':', ',', ';', '(', ')'>, StringView::CharGroup<CharGroupId::WhiteSpace>>();
342 75 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
343 75 : if (token.empty()) {
344 : // do nothing
345 75 : } else if (r.is(':')) {
346 25 : key.clear(); string::urldecode(key, token);
347 25 : transformToDict(*back);
348 25 : backType = stack.back().first = BackIsDict;
349 25 : push(BackIsPlain, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
350 50 : } else if (r.is('(') || r.is("~(")) {
351 0 : key.clear();
352 0 : string::urldecode(key, token);
353 0 : transformToDict(*back);
354 0 : backType = stack.back().first = BackIsDict;
355 0 : push(BackIsGeneric, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
356 : } else {
357 50 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
358 50 : parsePlainToken(back->arrayVal->back(), token);
359 : // continue
360 : }
361 : }
362 : } else {
363 25 : back->arrayVal->shrink_to_fit();
364 25 : pop();
365 : }
366 100 : break;
367 2225 : case BackIsDict:
368 2225 : if (!r.is(')')) {
369 1075 : if (r.is(';') || r.is(',')) {
370 1050 : ++ r;
371 : }
372 :
373 1075 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
374 1075 : if (r.is(')')) {
375 25 : pop();
376 25 : continue;
377 : }
378 :
379 1050 : if (!r.is<TokenSpecials>() && !r.is<StringView::CharGroup<CharGroupId::Alphanumeric>>()) {
380 0 : stop = true;
381 0 : log::error("DataSerenityDecoder", "Invalid key");
382 0 : break;
383 : }
384 :
385 1050 : StringView token = r.readUntil<StringView::Chars<'~', ':', ',', ';', '(', ')'>, StringView::CharGroup<CharGroupId::WhiteSpace>>();
386 1050 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
387 1050 : key.clear(); string::urldecode(key, token);
388 1050 : if (r.is(':')) {
389 750 : push(BackIsPlain, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
390 300 : } else if (r.is('(') || r.is("~(")) {
391 300 : push(BackIsGeneric, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
392 0 : } else if (r.is(';') || r.is(',')) {
393 0 : back->dictVal->emplace(key, ValueType(true));
394 : } else {
395 0 : stop = true;
396 0 : log::error("DataSerenityDecoder", "Invalid token in value");
397 0 : break;
398 : }
399 : } else {
400 1150 : pop();
401 : }
402 2200 : break;
403 1300 : case BackIsGeneric:
404 1300 : if (r.is('(') || r.is("~(")) {
405 1300 : if (r.is('(')) {
406 1275 : ++ r;
407 25 : } else if (r.is("~(")) {
408 25 : r += 2;
409 : }
410 1300 : if (r.is('(')) {
411 0 : back->_type = ValueType::Type::ARRAY;
412 0 : back->arrayVal = new typename ValueType::ArrayType();
413 0 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
414 0 : backType = stack.back().first = BackIsArray;
415 0 : push(BackIsGeneric, &back->arrayVal->back());
416 : } else {
417 1300 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
418 1300 : StringView token = r.readUntil<StringView::Chars<'~', ':', ',', ';', '(', ')'>, StringView::CharGroup<CharGroupId::WhiteSpace>>();
419 1300 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
420 1300 : if (token.empty()) {
421 0 : pop();
422 1300 : } else if (r.is(')') || r.empty()) {
423 50 : parsePlainToken(*back, token);
424 50 : pop();
425 1250 : } else if (r.is(':')) {
426 1000 : key.clear(); string::urldecode(key, token);
427 1000 : back->_type = ValueType::Type::DICTIONARY;
428 2000 : back->dictVal = new typename ValueType::DictionaryType();
429 1000 : backType = stack.back().first = BackIsDict;
430 1000 : push(BackIsPlain, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
431 :
432 1000 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
433 :
434 250 : } else if (r.is('(') || r.is("~(")) {
435 200 : key.clear(); string::urldecode(key, token);
436 200 : back->_type = ValueType::Type::DICTIONARY;
437 400 : back->dictVal = new typename ValueType::DictionaryType();
438 200 : backType = stack.back().first = BackIsDict;
439 200 : push(BackIsGeneric, &back->dictVal->emplace(key, ValueType::Type::EMPTY).first->second);
440 50 : } else if (r.is(',') || r.is(';')) {
441 50 : back->_type = ValueType::Type::ARRAY;
442 100 : back->arrayVal = new typename ValueType::ArrayType();
443 50 : back->arrayVal->emplace_back(ValueType::Type::EMPTY);
444 50 : backType = stack.back().first = BackIsArray;
445 50 : parsePlainToken(back->arrayVal->back(), token);
446 : }
447 : }
448 : } else {
449 0 : log::error("DataSerenityDecoder", "Invalid token in plain stop: '", r.sub(16), "'");
450 : }
451 :
452 1300 : break;
453 : }
454 7500 : } while (!r.empty() && !stack.empty() && !stop);
455 775 : }
456 :
457 : template <typename Interface>
458 775 : auto read(StringView &n) -> ValueTemplate<Interface> {
459 775 : auto r = n;
460 775 : if (r.empty() || r == "null") {
461 0 : return ValueTemplate<Interface>();
462 : }
463 :
464 775 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
465 775 : Decoder<Interface> dec(r);
466 775 : ValueTemplate<Interface> ret;
467 775 : dec.parse(ret);
468 775 : n = dec.r;
469 775 : return ret;
470 775 : }
471 :
472 : template <typename Interface>
473 150 : auto read(const StringView &r) -> ValueTemplate<Interface> {
474 150 : StringView tmp(r);
475 300 : return read<Interface>(tmp);
476 : }
477 :
478 : }
479 :
480 : #endif /* STAPPLER_DATA_SPDATADECODESERENITY_H_ */
|