1 /*
2 * Copyright (C) 2005-2008 by Dr. Marc Boris Duerner
3 * Copyright (C) 2011 by Tommi Maekitalo
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * As a special exception, you may use this file as part of a free
11 * software library without restriction. Specifically, if other files
12 * instantiate templates or use macros or inline functions from this
13 * file, or you compile this file and link it with other files to
14 * produce an executable, this file does not by itself cause the
15 * resulting executable to be covered by the GNU General Public
16 * License. This exception does not however invalidate any other
17 * reasons why the executable file might be covered by the GNU Library
18 * General Public License.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30 #include <cxxtools/serializationinfo.h>
31 #include <stdexcept>
32 #include <sstream>
33
34 namespace cxxtools
35 {
36
SerializationInfo()37 SerializationInfo::SerializationInfo()
38 : _parent(0)
39 , _category(Void)
40 , _t(t_none)
41 { }
42
43
SerializationInfo(const SerializationInfo & si)44 SerializationInfo::SerializationInfo(const SerializationInfo& si)
45 : _parent(si._parent)
46 , _category(si._category)
47 , _name(si._name)
48 , _type(si._type)
49 , _u(si._u)
50 , _t(si._t)
51 , _nodes(si._nodes)
52 {
53 switch (_t)
54 {
55 case t_string: new (_StringPtr()) String(si._String());
56 break;
57
58 case t_string8: new (_String8Ptr()) std::string(si._String8());
59 break;
60
61 default:
62 ;
63 }
64 }
65
66
operator =(const SerializationInfo & si)67 SerializationInfo& SerializationInfo::operator=(const SerializationInfo& si)
68 {
69 _parent = si._parent;
70 _category = si._category;
71 _name = si._name;
72 _type = si._type;
73 _nodes = si._nodes;
74
75 if (si._t == t_string)
76 _setString( si._String() );
77 else if (si._t == t_string8)
78 _setString8( si._String8() );
79 else
80 {
81 _releaseValue();
82 _u = si._u;
83 _t = si._t;
84 }
85
86 return *this;
87 }
88
89
reserve(size_t n)90 void SerializationInfo::reserve(size_t n)
91 {
92 _nodes.reserve(n);
93 }
94
95
addMember(const std::string & name)96 SerializationInfo& SerializationInfo::addMember(const std::string& name)
97 {
98 _nodes.resize(_nodes.size() + 1);
99 _nodes.back().setParent(*this);
100 _nodes.back().setName(name);
101
102 // category Array overrides Object (is this a hack?)
103 // This is needed for xmldeserialization. In the xml file the root node of a array
104 // has a category attribute. When the serializationinfo of the array is created
105 // it is known, that it is of category Array. When the members of the array are read,
106 // they should not make an object out of the array.
107 if (_category != Array)
108 _category = Object;
109
110 return _nodes.back();
111 }
112
113
begin()114 SerializationInfo::Iterator SerializationInfo::begin()
115 {
116 if(_nodes.size() == 0)
117 return 0;
118
119 return &( _nodes[0] );
120 }
121
122
end()123 SerializationInfo::Iterator SerializationInfo::end()
124 {
125 if(_nodes.size() == 0)
126 return 0;
127
128 return &_nodes[0] + _nodes.size();
129 }
130
131
begin() const132 SerializationInfo::ConstIterator SerializationInfo::begin() const
133 {
134 if(_nodes.size() == 0)
135 return 0;
136
137 return &( _nodes[0] );
138 }
139
140
end() const141 SerializationInfo::ConstIterator SerializationInfo::end() const
142 {
143 if(_nodes.size() == 0)
144 return 0;
145
146 return &_nodes[0] + _nodes.size();
147 }
148
149
getMember(const std::string & name) const150 const SerializationInfo& SerializationInfo::getMember(const std::string& name) const
151 {
152 Nodes::const_iterator it = _nodes.begin();
153 for(; it != _nodes.end(); ++it)
154 {
155 if( it->name() == name )
156 return *it;
157 }
158
159 throw SerializationMemberNotFound(name);
160 }
161
162
getMember(unsigned idx) const163 const SerializationInfo& SerializationInfo::getMember(unsigned idx) const
164 {
165 if (idx >= _nodes.size())
166 {
167 std::ostringstream msg;
168 msg << "requested member index " << idx << " exceeds number of members " << _nodes.size();
169 throw std::range_error(msg.str());
170 }
171
172 return _nodes[idx];
173 }
174
175
findMember(const std::string & name) const176 const SerializationInfo* SerializationInfo::findMember(const std::string& name) const
177 {
178 Nodes::const_iterator it = _nodes.begin();
179 for(; it != _nodes.end(); ++it)
180 {
181 if( it->name() == name )
182 return &(*it);
183 }
184
185 return 0;
186 }
187
188
findMember(const std::string & name)189 SerializationInfo* SerializationInfo::findMember(const std::string& name)
190 {
191 Nodes::iterator it = _nodes.begin();
192 for(; it != _nodes.end(); ++it)
193 {
194 if( it->name() == name )
195 return &(*it);
196 }
197
198 return 0;
199 }
200
clear()201 void SerializationInfo::clear()
202 {
203 _category = Void;
204 _name.clear();
205 _type.clear();
206 _nodes.clear();
207 switch (_t)
208 {
209 case t_string: _String().clear(); break;
210 case t_string8: _String8().clear(); break;
211 default: _t = t_none; break;
212 }
213 }
214
swap(SerializationInfo & si)215 void SerializationInfo::swap(SerializationInfo& si)
216 {
217 if (this == &si)
218 return;
219
220 std::swap(_parent, si._parent);
221 std::swap(_category, si._category);
222 std::swap(_name, si._name);
223 std::swap(_type, si._type);
224
225 if (_t == t_string)
226 {
227 if (si._t == t_string)
228 {
229 // this: String, other: String
230 _String().swap(si._String());
231 }
232 else if (si._t == t_string8)
233 {
234 // this: String, other: std::string
235 std::string s;
236 si._String8().swap(s);
237 si.setValue(String());
238 si._String().swap(_String());
239 setValue(s);
240 }
241 else
242 {
243 // this: String, other: something
244 U u = si._u;
245 T t = si._t;
246 si.setValue(String());
247 _String().swap(si._String());
248 _releaseValue();
249 _u = u;
250 _t = t;
251 }
252 }
253 else if (_t == t_string8)
254 {
255 if (si._t == t_string)
256 {
257 // this: std::string, other: String
258 String s;
259 si._String().swap(s);
260 si.setValue(std::string());
261 _String8().swap(si._String8());
262 setValue(s);
263 }
264 else if (si._t == t_string8)
265 {
266 // this: std::string, other: std::string
267 _String8().swap(si._String8());
268 }
269 else
270 {
271 // this: std::string, other: something
272 U u = si._u;
273 T t = si._t;
274 si.setValue(_String8());
275 _releaseValue();
276 _u = u;
277 _t = t;
278 }
279 }
280 else
281 {
282 if (si._t == t_string)
283 {
284 // this: something, other: String
285 U u = _u;
286 T t = _t;
287 setValue(si._String());
288 si._releaseValue();
289 si._u = u;
290 si._t = t;
291 }
292 else if (si._t == t_string8)
293 {
294 // this: something, other: std::string
295 U u = _u;
296 T t = _t;
297 setValue(si._String8());
298 si._releaseValue();
299 si._u = u;
300 si._t = t;
301 }
302 else
303 {
304 // this: something, other: something
305 std::swap(_u, si._u);
306 std::swap(_t, si._t);
307 }
308 }
309
310 _nodes.swap(si._nodes);
311 }
312
dump(std::ostream & out,const std::string & praefix) const313 void SerializationInfo::dump(std::ostream& out, const std::string& praefix) const
314 {
315 if (!_name.empty())
316 out << praefix << "name = \"" << _name << "\"\n";
317
318 if (_t != t_none)
319 {
320 out << praefix << "type = " << (_t == t_none ? "none" :
321 _t == t_string ? "string" :
322 _t == t_string8 ? "string8" :
323 _t == t_char ? "char" :
324 _t == t_bool ? "bool" :
325 _t == t_int ? "int" :
326 _t == t_uint ? "uint" :
327 _t == t_float ? "float" : "?") << '\n';
328
329 out << praefix << "value = ";
330
331 switch (_t)
332 {
333 case t_none: out << '-'; break;
334 case t_string: out << '"' << _String().narrow() << '"'; break;
335 case t_string8: out << '"' << _String8() << '"'; break;
336 case t_char: out << '\'' << _u._c << '\''; break;
337 case t_bool: out << _u._b; break;
338 case t_int: out << _u._i; break;
339 case t_uint: out << _u._u; break;
340 case t_float: out << _u._f; break;
341 }
342
343 out << '\n';
344 }
345
346 if (!_type.empty())
347 out << praefix << "typeName = " << _type << '\n';
348 if (!_nodes.empty())
349 {
350 std::string p = praefix + '\t';
351 for (std::vector<SerializationInfo>::size_type n = 0; n < _nodes.size(); ++n)
352 {
353 out << praefix << "node[" << n << "]\n";
354 _nodes[n].dump(out, p);
355 }
356 }
357 }
358
_releaseValue()359 void SerializationInfo::_releaseValue()
360 {
361 switch (_t)
362 {
363 case t_string: _String().~String(); break;
364 case t_string8:
365 {
366 // I don't know how to call the destructor without 'using' so that
367 // both gcc and xlc understand it.
368 using std::string;
369 _String8().~string();
370 break;
371 }
372
373 default:
374 ;
375 }
376 _t = t_none;
377 }
378
setNull()379 void SerializationInfo::setNull()
380 {
381 _releaseValue();
382 _t = t_none;
383 _category = Void;
384 }
385
_setString(const String & value)386 void SerializationInfo::_setString(const String& value)
387 {
388 if (_t != t_string)
389 {
390 _releaseValue();
391 new (_StringPtr()) String(value);
392 _t = t_string;
393 }
394 else
395 {
396 _String().assign(value);
397 }
398
399 _category = Value;
400 }
401
_setString8(const std::string & value)402 void SerializationInfo::_setString8(const std::string& value)
403 {
404 if (_t != t_string8)
405 {
406 _releaseValue();
407 new (_String8Ptr()) std::string(value);
408 _t = t_string8;
409 }
410 else
411 {
412 _String8().assign(value);
413 }
414
415 _category = Value;
416 }
417
_setString8(const char * value)418 void SerializationInfo::_setString8(const char* value)
419 {
420 if (_t != t_string8)
421 {
422 _releaseValue();
423 new (_String8Ptr()) std::string(value);
424 _t = t_string8;
425 }
426 else
427 {
428 _String8().assign(value);
429 }
430
431 _category = Value;
432 }
433
_setChar(char value)434 void SerializationInfo::_setChar(char value)
435 {
436 if (_t != t_char)
437 {
438 _releaseValue();
439 _t = t_char;
440 }
441
442 _u._c = value;
443
444 _category = Value;
445 }
446
_setBool(bool value)447 void SerializationInfo::_setBool(bool value)
448 {
449 if (_t != t_bool)
450 {
451 _releaseValue();
452 _t = t_bool;
453 }
454
455 _u._b = value;
456
457 _category = Value;
458 }
459
_setInt(int_type value)460 void SerializationInfo::_setInt(int_type value)
461 {
462 if (_t != t_int)
463 {
464 _releaseValue();
465 _t = t_int;
466 }
467
468 _u._i = value;
469
470 _category = Value;
471 }
472
_setUInt(unsigned_type value)473 void SerializationInfo::_setUInt(unsigned_type value)
474 {
475 if (_t != t_uint)
476 {
477 _releaseValue();
478 _t = t_uint;
479 }
480
481 _u._u= value;
482
483 _category = Value;
484 }
485
_setFloat(long double value)486 void SerializationInfo::_setFloat(long double value)
487 {
488 if (_t != t_float)
489 {
490 _releaseValue();
491 _t = t_float;
492 }
493
494 _u._f = value;
495
496 _category = Value;
497 }
498
499
getValue(String & value) const500 void SerializationInfo::getValue(String& value) const
501 {
502 switch (_t)
503 {
504 case t_none: value.clear(); break;
505 case t_string: value.assign(_String()); break;
506 case t_string8: value.assign(_String8()); break;
507 case t_char: value.assign(1, _u._c); break;
508 case t_bool: convert(value, _u._b); break;
509 case t_int: convert(value, _u._i); break;
510 case t_uint: convert(value, _u._u); break;
511 case t_float: convert(value, _u._f); break;
512 }
513 }
514
getValue(std::string & value) const515 void SerializationInfo::getValue(std::string& value) const
516 {
517 switch (_t)
518 {
519 case t_none: value.clear(); break;
520 case t_string: value = _String().narrow(); break;
521 case t_string8: value.assign(_String8()); break;
522 case t_char: value.assign(1, _u._c); break;
523 case t_bool: convert(value, _u._b); break;
524 case t_int: convert(value, _u._i); break;
525 case t_uint: convert(value, _u._u); break;
526 case t_float: convert(value, _u._f); break;
527 }
528 }
529
530 namespace
531 {
isFalse(char c)532 inline bool isFalse(char c)
533 {
534 return c == '\0'
535 || c == '0'
536 || c == 'f'
537 || c == 'F'
538 || c == 'n'
539 || c == 'N';
540 }
541 }
542
_getBool() const543 bool SerializationInfo::_getBool() const
544 {
545 switch (_t)
546 {
547 case t_none: return false;
548 case t_string: return !_String().empty() && !isFalse((_String())[0].narrow());
549 case t_string8: return !_String8().empty() && !isFalse((_String8())[0]);
550 case t_char: return !isFalse(_u._c);
551 case t_bool: return _u._b;
552 case t_int: return _u._i;
553 case t_uint: return _u._u;
554 case t_float: return _u._f;
555 }
556
557 // never reached
558 return false;
559 }
560
_getWChar() const561 wchar_t SerializationInfo::_getWChar() const
562 {
563 switch (_t)
564 {
565 case t_none: return L'\0';
566 case t_string: return _String().empty() ? L'\0' : _String()[0].toWchar();
567 case t_string8: return _String8().empty() ? '\0' : _String8()[0];
568 case t_char: return _u._c;
569 case t_bool: return _u._b;
570 case t_int: return _u._i;
571 case t_uint: return _u._u;
572 case t_float: return static_cast<wchar_t>(_u._f);
573 }
574
575 // never reached
576 return 0;
577 }
578
_getChar() const579 char SerializationInfo::_getChar() const
580 {
581 switch (_t)
582 {
583 case t_none: return '\0'; break;
584 case t_string: return _String().empty() ? '\0' : (_String())[0].narrow(); break;
585 case t_string8: return _String8().empty() ? '\0' : (_String8())[0]; break;
586 case t_char: return _u._c; break;
587 case t_bool: return _u._b; break;
588 case t_int: return _u._i; break;
589 case t_uint: return _u._u; break;
590 case t_float: return static_cast<char>(_u._f); break;
591 }
592 // never reached
593 return 0;
594 }
595
_getInt(const char * type,int_type min,int_type max) const596 SerializationInfo::int_type SerializationInfo::_getInt(const char* type, int_type min, int_type max) const
597 {
598 int_type ret = 0;
599
600 switch (_t)
601 {
602 case t_none: break;
603
604 case t_string: try
605 {
606 ret = convert<int_type>(_String());
607 }
608 catch (const ConversionError&)
609 {
610 ConversionError::doThrow(type, "String", _String().narrow().c_str());
611 }
612 break;
613
614 case t_string8: try
615 {
616 ret = convert<int_type>(_String8());
617 }
618 catch (const ConversionError&)
619 {
620 ConversionError::doThrow(type, "string", _String8().c_str());
621 }
622 break;
623
624 case t_char: ret = _u._c - '0'; break;
625 case t_bool: ret = _u._b; break;
626 case t_int: ret = _u._i; break;
627 case t_uint: if (_u._u > static_cast<unsigned_type>(std::numeric_limits<int_type>::max()))
628 {
629 std::ostringstream msg;
630 msg << "value " << ret << " does not fit into " << type;
631 throw std::range_error(msg.str());
632 }
633 ret = _u._u; break;
634 case t_float: ret = static_cast<int_type>(_u._f); break;
635 }
636
637 if (ret < min || ret > max)
638 {
639 std::ostringstream msg;
640 msg << "value " << ret << " does not fit into " << type;
641 throw std::range_error(msg.str());
642 }
643
644 return ret;
645 }
646
_getUInt(const char * type,unsigned_type max) const647 SerializationInfo::unsigned_type SerializationInfo::_getUInt(const char* type, unsigned_type max) const
648 {
649 unsigned_type ret = 0;
650
651 switch (_t)
652 {
653 case t_none: break;
654
655 case t_string: try
656 {
657 ret = convert<unsigned_type>(_String());
658 }
659 catch (const ConversionError&)
660 {
661 ConversionError::doThrow(type, "String", _String().narrow().c_str());
662 }
663 break;
664
665 case t_string8: try
666 {
667 ret = convert<unsigned_type>(_String8());
668 }
669 catch (const ConversionError&)
670 {
671 ConversionError::doThrow(type, "string", _String8().c_str());
672 }
673 break;
674
675 case t_char: ret = _u._c - '0'; break;
676 case t_bool: ret = _u._b; break;
677 case t_int: if (_u._i < 0)
678 throw std::range_error(std::string("negative values do not fit into ") + type);
679 ret = _u._i;
680 break;
681 case t_uint: ret = _u._u; break;
682 case t_float: ret = static_cast<unsigned_type>(_u._f); break;
683 }
684
685 if (ret > max)
686 {
687 std::ostringstream msg;
688 msg << "value " << ret << " does not fit into " << type;
689 throw std::range_error(msg.str());
690 }
691
692 return ret;
693 }
694
_getFloat(const char * type,long double max) const695 long double SerializationInfo::_getFloat(const char* type, long double max) const
696 {
697 long double ret = 0;
698
699 switch (_t)
700 {
701 case t_none: break;
702
703 case t_string: try
704 {
705 ret = convert<long double>(_String());
706 }
707 catch (const ConversionError&)
708 {
709 ConversionError::doThrow(type, "String", _String().narrow().c_str());
710 }
711 break;
712
713 case t_string8: try
714 {
715 ret = convert<long double>(_String8());
716 }
717 catch (const ConversionError&)
718 {
719 ConversionError::doThrow(type, "string", _String8().c_str());
720 }
721 break;
722
723 case t_char: ret = _u._c - '0'; break;
724 case t_bool: ret = _u._b; break;
725 case t_int: ret = _u._i; break;
726 case t_uint: ret = _u._u; break;
727 case t_float: ret = _u._f; break;
728 }
729
730 if (ret != std::numeric_limits<long double>::infinity()
731 && ret != -std::numeric_limits<long double>::infinity()
732 && ret == ret // check for NaN
733 && (ret < -max || ret > max))
734 {
735 std::ostringstream msg;
736 msg << "value " << ret << " does not fit into " << type;
737 throw std::range_error(msg.str());
738 }
739
740 return ret;
741 }
742
743
744 } // namespace cxxtools
745