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
24namespace Poco {
25namespace Dynamic {
26
27
28Var::Var()
29#ifdef POCO_NO_SOO
30 : _pHolder(0)
31#endif
32{
33}
34
35
36Var::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
48Var::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
61Var::~Var()
62{
63 destruct();
64}
65
66
67Var& 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
82const 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
100Var& 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
118const 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
134Var& 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
150const 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
166Var& 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
182const 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
198Var& 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
214Var& Var::operator ++ ()
215{
216 if (!isInteger())
217 throw InvalidArgumentException("Invalid operation for this data type.");
218
219 return *this = *this + 1;
220}
221
222
223const 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
234Var& Var::operator -- ()
235{
236 if (!isInteger())
237 throw InvalidArgumentException("Invalid operation for this data type.");
238
239 return *this = *this - 1;
240}
241
242
243const 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
254bool 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
262bool Var::operator == (const char* other) const
263{
264 if (isEmpty()) return false;
265 return convert<std::string>() == other;
266}
267
268
269bool 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
278bool Var::operator != (const char* other) const
279{
280 if (isEmpty()) return true;
281 return convert<std::string>() != other;
282}
283
284
285bool 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
292bool 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
299bool 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
306bool 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
313bool Var::operator || (const Var& other) const
314{
315 if (isEmpty() || other.isEmpty()) return false;
316 return convert<bool>() || other.convert<bool>();
317}
318
319
320bool Var::operator && (const Var& other) const
321{
322 if (isEmpty() || other.isEmpty()) return false;
323 return convert<bool>() && other.convert<bool>();
324}
325
326
327void 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
340void 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
353Var& 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
374char& 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
386Var& Var::getAt(const std::string& name)
387{
388 return holderImpl<DynamicStruct,
389 InvalidAccessException>("Not a struct.")->operator[](name);
390}
391
392
393Var Var::parse(const std::string& val)
394{
395 std::string::size_type t = 0;
396 return parse(val, t);
397}
398
399
400Var 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
482Var 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
511Var 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
534std::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
557std::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
614void 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
622std::string Var::toString(const Var& any)
623{
624 std::string res;
625 Impl::appendJSONValue(res, any);
626 return res;
627}
628
629
630Var& Var::structIndexOperator(VarHolderImpl<Struct<int> >* pStr, int n) const
631{
632 return pStr->operator[](n);
633}
634
635
636} } // namespace Poco::Dynamic
637