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