1 | // |
2 | // Var.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Core |
6 | // Module: Var |
7 | // |
8 | // Copyright (c) 2007, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Dynamic/Var.h" |
16 | #include "Poco/Dynamic/Struct.h" |
17 | #include <algorithm> |
18 | #include <cctype> |
19 | #include <vector> |
20 | #include <list> |
21 | #include <deque> |
22 | |
23 | |
24 | namespace Poco { |
25 | namespace Dynamic { |
26 | |
27 | |
28 | Var::Var() |
29 | #ifdef POCO_NO_SOO |
30 | : _pHolder(0) |
31 | #endif |
32 | { |
33 | } |
34 | |
35 | |
36 | Var::Var(const char* pVal) |
37 | #ifdef POCO_NO_SOO |
38 | : _pHolder(new VarHolderImpl<std::string>(pVal)) |
39 | { |
40 | } |
41 | #else |
42 | { |
43 | construct(std::string(pVal)); |
44 | } |
45 | #endif |
46 | |
47 | |
48 | Var::Var(const Var& other) |
49 | #ifdef POCO_NO_SOO |
50 | : _pHolder(other._pHolder ? other._pHolder->clone() : 0) |
51 | { |
52 | } |
53 | #else |
54 | { |
55 | if ((this != &other) && !other.isEmpty()) |
56 | construct(other); |
57 | } |
58 | #endif |
59 | |
60 | |
61 | Var::~Var() |
62 | { |
63 | destruct(); |
64 | } |
65 | |
66 | |
67 | Var& Var::operator = (const Var& rhs) |
68 | { |
69 | #ifdef POCO_NO_SOO |
70 | Var tmp(rhs); |
71 | swap(tmp); |
72 | #else |
73 | if ((this != &rhs) && !rhs.isEmpty()) |
74 | construct(rhs); |
75 | else if ((this != &rhs) && rhs.isEmpty()) |
76 | _placeholder.erase(); |
77 | #endif |
78 | return *this; |
79 | } |
80 | |
81 | |
82 | const Var Var::operator + (const Var& other) const |
83 | { |
84 | if (isInteger()) |
85 | { |
86 | if (isSigned()) |
87 | return add<Poco::Int64>(other); |
88 | else |
89 | return add<Poco::UInt64>(other); |
90 | } |
91 | else if (isNumeric()) |
92 | return add<double>(other); |
93 | else if (isString()) |
94 | return add<std::string>(other); |
95 | else |
96 | throw InvalidArgumentException("Invalid operation for this data type." ); |
97 | } |
98 | |
99 | |
100 | Var& Var::operator += (const Var& other) |
101 | { |
102 | if (isInteger()) |
103 | { |
104 | if (isSigned()) |
105 | return *this = add<Poco::Int64>(other); |
106 | else |
107 | return *this = add<Poco::UInt64>(other); |
108 | } |
109 | else if (isNumeric()) |
110 | return *this = add<double>(other); |
111 | else if (isString()) |
112 | return *this = add<std::string>(other); |
113 | else |
114 | throw InvalidArgumentException("Invalid operation for this data type." ); |
115 | } |
116 | |
117 | |
118 | const Var Var::operator - (const Var& other) const |
119 | { |
120 | if (isInteger()) |
121 | { |
122 | if (isSigned()) |
123 | return subtract<Poco::Int64>(other); |
124 | else |
125 | return subtract<Poco::UInt64>(other); |
126 | } |
127 | else if (isNumeric()) |
128 | return subtract<double>(other); |
129 | else |
130 | throw InvalidArgumentException("Invalid operation for this data type." ); |
131 | } |
132 | |
133 | |
134 | Var& Var::operator -= (const Var& other) |
135 | { |
136 | if (isInteger()) |
137 | { |
138 | if (isSigned()) |
139 | return *this = subtract<Poco::Int64>(other); |
140 | else |
141 | return *this = subtract<Poco::UInt64>(other); |
142 | } |
143 | else if (isNumeric()) |
144 | return *this = subtract<double>(other); |
145 | else |
146 | throw InvalidArgumentException("Invalid operation for this data type." ); |
147 | } |
148 | |
149 | |
150 | const Var Var::operator * (const Var& other) const |
151 | { |
152 | if (isInteger()) |
153 | { |
154 | if (isSigned()) |
155 | return multiply<Poco::Int64>(other); |
156 | else |
157 | return multiply<Poco::UInt64>(other); |
158 | } |
159 | else if (isNumeric()) |
160 | return multiply<double>(other); |
161 | else |
162 | throw InvalidArgumentException("Invalid operation for this data type." ); |
163 | } |
164 | |
165 | |
166 | Var& Var::operator *= (const Var& other) |
167 | { |
168 | if (isInteger()) |
169 | { |
170 | if (isSigned()) |
171 | return *this = multiply<Poco::Int64>(other); |
172 | else |
173 | return *this = multiply<Poco::UInt64>(other); |
174 | } |
175 | else if (isNumeric()) |
176 | return *this = multiply<double>(other); |
177 | else |
178 | throw InvalidArgumentException("Invalid operation for this data type." ); |
179 | } |
180 | |
181 | |
182 | const Var Var::operator / (const Var& other) const |
183 | { |
184 | if (isInteger()) |
185 | { |
186 | if (isSigned()) |
187 | return divide<Poco::Int64>(other); |
188 | else |
189 | return divide<Poco::UInt64>(other); |
190 | } |
191 | else if (isNumeric()) |
192 | return divide<double>(other); |
193 | else |
194 | throw InvalidArgumentException("Invalid operation for this data type." ); |
195 | } |
196 | |
197 | |
198 | Var& Var::operator /= (const Var& other) |
199 | { |
200 | if (isInteger()) |
201 | { |
202 | if (isSigned()) |
203 | return *this = divide<Poco::Int64>(other); |
204 | else |
205 | return *this = divide<Poco::UInt64>(other); |
206 | } |
207 | else if (isNumeric()) |
208 | return *this = divide<double>(other); |
209 | else |
210 | throw InvalidArgumentException("Invalid operation for this data type." ); |
211 | } |
212 | |
213 | |
214 | Var& Var::operator ++ () |
215 | { |
216 | if (!isInteger()) |
217 | throw InvalidArgumentException("Invalid operation for this data type." ); |
218 | |
219 | return *this = *this + 1; |
220 | } |
221 | |
222 | |
223 | const Var Var::operator ++ (int) |
224 | { |
225 | if (!isInteger()) |
226 | throw InvalidArgumentException("Invalid operation for this data type." ); |
227 | |
228 | Var tmp(*this); |
229 | *this += 1; |
230 | return tmp; |
231 | } |
232 | |
233 | |
234 | Var& Var::operator -- () |
235 | { |
236 | if (!isInteger()) |
237 | throw InvalidArgumentException("Invalid operation for this data type." ); |
238 | |
239 | return *this = *this - 1; |
240 | } |
241 | |
242 | |
243 | const Var Var::operator -- (int) |
244 | { |
245 | if (!isInteger()) |
246 | throw InvalidArgumentException("Invalid operation for this data type." ); |
247 | |
248 | Var tmp(*this); |
249 | *this -= 1; |
250 | return tmp; |
251 | } |
252 | |
253 | |
254 | bool Var::operator == (const Var& other) const |
255 | { |
256 | if (isEmpty() != other.isEmpty()) return false; |
257 | if (isEmpty() && other.isEmpty()) return true; |
258 | return convert<std::string>() == other.convert<std::string>(); |
259 | } |
260 | |
261 | |
262 | bool Var::operator == (const char* other) const |
263 | { |
264 | if (isEmpty()) return false; |
265 | return convert<std::string>() == other; |
266 | } |
267 | |
268 | |
269 | bool Var::operator != (const Var& other) const |
270 | { |
271 | if (isEmpty() && other.isEmpty()) return false; |
272 | else if (isEmpty() || other.isEmpty()) return true; |
273 | |
274 | return convert<std::string>() != other.convert<std::string>(); |
275 | } |
276 | |
277 | |
278 | bool Var::operator != (const char* other) const |
279 | { |
280 | if (isEmpty()) return true; |
281 | return convert<std::string>() != other; |
282 | } |
283 | |
284 | |
285 | bool Var::operator < (const Var& other) const |
286 | { |
287 | if (isEmpty() || other.isEmpty()) return false; |
288 | return convert<std::string>() < other.convert<std::string>(); |
289 | } |
290 | |
291 | |
292 | bool Var::operator <= (const Var& other) const |
293 | { |
294 | if (isEmpty() || other.isEmpty()) return false; |
295 | return convert<std::string>() <= other.convert<std::string>(); |
296 | } |
297 | |
298 | |
299 | bool Var::operator > (const Var& other) const |
300 | { |
301 | if (isEmpty() || other.isEmpty()) return false; |
302 | return convert<std::string>() > other.convert<std::string>(); |
303 | } |
304 | |
305 | |
306 | bool Var::operator >= (const Var& other) const |
307 | { |
308 | if (isEmpty() || other.isEmpty()) return false; |
309 | return convert<std::string>() >= other.convert<std::string>(); |
310 | } |
311 | |
312 | |
313 | bool Var::operator || (const Var& other) const |
314 | { |
315 | if (isEmpty() || other.isEmpty()) return false; |
316 | return convert<bool>() || other.convert<bool>(); |
317 | } |
318 | |
319 | |
320 | bool Var::operator && (const Var& other) const |
321 | { |
322 | if (isEmpty() || other.isEmpty()) return false; |
323 | return convert<bool>() && other.convert<bool>(); |
324 | } |
325 | |
326 | |
327 | void Var::empty() |
328 | { |
329 | #ifdef POCO_NO_SOO |
330 | delete _pHolder; |
331 | _pHolder = 0; |
332 | #else |
333 | if (_placeholder.isLocal()) this->~Var(); |
334 | else delete content(); |
335 | _placeholder.erase(); |
336 | #endif |
337 | } |
338 | |
339 | |
340 | void Var::clear() |
341 | { |
342 | #ifdef POCO_NO_SOO |
343 | delete _pHolder; |
344 | _pHolder = 0; |
345 | #else |
346 | if (_placeholder.isLocal()) this->~Var(); |
347 | else delete content(); |
348 | _placeholder.erase(); |
349 | #endif |
350 | } |
351 | |
352 | |
353 | Var& Var::getAt(std::size_t n) |
354 | { |
355 | if (isVector()) |
356 | return holderImpl<std::vector<Var>, |
357 | InvalidAccessException>("Not a vector." )->operator[](n); |
358 | else if (isList()) |
359 | return holderImpl<std::list<Var>, |
360 | InvalidAccessException>("Not a list." )->operator[](n); |
361 | else if (isDeque()) |
362 | return holderImpl<std::deque<Var>, |
363 | InvalidAccessException>("Not a deque." )->operator[](n); |
364 | else if (isStruct()) |
365 | return structIndexOperator(holderImpl<Struct<int>, |
366 | InvalidAccessException>("Not a struct." ), static_cast<int>(n)); |
367 | else if (!isString() && !isEmpty() && (n == 0)) |
368 | return *this; |
369 | |
370 | throw RangeException("Index out of bounds." ); |
371 | } |
372 | |
373 | |
374 | char& Var::at(std::size_t n) |
375 | { |
376 | if (isString()) |
377 | { |
378 | return holderImpl<std::string, |
379 | InvalidAccessException>("Not a string." )->operator[](n); |
380 | } |
381 | |
382 | throw InvalidAccessException("Not a string." ); |
383 | } |
384 | |
385 | |
386 | Var& Var::getAt(const std::string& name) |
387 | { |
388 | return holderImpl<DynamicStruct, |
389 | InvalidAccessException>("Not a struct." )->operator[](name); |
390 | } |
391 | |
392 | |
393 | Var Var::parse(const std::string& val) |
394 | { |
395 | std::string::size_type t = 0; |
396 | return parse(val, t); |
397 | } |
398 | |
399 | |
400 | Var Var::parse(const std::string& val, std::string::size_type& pos) |
401 | { |
402 | // { -> an Object==DynamicStruct |
403 | // [ -> an array |
404 | // '/" -> a string (strip '/") |
405 | // other: also treat as string |
406 | skipWhiteSpace(val, pos); |
407 | if (pos < val.size()) |
408 | { |
409 | switch (val[pos]) |
410 | { |
411 | case '{': |
412 | return parseObject(val, pos); |
413 | case '[': |
414 | return parseArray(val, pos); |
415 | case '"': |
416 | return parseJSONString(val, pos); |
417 | default: |
418 | { |
419 | std::string str = parseString(val, pos); |
420 | if (str == "false" ) |
421 | return false; |
422 | |
423 | if (str == "true" ) |
424 | return true; |
425 | |
426 | bool isNumber = false; |
427 | bool isSigned = false; |
428 | int separators = 0; |
429 | int frac = 0; |
430 | int index = 0; |
431 | size_t size = str.size(); |
432 | for (size_t i = 0; i < size ; ++i) |
433 | { |
434 | int ch = str[i]; |
435 | if ((ch == '-' || ch == '+') && index == 0) |
436 | { |
437 | if (ch == '-') |
438 | isSigned = true; |
439 | } |
440 | else if (Ascii::isDigit(ch)) |
441 | { |
442 | isNumber |= true; |
443 | } |
444 | else if (ch == '.' || ch == ',') |
445 | { |
446 | frac = ch; |
447 | ++separators; |
448 | if (separators > 1) |
449 | return str; |
450 | } |
451 | else |
452 | return str; |
453 | |
454 | ++index; |
455 | } |
456 | |
457 | if (frac && isNumber) |
458 | { |
459 | const double number = NumberParser::parseFloat(str, frac); |
460 | return Var(number); |
461 | } |
462 | else if (frac == 0 && isNumber && isSigned) |
463 | { |
464 | const Poco::Int64 number = NumberParser::parse64(str); |
465 | return number; |
466 | } |
467 | else if (frac == 0 && isNumber && !isSigned) |
468 | { |
469 | const Poco::UInt64 number = NumberParser::parseUnsigned64(str); |
470 | return number; |
471 | } |
472 | |
473 | return str; |
474 | } |
475 | } |
476 | } |
477 | std::string empty; |
478 | return empty; |
479 | } |
480 | |
481 | |
482 | Var Var::parseObject(const std::string& val, std::string::size_type& pos) |
483 | { |
484 | poco_assert_dbg (pos < val.size() && val[pos] == '{'); |
485 | ++pos; |
486 | skipWhiteSpace(val, pos); |
487 | DynamicStruct aStruct; |
488 | while (val[pos] != '}' && pos < val.size()) |
489 | { |
490 | std::string key = parseString(val, pos); |
491 | skipWhiteSpace(val, pos); |
492 | if (val[pos] != ':') |
493 | throw DataFormatException("Incorrect object, must contain: key : value pairs" ); |
494 | ++pos; // skip past : |
495 | Var value = parse(val, pos); |
496 | aStruct.insert(key, value); |
497 | skipWhiteSpace(val, pos); |
498 | if (val[pos] == ',') |
499 | { |
500 | ++pos; |
501 | skipWhiteSpace(val, pos); |
502 | } |
503 | } |
504 | if (val[pos] != '}') |
505 | throw DataFormatException("Unterminated object" ); |
506 | ++pos; |
507 | return aStruct; |
508 | } |
509 | |
510 | |
511 | Var Var::parseArray(const std::string& val, std::string::size_type& pos) |
512 | { |
513 | poco_assert_dbg (pos < val.size() && val[pos] == '['); |
514 | ++pos; |
515 | skipWhiteSpace(val, pos); |
516 | std::vector<Var> result; |
517 | while (val[pos] != ']' && pos < val.size()) |
518 | { |
519 | result.push_back(parse(val, pos)); |
520 | skipWhiteSpace(val, pos); |
521 | if (val[pos] == ',') |
522 | { |
523 | ++pos; |
524 | skipWhiteSpace(val, pos); |
525 | } |
526 | } |
527 | if (val[pos] != ']') |
528 | throw DataFormatException("Unterminated array" ); |
529 | ++pos; |
530 | return result; |
531 | } |
532 | |
533 | |
534 | std::string Var::parseString(const std::string& val, std::string::size_type& pos) |
535 | { |
536 | poco_assert_dbg (pos < val.size()); |
537 | if (val[pos] == '"') |
538 | { |
539 | return parseJSONString(val, pos); |
540 | } |
541 | else |
542 | { |
543 | std::string result; |
544 | while (pos < val.size() |
545 | && !Poco::Ascii::isSpace(val[pos]) |
546 | && val[pos] != ',' |
547 | && val[pos] != ']' |
548 | && val[pos] != '}') |
549 | { |
550 | result += val[pos++]; |
551 | } |
552 | return result; |
553 | } |
554 | } |
555 | |
556 | |
557 | std::string Var::parseJSONString(const std::string& val, std::string::size_type& pos) |
558 | { |
559 | poco_assert_dbg (pos < val.size() && val[pos] == '"'); |
560 | ++pos; |
561 | std::string result; |
562 | bool done = false; |
563 | while (pos < val.size() && !done) |
564 | { |
565 | switch (val[pos]) |
566 | { |
567 | case '"': |
568 | done = true; |
569 | ++pos; |
570 | break; |
571 | case '\\': |
572 | if (pos < val.size()) |
573 | { |
574 | ++pos; |
575 | switch (val[pos]) |
576 | { |
577 | case 'b': |
578 | result += '\b'; |
579 | break; |
580 | case 'f': |
581 | result += '\f'; |
582 | break; |
583 | case 'n': |
584 | result += '\n'; |
585 | break; |
586 | case 'r': |
587 | result += '\r'; |
588 | break; |
589 | case 't': |
590 | result += '\t'; |
591 | break; |
592 | default: |
593 | result += val[pos]; |
594 | break; |
595 | } |
596 | break; |
597 | } |
598 | else |
599 | { |
600 | result += val[pos]; |
601 | } |
602 | ++pos; |
603 | break; |
604 | default: |
605 | result += val[pos++]; |
606 | break; |
607 | } |
608 | } |
609 | if (!done) throw Poco::DataFormatException("unterminated JSON string" ); |
610 | return result; |
611 | } |
612 | |
613 | |
614 | void Var::skipWhiteSpace(const std::string& val, std::string::size_type& pos) |
615 | { |
616 | poco_assert_dbg (pos < val.size()); |
617 | while (std::isspace(val[pos]) && pos < val.size()) |
618 | ++pos; |
619 | } |
620 | |
621 | |
622 | std::string Var::toString(const Var& any) |
623 | { |
624 | std::string res; |
625 | Impl::appendJSONValue(res, any); |
626 | return res; |
627 | } |
628 | |
629 | |
630 | Var& Var::structIndexOperator(VarHolderImpl<Struct<int> >* pStr, int n) const |
631 | { |
632 | return pStr->operator[](n); |
633 | } |
634 | |
635 | |
636 | } } // namespace Poco::Dynamic |
637 | |