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
25namespace Poco {
26namespace Dynamic {
27
28
29Var::Var()
30#ifdef POCO_NO_SOO
31 : _pHolder(0)
32#endif
33{
34}
35
36
37Var::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
49Var::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
62Var::~Var()
63{
64 destruct();
65}
66
67
68Var& 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
83const 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
101Var& 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
119const 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
135Var& 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
151const 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
167Var& 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
183const 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
199Var& 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
215Var& Var::operator ++ ()
216{
217 if (!isInteger())
218 throw InvalidArgumentException("Invalid operation for this data type.");
219
220 return *this = *this + 1;
221}
222
223
224const 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
235Var& Var::operator -- ()
236{
237 if (!isInteger())
238 throw InvalidArgumentException("Invalid operation for this data type.");
239
240 return *this = *this - 1;
241}
242
243
244const 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
255bool 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
263bool Var::operator == (const char* other) const
264{
265 if (isEmpty()) return false;
266 return convert<std::string>() == other;
267}
268
269
270bool 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
279bool Var::operator != (const char* other) const
280{
281 if (isEmpty()) return true;
282 return convert<std::string>() != other;
283}
284
285
286bool 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
293bool 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
300bool 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
307bool 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
314bool Var::operator || (const Var& other) const
315{
316 if (isEmpty() || other.isEmpty()) return false;
317 return convert<bool>() || other.convert<bool>();
318}
319
320
321bool Var::operator && (const Var& other) const
322{
323 if (isEmpty() || other.isEmpty()) return false;
324 return convert<bool>() && other.convert<bool>();
325}
326
327
328void 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
341void 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
354Var& 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
383char& 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
395Var& 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
411Var Var::parse(const std::string& val)
412{
413 std::string::size_type t = 0;
414 return parse(val, t);
415}
416
417
418Var 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
492Var 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
521Var 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
544std::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
567std::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
624void 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
632std::string Var::toString(const Var& any)
633{
634 std::string res;
635 Impl::appendJSONValue(res, any);
636 return res;
637}
638
639/*
640Var& Var::structIndexOperator(VarHolderImpl<Struct<int> >* pStr, int n) const
641{
642 return pStr->operator[](n);
643}
644*/
645
646} } // namespace Poco::Dynamic
647