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