1 #pragma once
2 /*
3  * DataElement/DataNode/DataTree -- structured serialization/deserialization system
4  * designed for the CoolMule project :)
5  *
6  Copyright (C) 2003 by Charles J. Cliffe
7 
8  Permission is hereby granted, free of charge, to any person obtaining a copy
9  of this software and associated documentation files (the "Software"), to deal
10  in the Software without restriction, including without limitation the rights
11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  copies of the Software, and to permit persons to whom the Software is
13  furnished to do so, subject to the following conditions:
14 
15  The above copyright notice and this permission notice shall be included in
16  all copies or substantial portions of the Software.
17 
18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  THE SOFTWARE.
25  */
26 
27 #include <vector>
28 #include <map>
29 #include <set>
30 #include <string>
31 #include <sstream>
32 #include <stack>
33 #include <iostream>
34 #include "tinyxml.h"
35 
36 using namespace std;
37 
38 
39 /* map comparison function */
40 struct string_less
41 {
operatorstring_less42  bool operator()(const std::string& a,const std::string& b) const
43  {
44   return a.compare(b) < 0;
45  }
46 };
47 
48 
49 
50 /* Data Exceptions */
51 class DataException : public exception
52 {
53 private:
54     string reason;
55 
56 public:
DataException(const char * why)57     explicit DataException(const char *why) : reason(why) {}
what()58     const char* what() const noexcept override { return reason.c_str(); }
string()59     explicit operator string() { return reason; }
60 };
61 
62 
63 class DataTypeMismatchException : public DataException
64 {
65 public:
DataTypeMismatchException(const char * why)66     explicit DataTypeMismatchException(const char *why) : DataException(why) { }
67 };
68 
69 
70 class DataInvalidChildException : public DataException
71 {
72 public:
DataInvalidChildException(const char * why)73     explicit DataInvalidChildException(const char *why) : DataException(why) { }
74 };
75 
76 
77 class DataElement
78 {
79 public :
80 
81     enum class Type {
82         DATA_NULL,
83         DATA_CHAR,
84         DATA_UCHAR,
85         DATA_INT,
86         DATA_UINT,
87         DATA_LONG,
88         DATA_ULONG,
89         DATA_LONGLONG,
90         DATA_FLOAT,
91         DATA_DOUBLE,
92         DATA_STRING,
93         DATA_STR_VECTOR,
94         DATA_CHAR_VECTOR,
95         DATA_UCHAR_VECTOR,
96         DATA_INT_VECTOR,
97         DATA_UINT_VECTOR,
98         DATA_LONG_VECTOR,
99         DATA_ULONG_VECTOR,
100         DATA_LONGLONG_VECTOR,
101         DATA_FLOAT_VECTOR,
102         DATA_DOUBLE_VECTOR,
103         DATA_VOID,
104         DATA_WSTRING
105     };
106 
107     typedef vector<unsigned char> DataElementBuffer;
108 
109     typedef vector< DataElementBuffer > DataElementBufferVector;
110 
111 private:
112     Type data_type;
113 
114     // raw buffer holding data_type element in bytes form.
115     DataElementBuffer data_val;
116 
117     //keep the vector of types in a spearate vector of DataElementBuffer.
118     DataElementBufferVector data_val_vector;
119 
120    //specializations to extract type: (need to be declared/done OUTSIDE of class scope else "Error: explicit specialization is not allowed in the current scope")
121    //this is apparently fixed in C++17...
122    // so we need to workaround it with a partial specialization using a fake Dummy parameter.
123 
124     //if the exact right determineScalarDataType specialization was not used, throw exception at runtime.
125     template<typename U, typename Dummy = int >
determineScalarDataType(const U &)126     Type determineScalarDataType(const U& /* type_in */) { throw DataTypeMismatchException("determineScalarDataType(U) usage with unsupported type !"); }
127 
128     template< typename Dummy = int >
determineScalarDataType(const char &)129    Type determineScalarDataType(const char& /* type_in */) { return DataElement::Type::DATA_CHAR; }
130 
131     template< typename Dummy = int >
determineScalarDataType(const unsigned char &)132     Type determineScalarDataType(const unsigned char& /* type_in */) { return DataElement::Type::DATA_UCHAR; }
133 
134     template< typename Dummy = int >
determineScalarDataType(const int &)135     Type determineScalarDataType(const int& /* type_in */) { return DataElement::Type::DATA_INT; }
136 
137     template< typename Dummy = int >
determineScalarDataType(const unsigned int &)138     Type determineScalarDataType(const unsigned int& /* type_in */) { return DataElement::Type::DATA_UINT; }
139 
140     template< typename Dummy = int >
determineScalarDataType(const long &)141     Type determineScalarDataType(const long& /* type_in */) { return DataElement::Type::DATA_LONG; }
142 
143     template< typename Dummy = int >
determineScalarDataType(const unsigned long &)144     Type determineScalarDataType(const unsigned long& /* type_in */) { return DataElement::Type::DATA_ULONG; }
145 
146     template< typename Dummy = int >
determineScalarDataType(const long long &)147     Type determineScalarDataType(const long long& /* type_in */) { return DataElement::Type::DATA_LONGLONG; }
148 
149     template< typename Dummy = int >
determineScalarDataType(const float &)150     Type determineScalarDataType(const float& /* type_in */) { return DataElement::Type::DATA_FLOAT; }
151 
152     template< typename Dummy = int >
determineScalarDataType(const double &)153     Type determineScalarDataType(const double& /* type_in */) { return DataElement::Type::DATA_DOUBLE; }
154 
155     //vector versions:
156     //if the exact right determineVectorDataType specialization was not used, throw exception at runtime.
157     template<typename V, typename Dummy = int >
determineVectorDataType(const vector<V> &)158     Type determineVectorDataType(const vector<V>& /* type_in */) { throw DataTypeMismatchException("determineVectorDataType(V) usage with unsupported type !"); }
159 
160     template< typename Dummy = int >
determineVectorDataType(const vector<char> &)161     Type determineVectorDataType(const vector<char>& /* type_in */) { return DataElement::Type::DATA_CHAR_VECTOR; }
162 
163     template< typename Dummy = int >
determineVectorDataType(const vector<unsigned char> &)164    Type determineVectorDataType(const vector<unsigned char>& /* type_in */) { return DataElement::Type::DATA_UCHAR_VECTOR; }
165 
166     template< typename Dummy = int >
determineVectorDataType(const vector<int> &)167     Type determineVectorDataType(const vector<int>& /* type_in */) { return DataElement::Type::DATA_INT_VECTOR; }
168 
169     template< typename Dummy = int >
determineVectorDataType(const vector<unsigned int> &)170     Type determineVectorDataType(const vector<unsigned int>& /* type_in */) { return DataElement::Type::DATA_UINT_VECTOR; }
171 
172     template< typename Dummy = int >
determineVectorDataType(const vector<long> &)173     Type determineVectorDataType(const vector<long>& /* type_in */) { return DataElement::Type::DATA_LONG_VECTOR; }
174 
175     template< typename Dummy = int >
determineVectorDataType(const vector<unsigned long> &)176     Type determineVectorDataType(const vector<unsigned long>& /* type_in */) { return DataElement::Type::DATA_ULONG_VECTOR; }
177 
178     template< typename Dummy = int >
determineVectorDataType(const vector<long long> &)179     Type determineVectorDataType(const vector<long long>& /* type_in */) { return DataElement::Type::DATA_LONGLONG_VECTOR; }
180 
181     template< typename Dummy = int >
determineVectorDataType(const vector<float> &)182     Type determineVectorDataType(const vector<float>& /* type_in */) { return DataElement::Type::DATA_FLOAT_VECTOR; }
183 
184     template< typename Dummy = int >
determineVectorDataType(const vector<double> &)185     Type determineVectorDataType(const vector<double>& /* type_in */) { return DataElement::Type::DATA_DOUBLE_VECTOR; }
186 
187 public:
188 
189     DataElement();
190     DataElement(DataElement &cloneFrom);
191     ~DataElement();
192 
193     Type getDataType();
194     char *getDataPointer();
195     size_t getDataSize();
196 
197     /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
198     //set overloads :
199 
200     // general templates : for scalars
201     template<typename T, typename Dummy = int >
set(const T & scalar_in)202     void set(const T& scalar_in) {
203 
204         data_type = determineScalarDataType<T>(scalar_in);
205 
206         int unit_size = sizeof(T);
207         //copy in a temporary variable (needed ?)
208         T local_copy = scalar_in;
209         auto* local_copy_ptr = reinterpret_cast<unsigned char*>(&local_copy);
210 
211         data_val.assign(local_copy_ptr, local_copy_ptr + unit_size);
212     }
213 
214     // general templates : for vector of scalars
215     template<typename T, typename Dummy = int >
set(const vector<T> & scalar_vector_in)216     void set(const vector<T>& scalar_vector_in) {
217 
218         data_type = determineVectorDataType<T>(scalar_vector_in);
219 
220         int unit_size = sizeof(T);
221 
222         data_val_vector.clear();
223 
224         DataElementBuffer single_buffer;
225 
226         for (auto single_element : scalar_vector_in) {
227 
228             //copy in a temporary variable (needed ?)
229             T local_copy = single_element;
230             auto* local_copy_ptr = reinterpret_cast<unsigned char*>(&local_copy);
231 
232             single_buffer.assign(local_copy_ptr, local_copy_ptr + unit_size);
233 
234             data_val_vector.push_back(single_buffer);
235         }
236     }
237 
238     //template specialization : for string
239     template< typename Dummy = int >
set(const string & str_in)240     void set(const string& str_in) {
241 
242         data_type = DataElement::Type::DATA_STRING;
243 
244         data_val.assign(str_in.begin(), str_in.end());
245     }
246 
247     //template specialization : for wstring
248     template< typename Dummy = int >
set(const wstring & wstr_in)249     void set(const wstring& wstr_in) {
250 
251         data_type = DataElement::Type::DATA_WSTRING;
252 
253         //wchar_t is tricky, the terminating zero is actually a (wchar_t)0 !
254         //wchar_t is typically 16 bits on windows, and 32 bits on Unix, so use sizeof(wchar_t) everywhere.
255         size_t maxLenBytes = (wstr_in.length() + 1) * sizeof(wchar_t);
256 
257         //be paranoid, zero the buffer
258         char *tmp_str = (char *)::calloc(maxLenBytes, sizeof(char));
259 
260         //if something awful happens, the last sizeof(wchar_t) is at least zero...
261         ::wcstombs(tmp_str, wstr_in.c_str(), maxLenBytes - sizeof(wchar_t));
262 
263         data_val.assign(tmp_str, tmp_str + maxLenBytes - sizeof(wchar_t));
264 
265         ::free(tmp_str);
266     }
267 
268     //template specialization : for vector<string>
269     template< typename Dummy = int >
set(const vector<string> & vector_str_in)270     void set(const vector<string>& vector_str_in) {
271 
272         data_type = DataElement::Type::DATA_STR_VECTOR;
273 
274         data_val_vector.clear();
275 
276         DataElementBuffer single_buffer;
277 
278         for (auto single_element : vector_str_in) {
279 
280             single_buffer.assign(single_element.begin(), single_element.end());
281 
282             data_val_vector.push_back(single_buffer);
283         }
284     }
285 
286 
287     ///specific versions
288     void set(const std::set<string> &strset_in);
289     void set(const char *data_in, long size_in); /* voids, file chunks anyone? */
290     void set(const char *data_in);	/* strings, stops at NULL, returns as string */
291 
292     /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
293     /* get overloads */
294 
295     template<typename T, typename Dummy = int >
get(T & scalar_out)296     void get(T& scalar_out) {
297 
298         if (getDataSize() == 0) {
299             throw DataException("Cannot get() the scalar, DataElement is empty !");
300         }
301 
302         DataElement::Type storageType = getDataType();
303 
304         //TODO: smarter way with templates ?
305         if (storageType == DataElement::Type::DATA_CHAR) {
306             char* storage_ptr = reinterpret_cast<char*>(&data_val[0]);
307             //constructor-like
308             scalar_out = T(*storage_ptr);
309 
310         } else if (storageType == DataElement::Type::DATA_UCHAR) {
311             auto* storage_ptr = reinterpret_cast<unsigned char*>(&data_val[0]);
312             //constructor-like
313             scalar_out = T(*storage_ptr);
314         } else if (storageType == DataElement::Type::DATA_INT) {
315             int* storage_ptr = reinterpret_cast<int*>(&data_val[0]);
316             //constructor-like
317             scalar_out = T(*storage_ptr);
318         } else if (storageType == DataElement::Type::DATA_UINT) {
319             auto* storage_ptr = reinterpret_cast<unsigned int*>(&data_val[0]);
320             //constructor-like
321             scalar_out = T(*storage_ptr);
322         } else if (storageType == DataElement::Type::DATA_LONG) {
323             long* storage_ptr = reinterpret_cast<long*>(&data_val[0]);
324             //constructor-like
325             scalar_out = T(*storage_ptr);
326         } else if (storageType == DataElement::Type::DATA_ULONG) {
327             auto* storage_ptr = reinterpret_cast<unsigned long*>(&data_val[0]);
328             //constructor-like
329             scalar_out = T(*storage_ptr);
330         } else if (storageType == DataElement::Type::DATA_LONGLONG) {
331             auto* storage_ptr = reinterpret_cast<long long*>(&data_val[0]);
332             //constructor-like
333             scalar_out = T(*storage_ptr);
334         } else if (storageType == DataElement::Type::DATA_FLOAT) {
335             auto* storage_ptr = reinterpret_cast<float*>(&data_val[0]);
336             //constructor-like
337             scalar_out = T(*storage_ptr);
338         } else if (storageType == DataElement::Type::DATA_DOUBLE) {
339             auto* storage_ptr = reinterpret_cast<double*>(&data_val[0]);
340             //constructor-like
341             scalar_out = T(*storage_ptr);
342         }
343     }
344 
345     // general templates : for vector of scalars
346     template<typename T, typename Dummy = int >
get(vector<T> & scalar_vector_out)347     void get(vector<T>& scalar_vector_out) {
348 
349         scalar_vector_out.clear();
350 
351         DataElementBuffer single_buffer;
352 
353         Type storageType = getDataType();
354 
355         for (auto single_storage_element : data_val_vector) {
356 
357             if (single_storage_element.empty()) {
358                 throw DataException("Cannot get(vector<scalar>) on single element because it is empty!");
359             }
360 
361             T scalar_out;
362 
363             //TODO: smarter way with templates ?
364             if (storageType == DataElement::Type::DATA_CHAR_VECTOR) {
365                 char* storage_ptr = reinterpret_cast<char*>(&single_storage_element[0]);
366                 //constructor-like
367                 scalar_out = T(*storage_ptr);
368 
369             } else if (storageType == DataElement::Type::DATA_UCHAR_VECTOR) {
370                 auto* storage_ptr = reinterpret_cast<unsigned char*>(&single_storage_element[0]);
371                 //constructor-like
372                 scalar_out = T(*storage_ptr);
373             } else if (storageType == DataElement::Type::DATA_INT_VECTOR) {
374                 int* storage_ptr = reinterpret_cast<int*>(&single_storage_element[0]);
375                 //constructor-like
376                 scalar_out = T(*storage_ptr);
377             } else if (storageType == DataElement::Type::DATA_UINT_VECTOR) {
378                 auto* storage_ptr = reinterpret_cast<unsigned int*>(&single_storage_element[0]);
379                 //constructor-like
380                 scalar_out = T(*storage_ptr);
381             } else if (storageType == DataElement::Type::DATA_LONG_VECTOR) {
382                 long* storage_ptr = reinterpret_cast<long*>(&single_storage_element[0]);
383                 //constructor-like
384                 scalar_out = T(*storage_ptr);
385             } else if (storageType == DataElement::Type::DATA_ULONG_VECTOR) {
386                 auto* storage_ptr = reinterpret_cast<unsigned long*>(&single_storage_element[0]);
387                 //constructor-like
388                 scalar_out = T(*storage_ptr);
389             } else if (storageType == DataElement::Type::DATA_LONGLONG_VECTOR) {
390                 auto* storage_ptr = reinterpret_cast<long long*>(&single_storage_element[0]);
391                 //constructor-like
392                 scalar_out = T(*storage_ptr);
393             } else if (storageType == DataElement::Type::DATA_FLOAT_VECTOR) {
394                 auto* storage_ptr = reinterpret_cast<float*>(&single_storage_element[0]);
395                 //constructor-like
396                 scalar_out = T(*storage_ptr);
397             } else if (storageType == DataElement::Type::DATA_DOUBLE_VECTOR) {
398                 auto* storage_ptr = reinterpret_cast<double*>(&single_storage_element[0]);
399                 //constructor-like
400                 scalar_out = T(*storage_ptr);
401             }
402 
403             scalar_vector_out.push_back(scalar_out);
404         } //end for.
405     }
406 
407     //template specialization : for string or void* returned as string
408     template< typename Dummy = int >
get(string & str_out)409     void get(string& str_out) {
410 
411         //reset
412         str_out.clear();
413 
414         if (data_type == DataElement::Type::DATA_NULL) {
415             //it means TinyXML has parsed an empty tag,
416             //so return an empty string.
417             return;
418         }
419 
420         if (data_type != DataElement::Type::DATA_STRING && data_type != DataElement::Type::DATA_VOID) {
421             throw(DataTypeMismatchException("Type mismatch, neither a STRING nor a VOID*"));
422         }
423 
424         for (auto single_char : data_val) {
425             str_out.push_back((char)single_char);
426         }
427     }
428 
429     //template specialization : for wstring
430     template< typename Dummy = int >
get(wstring & wstr_out)431     void get(wstring& wstr_out) {
432 
433         //reset
434         wstr_out.clear();
435 
436         if (data_type == DataElement::Type::DATA_NULL) {
437             //it means TinyXML has parsed an empty tag,
438             //so return an empty string.
439             return;
440         }
441 
442         if (data_type != DataElement::Type::DATA_WSTRING) {
443             throw(DataTypeMismatchException("Type mismatch, not a WSTRING"));
444         }
445 
446         if (getDataSize() >= sizeof(wchar_t)) {
447 
448             //data_val is an array of bytes holding wchar_t characters, plus a terminating (wchar_t)0
449            //wchar_t is typically 16 bits on windows, and 32 bits on Unix, so use sizeof(wchar_t) everywhere.
450             size_t maxNbWchars = getDataSize() / sizeof(wchar_t);
451 
452             //be paranoid, zero the buffer
453             auto *tmp_wstr = (wchar_t *)::calloc(maxNbWchars + 1, sizeof(wchar_t));
454 
455             //the last wchar_t is actually zero if anything goes wrong...
456             ::mbstowcs(tmp_wstr, (const char*)&data_val[0], maxNbWchars);
457 
458             wstr_out.assign(tmp_wstr);
459 
460             ::free(tmp_wstr);
461         }
462     }
463 
464     //template specialization : for vector<string>
465     template< typename Dummy = int >
get(vector<string> & vector_str_out)466     void get(vector<string>& vector_str_out) {
467 
468         if (data_type != DataElement::Type::DATA_STR_VECTOR) {
469             throw(DataTypeMismatchException("Type mismatch, not a STRING VECTOR"));
470         }
471 
472         vector_str_out.clear();
473 
474         string single_buffer;
475 
476         for (auto single_element : data_val_vector) {
477 
478             single_buffer.assign(single_element.begin(), single_element.end());
479 
480             vector_str_out.push_back(single_buffer);
481         }
482     }
483 
484     //special versions:
485     void get(DataElementBuffer& data_out); /* getting a void or string */
486     void get(std::set<string> &strset_out);
487 
488 
489     /* special get functions, saves creating unnecessary vars */
getChar()490     int getChar()  { char i_get; get(i_get); return i_get; };
getUChar()491     unsigned int getUChar()  { unsigned char i_get; get(i_get); return i_get; };
getInt()492     int getInt()  { int i_get; get(i_get); return i_get; };
getUInt()493     unsigned int getUInt()  { unsigned int i_get; get(i_get); return i_get; };
getLong()494     long getLong()  { long l_get; get(l_get); return l_get; };
getULong()495     unsigned long getULong() { unsigned long l_get; get(l_get); return l_get; };
getLongLong()496     long long getLongLong() { long long l_get; get(l_get); return l_get; };
getFloat()497     float getFloat() { float f_get; get(f_get); return f_get; };
getDouble()498     double getDouble() { double d_get; get(d_get); return d_get; };
499 
500     std::string toString();
501 };
502 
503 ///
504 class DataNode
505 {
506 private:
507     DataNode *parentNode;
508     vector<DataNode *> children;
509     map<string, vector<DataNode *>, string_less> childmap;
510     map<string, unsigned int, string_less> childmap_ptr;
511 
512     string node_name;
513     DataElement *data_elem;
514     unsigned int ptr;
515 
516 
517 public:
518     DataNode();
519     explicit DataNode(const char *name_in);
520     DataNode(const char *name_in, DataElement &cloneFrom);
521     DataNode(const char *name_in, DataNode &cloneFrom);
522 
523     ~DataNode();
524 
525     void setName(const char *name_in);
getName()526     string &getName() { return node_name; }
527 
getParentNode()528     DataNode *getParentNode() { return parentNode; };
setParentNode(DataNode & parentNode_in)529     void setParentNode(DataNode &parentNode_in) { parentNode = &parentNode_in; };
530 
531     size_t numChildren();	/* Number of children */
532     size_t numChildren(const char *name_in); /* Number of children named 'name_in' */
533 
534     DataElement *element(); /* DataElement at this node */
535 
536     DataNode *newChild(const char *name_in);
537     DataNode *newChild(const char *name_in, DataNode *otherNode);
538     DataNode *newChildCloneFrom(const char *name_in, DataNode *cloneFrom);
539     DataNode *child(const char *name_in, int index = 0);
540     DataNode *child(int index);
541 
542 
543     bool hasAnother(const char *name_in);	/* useful for while() loops in conjunction with getNext() */
544     bool hasAnother();
545     DataNode *getNext(const char *name_in); /* get next of specified name */
546     DataNode *getNext();	/* get next child */
547     void rewind(const char *name_in);	/* rewind specific */
548     void rewind();	/* rewind generic */
549     void rewindAll();
550 
551     void findAll(const char *name_in, vector<DataNode *> &node_list_out);
552 
string()553     explicit operator string () { string s; element()->get(s); return s; }
554     explicit operator const char * () { if (element()->getDataType() == DataElement::Type::DATA_STRING) { return element()->getDataPointer(); } else { return nullptr; } }
555     explicit operator char () { char v=0; element()->get(v); return v; }
556     explicit operator unsigned char () { unsigned char v=0; element()->get(v); return v; }
557     explicit operator int () { int v=0; element()->get(v); return v; }
558     explicit operator unsigned int () { unsigned int v=0; element()->get(v); return v; }
559     explicit operator long () { long v=0; element()->get(v); return v; }
560     explicit operator unsigned long () { unsigned long v=0; element()->get(v); return v; }
561     explicit operator long long () { long long v=0; element()->get(v); return v; }
562     explicit operator float () { float v=0; element()->get(v); return v; }
563     explicit operator double () { double v=0; element()->get(v); return v; }
564 
565     explicit operator vector<char> () { vector<char> v; element()->get(v);  return v; }
566     explicit operator vector<unsigned char> () { vector<unsigned char> v; element()->get(v);  return v; }
567     explicit operator vector<int> () { vector<int> v; element()->get(v);  return v; }
568     explicit operator vector<unsigned int> () { vector<unsigned int> v; element()->get(v);  return v; }
569     explicit operator vector<long> () { vector<long> v; element()->get(v);  return v; }
570     explicit operator vector<unsigned long> () { vector<unsigned long> v; element()->get(v);  return v; }
571     explicit operator vector<float> () { vector<float> v; element()->get(v);  return v; }
572     explicit operator vector<double> () { vector<double> v; element()->get(v);  return v; }
573 
574     const string &operator= (const string &s) { element()->set(s); return s; }
575     const wstring &operator= (const wstring &s) { element()->set(s); return s; }
576 
577     char operator= (char i) { element()->set(i); return i; }
578     unsigned char operator= (unsigned char i) { element()->set(i); return i; }
579     int operator= (int i) { element()->set(i); return i; }
580     unsigned int operator= (unsigned int i) { element()->set(i); return i; }
581     long operator= (long i) { element()->set(i); return i; }
582     unsigned long operator= (unsigned long i) { element()->set(i); return i; }
583     long long operator= (long long i) { element()->set(i); return i; }
584     float operator= (float i) { element()->set(i); return i; }
585     double operator= (double i) { element()->set(i); return i; }
586 
587     vector<char> &operator= (vector<char> &v) { element()->set(v); return v; }
588     vector<unsigned char> &operator= (vector<unsigned char> &v) { element()->set(v); return v; }
589     vector<int> &operator= (vector<int> &v) { element()->set(v); return v; }
590     vector<unsigned int> &operator= (vector<unsigned int> &v) { element()->set(v); return v; }
591     vector<long> &operator= (vector<long> &v) { element()->set(v); return v; }
592     vector<unsigned long> &operator= (vector<unsigned long> &v) { element()->set(v); return v; }
593     vector<float> &operator= (vector<float> &v) { element()->set(v); return v; }
594     vector<double> &operator= (vector<double> &v) { element()->set(v); return v; }
595 
596     DataNode *operator[] (const char *name_in) { return getNext(name_in); }
597     DataNode *operator[] (int idx) { return child(idx); }
598 
operator()599     bool operator() (const char *name_in) { return hasAnother(name_in); }
operator()600     bool operator() () { return hasAnother(); }
601 
602     DataNode *operator ^(const char *name_in) { return newChild(name_in); }
603 };
604 
605 
606 typedef vector<DataNode *> DataNodeList;
607 
608 enum DT_FloatingPointPolicy {
609     USE_FLOAT,
610     USE_DOUBLE
611 };
612 
613 class DataTree
614 {
615 private:
616     DataNode dn_root;
617 
618     string wsEncode(const wstring& wstr);
619     wstring wsDecode(const string& str);
620 
621 public:
622     explicit DataTree(const char *name_in);
623     DataTree();
624     ~DataTree();
625 
626     DataNode *rootNode();
627 
628     void nodeToXML(DataNode *elem, TiXmlElement *elxml);
629     void setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node=true, DT_FloatingPointPolicy fpp=USE_FLOAT);
630     void decodeXMLText(DataNode *elem, const char *in_text, DT_FloatingPointPolicy fpp);
631 
632     void printXML();	/* print datatree as XML */
633 
634     bool LoadFromFileXML(const std::string& filename, DT_FloatingPointPolicy fpp=USE_FLOAT);
635     bool SaveToFileXML(const std::string& filename);
636 
637 };
638