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
Var()28 Var::Var()
29 #ifdef POCO_NO_SOO
30 : _pHolder(0)
31 #endif
32 {
33 }
34
35
Var(const char * pVal)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
Var(const Var & other)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
~Var()61 Var::~Var()
62 {
63 destruct();
64 }
65
66
operator =(const Var & rhs)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
operator +(const Var & other) const82 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
operator +=(const Var & other)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
operator -(const Var & other) const118 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
operator -=(const Var & other)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
operator *(const Var & other) const150 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
operator *=(const Var & other)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
operator /(const Var & other) const182 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
operator /=(const Var & other)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
operator ++()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
operator ++(int)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
operator --()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
operator --(int)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
operator ==(const Var & other) const254 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
operator ==(const char * other) const262 bool Var::operator == (const char* other) const
263 {
264 if (isEmpty()) return false;
265 return convert<std::string>() == other;
266 }
267
268
operator !=(const Var & other) const269 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
operator !=(const char * other) const278 bool Var::operator != (const char* other) const
279 {
280 if (isEmpty()) return true;
281 return convert<std::string>() != other;
282 }
283
284
operator <(const Var & other) const285 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
operator <=(const Var & other) const292 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
operator >(const Var & other) const299 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
operator >=(const Var & other) const306 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
operator ||(const Var & other) const313 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
operator &&(const Var & other) const320 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
empty()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
clear()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
getAt(std::size_t n)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 {
366 if (isOrdered())
367 return structIndexOperator(holderImpl<Struct<int, OrderedMap<int, Var>, OrderedSet<int>>,
368 InvalidAccessException>("Not a struct."), static_cast<int>(n));
369 else
370 return structIndexOperator(holderImpl<Struct<int, std::map<int, Var>, std::set<int>>,
371 InvalidAccessException>("Not a struct."), static_cast<int>(n));
372 }
373 else if (!isString() && !isEmpty() && (n == 0))
374 return *this;
375
376 throw RangeException("Index out of bounds.");
377 }
378
379
at(std::size_t n)380 char& Var::at(std::size_t n)
381 {
382 if (isString())
383 {
384 return holderImpl<std::string,
385 InvalidAccessException>("Not a string.")->operator[](n);
386 }
387
388 throw InvalidAccessException("Not a string.");
389 }
390
391
getAt(const std::string & name)392 Var& Var::getAt(const std::string& name)
393 {
394 if (isStruct())
395 {
396 if (isOrdered())
397 return structIndexOperator(holderImpl<OrderedDynamicStruct, InvalidAccessException>("Not a struct."), name);
398 else
399 return structIndexOperator(holderImpl<DynamicStruct, InvalidAccessException>("Not a struct."), name);
400 }
401
402 throw InvalidAccessException("Not a struct.");
403 }
404
405
parse(const std::string & val)406 Var Var::parse(const std::string& val)
407 {
408 std::string::size_type t = 0;
409 return parse(val, t);
410 }
411
412
parse(const std::string & val,std::string::size_type & pos)413 Var Var::parse(const std::string& val, std::string::size_type& pos)
414 {
415 // { -> an Object==DynamicStruct
416 // [ -> an array
417 // '/" -> a string (strip '/")
418 // other: also treat as string
419 skipWhiteSpace(val, pos);
420 if (pos < val.size())
421 {
422 switch (val[pos])
423 {
424 case '{':
425 return parseObject(val, pos);
426 case '[':
427 return parseArray(val, pos);
428 case '"':
429 return parseJSONString(val, pos);
430 default:
431 {
432 std::string str = parseString(val, pos);
433 if (str == "false")
434 return false;
435
436 if (str == "true")
437 return true;
438
439 bool isNumber = false;
440 bool isSigned = false;
441 int separators = 0;
442 int frac = 0;
443 int index = 0;
444 size_t size = str.size();
445 for (size_t i = 0; i < size ; ++i)
446 {
447 int ch = str[i];
448 if ((ch == '-' || ch == '+') && index == 0)
449 {
450 if (ch == '-')
451 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)
462 return str;
463 }
464 else
465 return str;
466
467 ++index;
468 }
469
470 if (frac && isNumber)
471 {
472 const double number = NumberParser::parseFloat(str, frac);
473 return Var(number);
474 }
475 else if (frac == 0 && isNumber && isSigned)
476 {
477 const Poco::Int64 number = NumberParser::parse64(str);
478 return number;
479 }
480 else if (frac == 0 && isNumber && !isSigned)
481 {
482 const Poco::UInt64 number = NumberParser::parseUnsigned64(str);
483 return number;
484 }
485
486 return str;
487 }
488 }
489 }
490 std::string empty;
491 return empty;
492 }
493
494
parseObject(const std::string & val,std::string::size_type & pos)495 Var Var::parseObject(const std::string& val, std::string::size_type& pos)
496 {
497 poco_assert_dbg (pos < val.size() && val[pos] == '{');
498 ++pos;
499 skipWhiteSpace(val, pos);
500 DynamicStruct aStruct;
501 while (val[pos] != '}' && pos < val.size())
502 {
503 std::string key = parseString(val, pos);
504 skipWhiteSpace(val, pos);
505 if (val[pos] != ':')
506 throw DataFormatException("Incorrect object, must contain: key : value pairs");
507 ++pos; // skip past :
508 Var value = parse(val, pos);
509 aStruct.insert(key, value);
510 skipWhiteSpace(val, pos);
511 if (val[pos] == ',')
512 {
513 ++pos;
514 skipWhiteSpace(val, pos);
515 }
516 }
517 if (val[pos] != '}')
518 throw DataFormatException("Unterminated object");
519 ++pos;
520 return aStruct;
521 }
522
523
parseArray(const std::string & val,std::string::size_type & pos)524 Var Var::parseArray(const std::string& val, std::string::size_type& pos)
525 {
526 poco_assert_dbg (pos < val.size() && val[pos] == '[');
527 ++pos;
528 skipWhiteSpace(val, pos);
529 std::vector<Var> result;
530 while (val[pos] != ']' && pos < val.size())
531 {
532 result.push_back(parse(val, pos));
533 skipWhiteSpace(val, pos);
534 if (val[pos] == ',')
535 {
536 ++pos;
537 skipWhiteSpace(val, pos);
538 }
539 }
540 if (val[pos] != ']')
541 throw DataFormatException("Unterminated array");
542 ++pos;
543 return result;
544 }
545
546
parseString(const std::string & val,std::string::size_type & pos)547 std::string Var::parseString(const std::string& val, std::string::size_type& pos)
548 {
549 poco_assert_dbg (pos < val.size());
550 if (val[pos] == '"')
551 {
552 return parseJSONString(val, pos);
553 }
554 else
555 {
556 std::string result;
557 while (pos < val.size()
558 && !Poco::Ascii::isSpace(val[pos])
559 && val[pos] != ','
560 && val[pos] != ']'
561 && val[pos] != '}')
562 {
563 result += val[pos++];
564 }
565 return result;
566 }
567 }
568
569
parseJSONString(const std::string & val,std::string::size_type & pos)570 std::string Var::parseJSONString(const std::string& val, std::string::size_type& pos)
571 {
572 poco_assert_dbg (pos < val.size() && val[pos] == '"');
573 ++pos;
574 std::string result;
575 bool done = false;
576 while (pos < val.size() && !done)
577 {
578 switch (val[pos])
579 {
580 case '"':
581 done = true;
582 ++pos;
583 break;
584 case '\\':
585 if (pos < val.size() - 1)
586 {
587 ++pos;
588 switch (val[pos])
589 {
590 case 'b':
591 result += '\b';
592 break;
593 case 'f':
594 result += '\f';
595 break;
596 case 'n':
597 result += '\n';
598 break;
599 case 'r':
600 result += '\r';
601 break;
602 case 't':
603 result += '\t';
604 break;
605 default:
606 result += val[pos];
607 break;
608 }
609 }
610 else
611 {
612 result += val[pos];
613 }
614 ++pos;
615 break;
616 default:
617 result += val[pos++];
618 break;
619 }
620 }
621 if (!done) throw Poco::DataFormatException("unterminated JSON string");
622 return result;
623 }
624
625
skipWhiteSpace(const std::string & val,std::string::size_type & pos)626 void Var::skipWhiteSpace(const std::string& val, std::string::size_type& pos)
627 {
628 poco_assert_dbg (pos < val.size());
629 while (std::isspace(val[pos]) && pos < val.size())
630 ++pos;
631 }
632
633
toString(const Var & any)634 std::string Var::toString(const Var& any)
635 {
636 std::string res;
637 Impl::appendJSONValue(res, any);
638 return res;
639 }
640
641 /*
642 Var& Var::structIndexOperator(VarHolderImpl<Struct<int>>* pStr, int n) const
643 {
644 return pStr->operator[](n);
645 }
646 */
647
648 } } // namespace Poco::Dynamic
649