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