From 93e88a9208956d6b808c47e8505045844fbca6e0 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 7 Jan 2015 20:23:15 -0500 Subject: [PATCH 01/11] Import TinyXML and DataTree, OSX related UI tweaks --- CMakeLists.txt | 10 + external/tinyxml/tinystr.cpp | 116 ++ external/tinyxml/tinystr.h | 319 +++++ external/tinyxml/tinyxml.cpp | 1888 ++++++++++++++++++++++++++++ external/tinyxml/tinyxml.h | 1802 ++++++++++++++++++++++++++ external/tinyxml/tinyxmlerror.cpp | 53 + external/tinyxml/tinyxmlparser.cpp | 1638 ++++++++++++++++++++++++ external/tinyxml/xmltest.cpp | 1294 +++++++++++++++++++ src/AppFrame.cpp | 1 + src/demod/DemodDefs.h | 1 + src/demod/DemodulatorThread.cpp | 5 + src/demod/DemodulatorThread.h | 1 + src/util/DataTree.cpp | 1780 ++++++++++++++++++++++++++ src/util/DataTree.h | 335 +++++ src/visual/TuningCanvas.cpp | 64 +- src/visual/TuningCanvas.h | 1 + src/visual/TuningContext.cpp | 32 +- src/visual/TuningContext.h | 2 +- src/visual/WaterfallCanvas.cpp | 7 + 19 files changed, 9305 insertions(+), 44 deletions(-) create mode 100644 external/tinyxml/tinystr.cpp create mode 100644 external/tinyxml/tinystr.h create mode 100644 external/tinyxml/tinyxml.cpp create mode 100644 external/tinyxml/tinyxml.h create mode 100644 external/tinyxml/tinyxmlerror.cpp create mode 100644 external/tinyxml/tinyxmlparser.cpp create mode 100644 external/tinyxml/xmltest.cpp create mode 100755 src/util/DataTree.cpp create mode 100755 src/util/DataTree.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a181389..1ab58ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,7 @@ SET (cubicsdr_sources src/util/Timer.cpp src/util/MouseTracker.cpp src/util/GLFont.cpp + src/util/DataTree.cpp src/visual/PrimaryGLContext.cpp src/visual/InteractiveCanvas.cpp src/visual/MeterCanvas.cpp @@ -151,6 +152,10 @@ SET (cubicsdr_sources src/visual/WaterfallContext.cpp external/rtaudio/RtAudio.cpp external/lodepng/lodepng.cpp + external/tinyxml/tinyxml.cpp + external/tinyxml/tinystr.cpp + external/tinyxml/tinyxmlparser.cpp + external/tinyxml/tinyxmlerror.cpp ) SET (cubicsdr_headers @@ -171,6 +176,7 @@ SET (cubicsdr_headers src/util/ThreadQueue.h src/util/MouseTracker.h src/util/GLFont.h + src/util/DataTree.h src/visual/PrimaryGLContext.h src/visual/InteractiveCanvas.h src/visual/MeterCanvas.h @@ -187,6 +193,8 @@ SET (cubicsdr_headers src/visual/WaterfallContext.h external/rtaudio/RtAudio.h external/lodepng/lodepng.h + external/tinyxml/tinyxml.h + external/tinyxml/tinystr.h ) include_directories ( @@ -198,6 +206,8 @@ include_directories ( ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/external/rtaudio ${PROJECT_SOURCE_DIR}/external/lodepng + ${PROJECT_SOURCE_DIR}/external/fastlz + ${PROJECT_SOURCE_DIR}/external/tinyxml ) ADD_DEFINITIONS( diff --git a/external/tinyxml/tinystr.cpp b/external/tinyxml/tinystr.cpp new file mode 100644 index 0000000..8bcb603 --- /dev/null +++ b/external/tinyxml/tinystr.cpp @@ -0,0 +1,116 @@ +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* + * THIS FILE WAS ALTERED BY Tyge L?vset, 7. April 2005. + */ + + +#ifndef TIXML_USE_STL + +#include "tinystr.h" + +// Error value for find primitive +const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); + + +// Null rep. +TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; + + +void TiXmlString::reserve (size_type cap) +{ + if (cap > capacity()) + { + TiXmlString tmp; + tmp.init(length(), cap); + memcpy(tmp.start(), data(), length()); + swap(tmp); + } +} + + +TiXmlString& TiXmlString::assign(const char* str, size_type len) +{ + size_type cap = capacity(); + if (len > cap || cap > 3*(len + 8)) + { + TiXmlString tmp; + tmp.init(len); + memcpy(tmp.start(), str, len); + swap(tmp); + } + else + { + memmove(start(), str, len); + set_size(len); + } + return *this; +} + + +TiXmlString& TiXmlString::append(const char* str, size_type len) +{ + size_type newsize = length() + len; + if (newsize > capacity()) + { + reserve (newsize + capacity()); + } + memmove(finish(), str, len); + set_size(newsize); + return *this; +} + + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) +{ + TiXmlString tmp; + tmp.reserve(a.length() + b.length()); + tmp += a; + tmp += b; + return tmp; +} + +TiXmlString operator + (const TiXmlString & a, const char* b) +{ + TiXmlString tmp; + TiXmlString::size_type b_len = static_cast( strlen(b) ); + tmp.reserve(a.length() + b_len); + tmp += a; + tmp.append(b, b_len); + return tmp; +} + +TiXmlString operator + (const char* a, const TiXmlString & b) +{ + TiXmlString tmp; + TiXmlString::size_type a_len = static_cast( strlen(a) ); + tmp.reserve(a_len + b.length()); + tmp.append(a, a_len); + tmp += b; + return tmp; +} + + +#endif // TIXML_USE_STL diff --git a/external/tinyxml/tinystr.h b/external/tinyxml/tinystr.h new file mode 100644 index 0000000..3c2aa9d --- /dev/null +++ b/external/tinyxml/tinystr.h @@ -0,0 +1,319 @@ +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* + * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. + * + * - completely rewritten. compact, clean, and fast implementation. + * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) + * - fixed reserve() to work as per specification. + * - fixed buggy compares operator==(), operator<(), and operator>() + * - fixed operator+=() to take a const ref argument, following spec. + * - added "copy" constructor with length, and most compare operators. + * - added swap(), clear(), size(), capacity(), operator+(). + */ + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#include +#include + +/* The support for explicit isn't that universal, and it isn't really + required - it is used to check that the TiXmlString class isn't incorrectly + used. Be nice to old compilers and macro it here: +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + #define TIXML_EXPLICIT explicit +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + #define TIXML_EXPLICIT explicit +#else + #define TIXML_EXPLICIT +#endif + + +/* + TiXmlString is an emulation of a subset of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ + public : + // The size type used + typedef size_t size_type; + + // Error value for find primitive + static const size_type npos; // = -1; + + + // TiXmlString empty constructor + TiXmlString () : rep_(&nullrep_) + { + } + + // TiXmlString copy constructor + TiXmlString ( const TiXmlString & copy) : rep_(0) + { + init(copy.length()); + memcpy(start(), copy.data(), length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) + { + init( static_cast( strlen(copy) )); + memcpy(start(), copy, length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) + { + init(len); + memcpy(start(), str, len); + } + + // TiXmlString destructor + ~TiXmlString () + { + quit(); + } + + // = operator + TiXmlString& operator = (const char * copy) + { + return assign( copy, (size_type)strlen(copy)); + } + + // = operator + TiXmlString& operator = (const TiXmlString & copy) + { + return assign(copy.start(), copy.length()); + } + + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + return append(suffix, static_cast( strlen(suffix) )); + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + return append(&single, 1); + } + + // += operator. Maps to append + TiXmlString& operator += (const TiXmlString & suffix) + { + return append(suffix.data(), suffix.length()); + } + + + // Convert a TiXmlString into a null-terminated char * + const char * c_str () const { return rep_->str; } + + // Convert a TiXmlString into a char * (need not be null terminated). + const char * data () const { return rep_->str; } + + // Return the length of a TiXmlString + size_type length () const { return rep_->size; } + + // Alias for length() + size_type size () const { return rep_->size; } + + // Checks if a TiXmlString is empty + bool empty () const { return rep_->size == 0; } + + // Return capacity of string + size_type capacity () const { return rep_->capacity; } + + + // single char extraction + const char& at (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // [] operator + char& operator [] (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // find a char in a string. Return TiXmlString::npos if not found + size_type find (char lookup) const + { + return find(lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::npos if not found + size_type find (char tofind, size_type offset) const + { + if (offset >= length()) return npos; + + for (const char* p = c_str() + offset; *p != '\0'; ++p) + { + if (*p == tofind) return static_cast< size_type >( p - c_str() ); + } + return npos; + } + + void clear () + { + //Lee: + //The original was just too strange, though correct: + // TiXmlString().swap(*this); + //Instead use the quit & re-init: + quit(); + init(0,0); + } + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function DOES NOT clear the content of the TiXmlString if any exists. + */ + void reserve (size_type cap); + + TiXmlString& assign (const char* str, size_type len); + + TiXmlString& append (const char* str, size_type len); + + void swap (TiXmlString& other) + { + Rep* r = rep_; + rep_ = other.rep_; + other.rep_ = r; + } + + private: + + void init(size_type sz) { init(sz, sz); } + void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } + char* start() const { return rep_->str; } + char* finish() const { return rep_->str + rep_->size; } + + struct Rep + { + size_type size, capacity; + char str[1]; + }; + + void init(size_type sz, size_type cap) + { + if (cap) + { + // Lee: the original form: + // rep_ = static_cast(operator new(sizeof(Rep) + cap)); + // doesn't work in some cases of new being overloaded. Switching + // to the normal allocation, although use an 'int' for systems + // that are overly picky about structure alignment. + const size_type bytesNeeded = sizeof(Rep) + cap; + const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); + rep_ = reinterpret_cast( new int[ intsNeeded ] ); + + rep_->str[ rep_->size = sz ] = '\0'; + rep_->capacity = cap; + } + else + { + rep_ = &nullrep_; + } + } + + void quit() + { + if (rep_ != &nullrep_) + { + // The rep_ is really an array of ints. (see the allocator, above). + // Cast it back before delete, so the compiler won't incorrectly call destructors. + delete [] ( reinterpret_cast( rep_ ) ); + } + } + + Rep * rep_; + static Rep nullrep_; + +} ; + + +inline bool operator == (const TiXmlString & a, const TiXmlString & b) +{ + return ( a.length() == b.length() ) // optimization on some platforms + && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare +} +inline bool operator < (const TiXmlString & a, const TiXmlString & b) +{ + return strcmp(a.c_str(), b.c_str()) < 0; +} + +inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } +inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } +inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } +inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } + +inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } +inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } +inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } +inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); +TiXmlString operator + (const TiXmlString & a, const char* b); +TiXmlString operator + (const char* a, const TiXmlString & b); + + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developped. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const TiXmlString & in) + { + *this += in; + return *this; + } + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const char * in) + { + *this += in; + return *this; + } + +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL diff --git a/external/tinyxml/tinyxml.cpp b/external/tinyxml/tinyxml.cpp new file mode 100644 index 0000000..5de21f6 --- /dev/null +++ b/external/tinyxml/tinyxml.cpp @@ -0,0 +1,1888 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include + +#ifdef TIXML_USE_STL +#include +#include +#endif + +#include "tinyxml.h" + + +bool TiXmlBase::condenseWhiteSpace = true; + +// Microsoft compiler security +FILE* TiXmlFOpen( const char* filename, const char* mode ) +{ + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filename, mode ); + if ( !err && fp ) + return fp; + return 0; + #else + return fopen( filename, mode ); + #endif +} + +void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) +{ + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); + #else + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + #endif + + //*ME: warning C4267: convert 'size_t' to 'int' + //*ME: Int-Cast to make compiler happy ... + outString->append( buf, (int)strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } +} + + +TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() +{ + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; +} + + +TiXmlNode::~TiXmlNode() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } +} + + +void TiXmlNode::CopyTo( TiXmlNode* target ) const +{ + target->SetValue (value.c_str() ); + target->userData = userData; +} + + +void TiXmlNode::Clear() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } + + firstChild = 0; + lastChild = 0; +} + + +TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) +{ + assert( node->parent == 0 || node->parent == this ); + assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); + + if ( node->Type() == TiXmlNode::DOCUMENT ) + { + delete node; + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + node->parent = this; + + node->prev = lastChild; + node->next = 0; + + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. + + lastChild = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) +{ + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + + return LinkEndChild( node ); +} + + +TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) +{ + if ( !beforeThis || beforeThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) +{ + if ( !afterThis || afterThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; +} + + +TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) +{ + if ( replaceThis->parent != this ) + return 0; + + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; + + node->next = replaceThis->next; + node->prev = replaceThis->prev; + + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; + + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; + + delete replaceThis; + node->parent = this; + return node; +} + + +bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) +{ + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } + + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; + + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; + + delete removeThis; + return true; +} + +const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } +} + + +const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +void TiXmlElement::RemoveAttribute( const char * name ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING str( name ); + TiXmlAttribute* node = attributeSet.Find( str ); + #else + TiXmlAttribute* node = attributeSet.Find( name ); + #endif + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } +} + +const TiXmlElement* TiXmlNode::FirstChildElement() const +{ + const TiXmlNode* node; + + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement() const +{ + const TiXmlNode* node; + + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlDocument* TiXmlNode::GetDocument() const +{ + const TiXmlNode* node; + + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; +} + + +TiXmlElement::TiXmlElement (const char * _value) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} + + +#ifdef TIXML_USE_STL +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} +#endif + + +TiXmlElement::TiXmlElement( const TiXmlElement& copy) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + copy.CopyTo( this ); +} + + +void TiXmlElement::operator=( const TiXmlElement& base ) +{ + ClearThis(); + base.CopyTo( this ); +} + + +TiXmlElement::~TiXmlElement() +{ + ClearThis(); +} + + +void TiXmlElement::ClearThis() +{ + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } +} + + +const char* TiXmlElement::Attribute( const char* name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return node->Value(); + return 0; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return &node->ValueStr(); + return 0; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, int* i ) const +{ + const char* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s ); + } + else { + *i = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const +{ + const std::string* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s->c_str() ); + } + else { + *i = 0; + } + } + return s; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, double* d ) const +{ + const char* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s ); + } + else { + *d = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const +{ + const std::string* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s->c_str() ); + } + else { + *d = 0; + } + } + return s; +} +#endif + + +int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} +#endif + + +int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} +#endif + + +void TiXmlElement::SetAttribute( const char * name, int val ) +{ + char buf[64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); + #else + sprintf( buf, "%d", val ); + #endif + SetAttribute( name, buf ); +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, int val ) +{ + std::ostringstream oss; + oss << val; + SetAttribute( name, oss.str() ); +} +#endif + + +void TiXmlElement::SetDoubleAttribute( const char * name, double val ) +{ + char buf[256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); + #else + sprintf( buf, "%f", val ); + #endif + SetAttribute( name, buf ); +} + + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING _name( cname ); + TIXML_STRING _value( cvalue ); + #else + const char* _name = cname; + const char* _value = cvalue; + #endif + + TiXmlAttribute* node = attributeSet.Find( _name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} +#endif + + +void TiXmlElement::Print( FILE* cfile, int depth ) const +{ + int i; + assert( cfile ); + for ( i=0; iNext() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a node + // 2) An element with only a text child is printed as text + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i", value.c_str() ); + } +} + + +void TiXmlElement::CopyTo( TiXmlElement* target ) const +{ + // superclass: + TiXmlNode::CopyTo( target ); + + // Element class: + // Clone the attributes, then clone the children. + const TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + +bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this, attributeSet.First() ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +TiXmlNode* TiXmlElement::Clone() const +{ + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +const char* TiXmlElement::GetText() const +{ + const TiXmlNode* child = this->FirstChild(); + if ( child ) { + const TiXmlText* childText = child->ToText(); + if ( childText ) { + return childText->Value(); + } + } + return 0; +} + + +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + ClearError(); +} + +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} + + +#ifdef TIXML_USE_STL +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} +#endif + + +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDocument::operator=( const TiXmlDocument& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) +{ + // See STL_STRING_BUG below. + //StringToBuffer buf( value ); + + return LoadFile( Value(), encoding ); +} + + +bool TiXmlDocument::SaveFile() const +{ + // See STL_STRING_BUG below. +// StringToBuffer buf( value ); +// +// if ( buf.buffer && SaveFile( buf.buffer ) ) +// return true; +// +// return false; + return SaveFile( Value() ); +} + +bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) +{ + // There was a really terrifying little bug here. The code: + // value = filename + // in the STL case, cause the assignment method of the std::string to + // be called. What is strange, is that the std::string had the same + // address as it's c_str() method, and so bad things happen. Looks + // like a bug in the Microsoft STL implementation. + // Add an extra string to avoid the crash. + TIXML_STRING filename( _filename ); + value = filename; + + // reading in binary mode so that tinyxml can normalize the EOL + FILE* file = TiXmlFOpen( value.c_str (), "rb" ); + + if ( file ) + { + bool result = LoadFile( file, encoding ); + fclose( file ); + return result; + } + else + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } +} + +bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) +{ + if ( !file ) + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length <= 0 ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // If we have a file, assume it is all one big XML file, and read it in. + // The document parser may decide the document ends sooner than the entire file, however. + TIXML_STRING data; + data.reserve( length ); + + // Subtle bug here. TinyXml did use fgets. But from the XML spec: + // 2.11 End-of-Line Handling + // + // + // ...the XML processor MUST behave as if it normalized all line breaks in external + // parsed entities (including the document entity) on input, before parsing, by translating + // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to + // a single #xA character. + // + // + // It is not clear fgets does that, and certainly isn't clear it works cross platform. + // Generally, you expect fgets to translate from the convention of the OS to the c/unix + // convention, and not work generally. + + /* + while( fgets( buf, sizeof(buf), file ) ) + { + data += buf; + } + */ + + char* buf = new char[ length+1 ]; + buf[0] = 0; + + if ( fread( buf, length, 1, file ) != 1 ) { + delete [] buf; + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + const char* lastPos = buf; + const char* p = buf; + + buf[length] = 0; + while( *p ) { + assert( p < (buf+length) ); + if ( *p == 0xa ) { + // Newline character. No special rules for this. Append all the characters + // since the last string, and include the newline. + data.append( lastPos, (p-lastPos+1) ); // append, include the newline + ++p; // move past the newline + lastPos = p; // and point to the new buffer (may be 0) + assert( p <= (buf+length) ); + } + else if ( *p == 0xd ) { + // Carriage return. Append what we have so far, then + // handle moving forward in the buffer. + if ( (p-lastPos) > 0 ) { + data.append( lastPos, p-lastPos ); // do not add the CR + } + data += (char)0xa; // a proper newline + + if ( *(p+1) == 0xa ) { + // Carriage return - new line sequence + p += 2; + lastPos = p; + assert( p <= (buf+length) ); + } + else { + // it was followed by something else...that is presumably characters again. + ++p; + lastPos = p; + assert( p <= (buf+length) ); + } + } + else { + ++p; + } + } + // Handle any left over characters. + if ( p-lastPos ) { + data.append( lastPos, p-lastPos ); + } + delete [] buf; + buf = 0; + + Parse( data.c_str(), 0, encoding ); + + if ( Error() ) + return false; + else + return true; +} + + +bool TiXmlDocument::SaveFile( const char * filename ) const +{ + // The old c stuff lives on... + FILE* fp = TiXmlFOpen( filename, "w" ); + if ( fp ) + { + bool result = SaveFile( fp ); + fclose( fp ); + return result; + } + return false; +} + + +bool TiXmlDocument::SaveFile( FILE* fp ) const +{ + if ( useMicrosoftBOM ) + { + const unsigned char TIXML_UTF_LEAD_0 = 0xefU; + const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; + const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + + fputc( TIXML_UTF_LEAD_0, fp ); + fputc( TIXML_UTF_LEAD_1, fp ); + fputc( TIXML_UTF_LEAD_2, fp ); + } + Print( fp, 0 ); + return (ferror(fp) == 0); +} + + +void TiXmlDocument::CopyTo( TiXmlDocument* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->error = error; + target->errorId = errorId; + target->errorDesc = errorDesc; + target->tabsize = tabsize; + target->errorLocation = errorLocation; + target->useMicrosoftBOM = useMicrosoftBOM; + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlDocument::Clone() const +{ + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlDocument::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } +} + + +bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +const TiXmlAttribute* TiXmlAttribute::Next() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} + +/* +TiXmlAttribute* TiXmlAttribute::Next() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} +*/ + +const TiXmlAttribute* TiXmlAttribute::Previous() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} + +/* +TiXmlAttribute* TiXmlAttribute::Previous() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} +*/ + +void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + TIXML_STRING n, v; + + EncodeString( name, &n ); + EncodeString( value, &v ); + + if (value.find ('\"') == TIXML_STRING::npos) { + if ( cfile ) { + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; + } + } + else { + if ( cfile ) { + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; + } + } +} + + +int TiXmlAttribute::QueryIntValue( int* ival ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +int TiXmlAttribute::QueryDoubleValue( double* dval ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +void TiXmlAttribute::SetIntValue( int _value ) +{ + char buf [64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); + #else + sprintf (buf, "%d", _value); + #endif + SetValue (buf); +} + +void TiXmlAttribute::SetDoubleValue( double _value ) +{ + char buf [256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); + #else + sprintf (buf, "%lf", _value); + #endif + SetValue (buf); +} + +int TiXmlAttribute::IntValue() const +{ + return atoi (value.c_str ()); +} + +double TiXmlAttribute::DoubleValue() const +{ + return atof (value.c_str ()); +} + + +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlComment::operator=( const TiXmlComment& base ) +{ + Clear(); + base.CopyTo( this ); +} + + +void TiXmlComment::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlComment::CopyTo( TiXmlComment* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlComment::Clone() const +{ + TiXmlComment* clone = new TiXmlComment(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlText::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + if ( cdata ) + { + int i; + fprintf( cfile, "\n" ); + for ( i=0; i\n", value.c_str() ); // unformatted output + } + else + { + TIXML_STRING buffer; + EncodeString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); + } +} + + +void TiXmlText::CopyTo( TiXmlText* target ) const +{ + TiXmlNode::CopyTo( target ); + target->cdata = cdata; +} + + +bool TiXmlText::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlText::Clone() const +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDeclaration::TiXmlDeclaration( const char * _version, + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} + + +#ifdef TIXML_USE_STL +TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} +#endif + + +TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + if ( cfile ) fprintf( cfile, "" ); + if ( str ) (*str) += "?>"; +} + + +void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->version = version; + target->encoding = encoding; + target->standalone = standalone; +} + + +bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlDeclaration::Clone() const +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlUnknown::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlUnknown::Clone() const +{ + TiXmlUnknown* clone = new TiXmlUnknown(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlAttributeSet::TiXmlAttributeSet() +{ + sentinel.next = &sentinel; + sentinel.prev = &sentinel; +} + + +TiXmlAttributeSet::~TiXmlAttributeSet() +{ + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); +} + + +void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) +{ + #ifdef TIXML_USE_STL + assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. + #else + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + #endif + + addMe->next = &sentinel; + addMe->prev = sentinel.prev; + + sentinel.prev->next = addMe; + sentinel.prev = addMe; +} + +void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. +} + + +#ifdef TIXML_USE_STL +const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} +*/ +#endif + + +const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} +*/ + +#ifdef TIXML_USE_STL +std::istream& operator>> (std::istream & in, TiXmlNode & base) +{ + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); + + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; +} +#endif + + +#ifdef TIXML_USE_STL +std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out << printer.Str(); + + return out; +} + + +std::string& operator<< (std::string& out, const TiXmlNode& base ) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out.append( printer.Str() ); + + return out; +} +#endif + + +TiXmlHandle TiXmlHandle::FirstChild() const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement() const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && iNextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && iNextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && iNextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && iNextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) +{ + DoIndent(); + buffer += "<"; + buffer += element.Value(); + + for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) + { + buffer += " "; + attrib->Print( 0, 0, &buffer ); + } + + if ( !element.FirstChild() ) + { + buffer += " />"; + DoLineBreak(); + } + else + { + buffer += ">"; + if ( element.FirstChild()->ToText() + && element.LastChild() == element.FirstChild() + && element.FirstChild()->ToText()->CDATA() == false ) + { + simpleTextPrint = true; + // no DoLineBreak()! + } + else + { + DoLineBreak(); + } + } + ++depth; + return true; +} + + +bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) +{ + --depth; + if ( !element.FirstChild() ) + { + // nothing. + } + else + { + if ( simpleTextPrint ) + { + simpleTextPrint = false; + } + else + { + DoIndent(); + } + buffer += ""; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlText& text ) +{ + if ( text.CDATA() ) + { + DoIndent(); + buffer += ""; + DoLineBreak(); + } + else if ( simpleTextPrint ) + { + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + } + else + { + DoIndent(); + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) +{ + DoIndent(); + declaration.Print( 0, 0, &buffer ); + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlComment& comment ) +{ + DoIndent(); + buffer += ""; + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) +{ + DoIndent(); + buffer += "<"; + buffer += unknown.Value(); + buffer += ">"; + DoLineBreak(); + return true; +} + diff --git a/external/tinyxml/tinyxml.h b/external/tinyxml/tinyxml.h new file mode 100644 index 0000000..c6f40cc --- /dev/null +++ b/external/tinyxml/tinyxml.h @@ -0,0 +1,1802 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TINYXML_INCLUDED +#define TINYXML_INCLUDED + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#ifdef TIXML_USE_STL + #include + #include + #include + #define TIXML_STRING std::string +#else + #include "tinystr.h" + #define TIXML_STRING TiXmlString +#endif + +// Deprecated library function hell. Compilers want to use the +// new safe versions. This probably doesn't fully address the problem, +// but it gets closer. There are too many compilers for me to fully +// test. If you get compilation troubles, undefine TIXML_SAFE +#define TIXML_SAFE + +#ifdef TIXML_SAFE + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + // Microsoft visual studio, version 2005 and higher. + #define TIXML_SNPRINTF _snprintf_s + #define TIXML_SNSCANF _snscanf_s + #define TIXML_SSCANF sscanf_s + #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + //#pragma message( "Using _sn* functions." ) + #define TIXML_SNPRINTF _snprintf + #define TIXML_SNSCANF _snscanf + #define TIXML_SSCANF sscanf + #elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_SNSCANF snscanf + #define TIXML_SSCANF sscanf + #else + #define TIXML_SSCANF sscanf + #endif +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 5; +const int TIXML_PATCH_VERSION = 3; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() { Clear(); } + void Clear() { row = col = -1; } + + int row; // 0 based. + int col; // 0 based. +}; + + +/** + If you call the Accept() method, it requires being passed a TiXmlVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves + are simple called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its sibilings will be Visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. + + You should never change the document from a callback. + + @sa TiXmlNode::Accept() +*/ +class TiXmlVisitor +{ +public: + virtual ~TiXmlVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } + /// Visit a document. + virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } + + /// Visit an element. + virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } + /// Visit an element. + virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } + + /// Visit a declaration + virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } + /// Visit a text node + virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } + /// Visit a comment node + virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } + /// Visit an unknow node + virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } +}; + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream + or the string class (TiXmlString in non-STL mode, std::string + in STL mode.) Either or both cfile and str can be null. + + This is a formatted print, and will insert + tabs and newlines. + + (For an unformatted stream, use the << operator.) + */ + virtual void Print( FILE* cfile, int depth ) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + value is not thread safe. + */ + static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const { return location.row + 1; } + int Column() const { return location.col + 1; } ///< See Row() + + void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. + void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. + const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. + + // Table that returs, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse( const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; + + /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, + or they will be transformed into entities! + */ + static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); + + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_OUT_OF_MEMORY, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + TIXML_ERROR_PARSING_CDATA, + TIXML_ERROR_DOCUMENT_TOP_ONLY, + + TIXML_ERROR_STRING_COUNT + }; + +protected: + + static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + inline static bool IsWhiteSpace( char c ) + { + return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); + } + inline static bool IsWhiteSpace( int c ) + { + if ( c < 256 ) + return IsWhiteSpace( (char) c ); + return false; // Again, only truly correct for English/Latin...but usually works. + } + + #ifdef TIXML_USE_STL + static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); + static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); + #endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText( const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding ); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) + { + assert( p ); + if ( encoding == TIXML_ENCODING_UTF8 ) + { + *length = utf8ByteTable[ *((const unsigned char*)p) ]; + assert( *length >= 0 && *length < 5 ); + } + else + { + *length = 1; + } + + if ( *length == 1 ) + { + if ( *p == '&' ) + return GetEntity( p, _value, length, encoding ); + *_value = *p; + return p+1; + } + else if ( *length ) + { + //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), + // and the null terminator isn't needed + for( int i=0; p[i] && i<*length; ++i ) { + _value[i] = p[i]; + } + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for english, and should only be relied on when comparing + // to English words: StringEqual( p, "version", true ) is fine. + static bool StringEqual( const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding ); + + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); + static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); + inline static int ToLower( int v, TiXmlEncoding encoding ) + { + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( v < 128 ) return tolower( v ); + return v; + } + else + { + return tolower( v ); + } + } + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + +private: + TiXmlBase( const TiXmlBase& ); // not implemented. + void operator=( const TiXmlBase& base ); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: + #ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra whitespace or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base ); + + #endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + DOCUMENT, + ELEMENT, + COMMENT, + UNKNOWN, + TEXT, + DECLARATION, + TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The subclasses will wrap this function. + */ + const char *Value() const { return value.c_str (); } + + #ifdef TIXML_USE_STL + /** Return Value() as a std::string. If you only use STL, + this is more efficient than calling Value(). + Only available in STL mode. + */ + const std::string& ValueStr() const { return value; } + #endif + + const TIXML_STRING& ValueTStr() const { return value; } + + /** Changes the value of the node. Defined as: + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) { value = _value;} + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() { return parent; } + const TiXmlNode* Parent() const { return parent; } + + const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. + TiXmlNode* FirstChild() { return firstChild; } + const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + /// The first child of this node with the matching 'value'. Will be null if none found. + TiXmlNode* FirstChild( const char * _value ) { + // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) + // call the method, cast the return back to non-const. + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); + } + const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. + TiXmlNode* LastChild() { return lastChild; } + + const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. + TiXmlNode* LastChild( const char * _value ) { + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. + #endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); + } + + /// This flavor of IterateChildren searches for children with a particular 'value' + const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + #endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild( TiXmlNode* addThis ); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); + + /// Delete a child of this node. + bool RemoveChild( TiXmlNode* removeThis ); + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling() const { return prev; } + TiXmlNode* PreviousSibling() { return prev; } + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling( const char * ) const; + TiXmlNode* PreviousSibling( const char *_prev ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Navigate to a sibling node. + const TiXmlNode* NextSibling() const { return next; } + TiXmlNode* NextSibling() { return next; } + + /// Navigate to a sibling node with the given 'value'. + const TiXmlNode* NextSibling( const char * ) const; + TiXmlNode* NextSibling( const char* _next ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement() const; + TiXmlElement* NextSiblingElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement( const char * ) const; + TiXmlElement* NextSiblingElement( const char *_next ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement() const; + TiXmlElement* FirstChildElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); + } + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement( const char * _value ) const; + TiXmlElement* FirstChildElement( const char * _value ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: DOCUMENT, ELEMENT, COMMENT, + UNKNOWN, TEXT, and DECLARATION. + */ + int Type() const { return type; } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + const TiXmlDocument* GetDocument() const; + TiXmlDocument* GetDocument() { + return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); + } + + /// Returns true if this node has no children. + bool NoChildren() const { return !firstChild; } + + virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + + /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( TiXmlVisitor* visitor ) const = 0; + +protected: + TiXmlNode( NodeType _type ); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo( TiXmlNode* target ) const; + + #ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; + #endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode( const TiXmlNode& ); // not implemented. + void operator=( const TiXmlNode& base ); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute( const std::string& _name, const std::string& _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + #endif + + /// Construct an attribute with a name and value. + TiXmlAttribute( const char * _name, const char * _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. + const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. + #ifdef TIXML_USE_STL + const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. + #endif + int IntValue() const; ///< Return the value of this attribute, converted to an integer. + double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + // Get the tinyxml string representation + const TIXML_STRING& NameTStr() const { return name; } + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue( int* _value ) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue( double* _value ) const; + + void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. + void SetValue( const char* _value ) { value = _value; } ///< Set the value. + + void SetIntValue( int _value ); ///< Set the value from an integer. + void SetDoubleValue( double _value ); ///< Set the value from a double. + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetName( const std::string& _name ) { name = _name; } + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + const TiXmlAttribute* Next() const; + TiXmlAttribute* Next() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); + } + + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + const TiXmlAttribute* Previous() const; + TiXmlAttribute* Previous() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); + } + + bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } + bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } + bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + // Prints this Attribute to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument( TiXmlDocument* doc ) { document = doc; } + +private: + TiXmlAttribute( const TiXmlAttribute& ); // not implemented. + void operator=( const TiXmlAttribute& base ); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add( TiXmlAttribute* attribute ); + void Remove( TiXmlAttribute* attribute ); + + const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + + const TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* Find( const char* _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + #ifdef TIXML_USE_STL + const TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* Find( const std::string& _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + + #endif + +private: + //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), + //*ME: this class must be also use a hidden/disabled copy-constructor !!! + TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed + void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) + + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement (const char * in_value); + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement( const std::string& _value ); + #endif + + TiXmlElement( const TiXmlElement& ); + + void operator=( const TiXmlElement& base ); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute( const char* name ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute( const char* name, int* i ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute( const char* name, double* d ) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute( const char* name, double* _value ) const; + /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). + int QueryFloatAttribute( const char* name, float* _value ) const { + double d; + int result = QueryDoubleAttribute( name, &d ); + if ( result == TIXML_SUCCESS ) { + *_value = (float)d; + } + return result; + } + + #ifdef TIXML_USE_STL + /** Template form of the attribute query which will try to read the + attribute into the specified type. Very easy, very powerful, but + be careful to make sure to call this with the correct type. + + NOTE: This method doesn't work correctly for 'string' types. + + @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE + */ + template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + std::stringstream sstream( node->ValueStr() ); + sstream >> *outValue; + if ( !sstream.fail() ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; + } + /* + This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string" + but template specialization is hard to get working cross-compiler. Leaving the bug for now. + + // The above will fail for std::string because the space character is used as a seperator. + // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string + template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + *outValue = node->ValueStr(); + return TIXML_SUCCESS; + } + */ + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char* name, const char * _value ); + + #ifdef TIXML_USE_STL + const std::string* Attribute( const std::string& name ) const; + const std::string* Attribute( const std::string& name, int* i ) const; + const std::string* Attribute( const std::string& name, double* d ) const; + int QueryIntAttribute( const std::string& name, int* _value ) const; + int QueryDoubleAttribute( const std::string& name, double* _value ) const; + + /// STL std::string form. + void SetAttribute( const std::string& name, const std::string& _value ); + ///< STL std::string form. + void SetAttribute( const std::string& name, int _value ); + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char * name, int value ); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute( const char * name, double value ); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute( const char * name ); + #ifdef TIXML_USE_STL + void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. + #endif + + const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. + TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } + const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. + TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + + WARNING: GetText() accesses a child node - don't become confused with the + similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are + safe type casts on the referenced node. + */ + const char* GetText() const; + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + + void CopyTo( TiXmlElement* target ) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +private: + + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} + /// Construct a comment from text. + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { + SetValue( _value ); + } + TiXmlComment( const TiXmlComment& ); + void operator=( const TiXmlComment& base ); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + // Write this Comment to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlComment* target ) const; + + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif +// virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /** Constructor for text element. By default, it is treated as + normal, encoded text. If you want it be output as a CDATA text + element, set the parameter _cdata to 'true' + */ + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + virtual ~TiXmlText() {} + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + #endif + + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } + void operator=( const TiXmlText& base ) { base.CopyTo( this ); } + + // Write this text object to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /// Queries whether this represents text using a CDATA section. + bool CDATA() const { return cdata; } + /// Turns on or off a CDATA representation of text. + void SetCDATA( bool _cdata ) { cdata = _cdata; } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo( TiXmlText* target ) const; + + bool Blank() const; // returns true if all white space and new lines + // [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + bool cdata; // true if this should be input and output as a CDATA style text element +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ); +#endif + + /// Construct. + TiXmlDeclaration( const char* _version, + const char* _encoding, + const char* _standalone ); + + TiXmlDeclaration( const TiXmlDeclaration& copy ); + void operator=( const TiXmlDeclaration& copy ); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const { return version.c_str (); } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const { return encoding.c_str (); } + /// Is this a standalone document? + const char *Standalone() const { return standalone.c_str (); } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + // Print this declaration to a FILE stream. + virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlDeclaration* target ) const; + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } + void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + // Print this Unknown to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected: + void CopyTo( TiXmlUnknown* target ) const; + + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument( const char * documentName ); + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument( const std::string& documentName ); + #endif + + TiXmlDocument( const TiXmlDocument& copy ); + void operator=( const TiXmlDocument& copy ); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given filename. Returns true if successful. + bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given filename. Returns true if successful. + bool SaveFile( const char * filename ) const; + /** Load a file using the given FILE*. Returns true if successful. Note that this method + doesn't stream - the entire object pointed at by the FILE* + will be interpreted as an XML file. TinyXML doesn't stream in XML from the current + file location. Streaming may be added in the future. + */ + bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given FILE*. Returns true if successful. + bool SaveFile( FILE* ) const; + + #ifdef TIXML_USE_STL + bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && LoadFile( f.buffer, encoding )); + return LoadFile( filename.c_str(), encoding ); + } + bool SaveFile( const std::string& filename ) const ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && SaveFile( f.buffer )); + return SaveFile( filename.c_str() ); + } + #endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + const TiXmlElement* RootElement() const { return FirstChildElement(); } + TiXmlElement* RootElement() { return FirstChildElement(); } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const { return error; } + + /// Contains a textual (english) description of the error if one occurs. + const char * ErrorDesc() const { return errorDesc.c_str (); } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + int ErrorId() const { return errorId; } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() const { return errorLocation.row+1; } + int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() + + /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) + to report the correct values for row and column. It does not change the output + or input in any way. + + By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tabsize is set per document. Setting + the tabsize to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize( int _tabsize ) { tabsize = _tabsize; } + + int TabSize() const { return tabsize; } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() { error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Write the document to standard out using formatted printing ("pretty print"). */ + void Print() const { Print( stdout, 0 ); } + + /* Write the document to a string using formatted printing ("pretty print"). This + will allocate a character array (new char[]) and return it as a pointer. The + calling code pust call delete[] on the return char* to avoid a memory leak. + */ + //char* PrintToMemory() const; + + /// Print this Document to a FILE stream. + virtual void Print( FILE* cfile, int depth = 0 ) const; + // [internal use] + void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + + virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + // [internal use] + virtual TiXmlNode* Clone() const; + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + void CopyTo( TiXmlDocument* target ) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; + bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } + /// Copy constructor + TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild( const char * value ) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement( const char * value ) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( const char* value, int index ) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( int index ) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( const char* value, int index ) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( int index ) const; + + #ifdef TIXML_USE_STL + TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } + TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } + + TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } + TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } + #endif + + /** Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* ToNode() const { return node; } + /** Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } + /** Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } + /** Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } + + /** @deprecated use ToNode. + Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* Node() const { return ToNode(); } + /** @deprecated use ToElement. + Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* Element() const { return ToElement(); } + /** @deprecated use ToText() + Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* Text() const { return ToText(); } + /** @deprecated use ToUnknown() + Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* Unknown() const { return ToUnknown(); } + +private: + TiXmlNode* node; +}; + + +/** Print to memory functionality. The TiXmlPrinter is useful when you need to: + + -# Print to memory (especially in non-STL mode) + -# Control formatting (line endings, etc.) + + When constructed, the TiXmlPrinter is in its default "pretty printing" mode. + Before calling Accept() you can call methods to control the printing + of the XML document. After TiXmlNode::Accept() is called, the printed document can + be accessed via the CStr(), Str(), and Size() methods. + + TiXmlPrinter uses the Visitor API. + @verbatim + TiXmlPrinter printer; + printer.SetIndent( "\t" ); + + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + @endverbatim +*/ +class TiXmlPrinter : public TiXmlVisitor +{ +public: + TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), + buffer(), indent( " " ), lineBreak( "\n" ) {} + + virtual bool VisitEnter( const TiXmlDocument& doc ); + virtual bool VisitExit( const TiXmlDocument& doc ); + + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); + virtual bool VisitExit( const TiXmlElement& element ); + + virtual bool Visit( const TiXmlDeclaration& declaration ); + virtual bool Visit( const TiXmlText& text ); + virtual bool Visit( const TiXmlComment& comment ); + virtual bool Visit( const TiXmlUnknown& unknown ); + + /** Set the indent characters for printing. By default 4 spaces + but tab (\t) is also useful, or null/empty string for no indentation. + */ + void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } + /// Query the indention string. + const char* Indent() { return indent.c_str(); } + /** Set the line breaking string. By default set to newline (\n). + Some operating systems prefer other characters, or can be + set to the null/empty string for no indenation. + */ + void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } + /// Query the current line breaking string. + const char* LineBreak() { return lineBreak.c_str(); } + + /** Switch over to "stream printing" which is the most dense formatting without + linebreaks. Common when the XML is needed for network transmission. + */ + void SetStreamPrinting() { indent = ""; + lineBreak = ""; + } + /// Return the result. + const char* CStr() { return buffer.c_str(); } + /// Return the length of the result string. + size_t Size() { return buffer.size(); } + + #ifdef TIXML_USE_STL + /// Return the result. + const std::string& Str() { return buffer; } + #endif + +private: + void DoIndent() { + for( int i=0; i +#include + +#include "tinyxml.h" + +//#define DEBUG_PARSER +#if defined( DEBUG_PARSER ) +# if defined( DEBUG ) && defined( _MSC_VER ) +# include +# define TIXML_LOG OutputDebugString +# else +# define TIXML_LOG printf +# endif +#endif + +// Note tha "PutString" hardcodes the same list. This +// is less flexible than it appears. Changing the entries +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +{ + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } +}; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// Including the basic of this table, which determines the #bytes in the +// sequence from the lead byte. 1 placed for invalid sequences -- +// although the result will be junk, pass it through as much as possible. +// Beware of the non-characters in UTF-8: +// ef bb bf (Microsoft "lead bytes") +// ef bf be +// ef bf bf + +const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +const int TiXmlBase::utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; + + +void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } +} + + +/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalpha( anyByte ); +// } +} + + +/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalnum( anyByte ); +// } +} + + +class TiXmlParsingData +{ + friend class TiXmlDocument; + public: + void Stamp( const char* now, TiXmlEncoding encoding ); + + const TiXmlCursor& Cursor() { return cursor; } + + private: + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; +}; + + +void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) +{ + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Treat p as unsigned, so we have a happy compiler. + const unsigned char* pU = (const unsigned char*)p; + + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*pU) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case TIXML_UTF_LEAD_0: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); +} + + +const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) +{ + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + const unsigned char* pU = (const unsigned char*)p; + + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+2)==TIXML_UTF_LEAD_2 ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbeU ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbfU ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( (*p && IsWhiteSpace( *p )) || *p == '\n' || *p =='\r' ) + ++p; + } + + return p; +} + +#ifdef TIXML_USE_STL +/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) +{ + for( ;; ) + { + if ( !in->good() ) return false; + + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; + + *tag += (char) in->get(); + } +} + +/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) +{ + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; +} +#endif + +// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The +// "assign" optimization removes over 10% of the execution time. +// +const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) +{ + // Oddly, not supported on some comilers, + //name->clear(); + // So use this: + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + const char* start = p; + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + //(*name) += *p; // expensive + ++p; + } + if ( p-start > 0 ) { + name->assign( start, p-start ); + } + return p; + } + return 0; +} + +const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) +{ + // Presume an entity, and pull it out. + TIXML_STRING ent; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; iappend( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + if ( p ) + p += strlen( endTag ); + return p; +} + +#ifdef TIXML_USE_STL + +void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); +} + +#endif + +const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) +{ + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + const unsigned char* pU = (const unsigned char*)p; + if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 + && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 + && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) + { + encoding = TIXML_ENCODING_UTF8; + useMicrosoftBOM = true; + } + } + + p = SkipWhiteSpace( p, encoding ); + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // Was this empty? + if ( !firstChild ) { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); + return 0; + } + + // All is well. + return p; +} + +void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } +} + + +TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) +{ + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + TiXmlDocument* doc = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: "; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // [ 1475201 ] TinyXML parses entities in comments + // Oops - ReadText doesn't work, because we don't want to parse the entities. + // p = ReadText( p, &value, false, endTag, false, encoding ); + // + // from the XML spec: + /* + [Definition: Comments may appear anywhere in a document outside other markup; in addition, + they may appear within the document type declaration at places allowed by the grammar. + They are not part of the document's character data; an XML processor MAY, but need not, + make it possible for an application to retrieve the text of comments. For compatibility, + the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity + references MUST NOT be recognized within comments. + + An example of a comment: + + + */ + + value = ""; + // Keep all the white space. + while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) + { + value.append( p, 1 ); + ++p; + } + if ( p ) + p += strlen( endTag ); + + return p; +} + + +const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + +// int tabsize = 4; +// if ( document ) +// tabsize = document->TabSize(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + const char SINGLE_QUOTE = '\''; + const char DOUBLE_QUOTE = '\"'; + + if ( *p == SINGLE_QUOTE ) + { + ++p; + end = "\'"; // single quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == DOUBLE_QUOTE ) + { + ++p; + end = "\""; // double quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace + && *p != '/' && *p != '>' ) // tag end + { + if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { + // [ 1451649 ] Attribute values with trailing quotes not handled correctly + // We did not have an opening quote but seem to have a + // closing one. Give up and throw an error. + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + value += *p; + ++p; + } + } + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->peek(); + if ( !cdata && (c == '<' ) ) + { + return; + } + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); // "commits" the peek made above + + if ( cdata && c == '>' && tag->size() >= 3 ) { + size_t len = tag->size(); + if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { + // terminator of cdata. + return; + } + } + } +} +#endif + +const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + value = ""; + TiXmlDocument* document = GetDocument(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + const char* const startTag = ""; + + if ( cdata || StringEqual( p, startTag, false, encoding ) ) + { + cdata = true; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // Keep all the white space, ignore the encoding, etc. + while ( p && *p + && !StringEqual( p, endTag, false, encoding ) + ) + { + value += *p; + ++p; + } + + TIXML_STRING dummy; + p = ReadText( p, &dummy, false, endTag, false, encoding ); + return p; + } + else + { + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p ) + return p-1; // don't truncate the '<' + return 0; + } +} + +#ifdef TIXML_USE_STL +void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + +const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) +{ + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; +} + +bool TiXmlText::Blank() const +{ + for ( unsigned i=0; i + #include + using namespace std; +#else + #include +#endif + +#if defined( WIN32 ) && defined( TUNE ) + #include + _CrtMemState startMemState; + _CrtMemState endMemState; +#endif + +#include "tinyxml.h" + +static int gPass = 0; +static int gFail = 0; + + +bool XmlTest (const char* testString, const char* expected, const char* found, bool noEcho = false) +{ + bool pass = !strcmp( expected, found ); + if ( pass ) + printf ("[pass]"); + else + printf ("[fail]"); + + if ( noEcho ) + printf (" %s\n", testString); + else + printf (" %s [%s][%s]\n", testString, expected, found); + + if ( pass ) + ++gPass; + else + ++gFail; + return pass; +} + + +bool XmlTest( const char* testString, int expected, int found, bool noEcho = false ) +{ + bool pass = ( expected == found ); + if ( pass ) + printf ("[pass]"); + else + printf ("[fail]"); + + if ( noEcho ) + printf (" %s\n", testString); + else + printf (" %s [%d][%d]\n", testString, expected, found); + + if ( pass ) + ++gPass; + else + ++gFail; + return pass; +} + + +// +// This file demonstrates some basic functionality of TinyXml. +// Note that the example is very contrived. It presumes you know +// what is in the XML file. But it does test the basic operations, +// and show how to add and remove nodes. +// + +int main() +{ + // + // We start with the 'demoStart' todo list. Process it. And + // should hopefully end up with the todo list as illustrated. + // + const char* demoStart = + "\n" + "" + "\n" + "\n" + " Go to the Toy store!" + " Do bills " + " Look for Evil Dinosaurs! " + ""; + + { + + #ifdef TIXML_USE_STL + /* What the todo list should look like after processing. + In stream (no formatting) representation. */ + const char* demoEnd = + "" + "" + "" + "" + "Go to the" + "Toy store!" + "" + "" + "Talk to:" + "" + "" + "" + "" + "" + "" + "Do bills" + "" + ""; + #endif + + // The example parses from the character string (above): + #if defined( WIN32 ) && defined( TUNE ) + _CrtMemCheckpoint( &startMemState ); + #endif + + { + // Write to a file and read it back, to check file I/O. + + TiXmlDocument doc( "demotest.xml" ); + doc.Parse( demoStart ); + + if ( doc.Error() ) + { + printf( "Error in %s: %s\n", doc.Value(), doc.ErrorDesc() ); + exit( 1 ); + } + doc.SaveFile(); + } + + TiXmlDocument doc( "demotest.xml" ); + bool loadOkay = doc.LoadFile(); + + if ( !loadOkay ) + { + printf( "Could not load test file 'demotest.xml'. Error='%s'. Exiting.\n", doc.ErrorDesc() ); + exit( 1 ); + } + + printf( "** Demo doc read from disk: ** \n\n" ); + printf( "** Printing via doc.Print **\n" ); + doc.Print( stdout ); + + { + printf( "** Printing via TiXmlPrinter **\n" ); + TiXmlPrinter printer; + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + } + #ifdef TIXML_USE_STL + { + printf( "** Printing via operator<< **\n" ); + std::cout << doc; + } + #endif + TiXmlNode* node = 0; + TiXmlElement* todoElement = 0; + TiXmlElement* itemElement = 0; + + + // -------------------------------------------------------- + // An example of changing existing attributes, and removing + // an element from the document. + // -------------------------------------------------------- + + // Get the "ToDo" element. + // It is a child of the document, and can be selected by name. + node = doc.FirstChild( "ToDo" ); + assert( node ); + todoElement = node->ToElement(); + assert( todoElement ); + + // Going to the toy store is now our second priority... + // So set the "priority" attribute of the first item in the list. + node = todoElement->FirstChildElement(); // This skips the "PDA" comment. + assert( node ); + itemElement = node->ToElement(); + assert( itemElement ); + itemElement->SetAttribute( "priority", 2 ); + + // Change the distance to "doing bills" from + // "none" to "here". It's the next sibling element. + itemElement = itemElement->NextSiblingElement(); + assert( itemElement ); + itemElement->SetAttribute( "distance", "here" ); + + // Remove the "Look for Evil Dinosaurs!" item. + // It is 1 more sibling away. We ask the parent to remove + // a particular child. + itemElement = itemElement->NextSiblingElement(); + todoElement->RemoveChild( itemElement ); + + itemElement = 0; + + // -------------------------------------------------------- + // What follows is an example of created elements and text + // nodes and adding them to the document. + // -------------------------------------------------------- + + // Add some meetings. + TiXmlElement item( "Item" ); + item.SetAttribute( "priority", "1" ); + item.SetAttribute( "distance", "far" ); + + TiXmlText text( "Talk to:" ); + + TiXmlElement meeting1( "Meeting" ); + meeting1.SetAttribute( "where", "School" ); + + TiXmlElement meeting2( "Meeting" ); + meeting2.SetAttribute( "where", "Lunch" ); + + TiXmlElement attendee1( "Attendee" ); + attendee1.SetAttribute( "name", "Marple" ); + attendee1.SetAttribute( "position", "teacher" ); + + TiXmlElement attendee2( "Attendee" ); + attendee2.SetAttribute( "name", "Voel" ); + attendee2.SetAttribute( "position", "counselor" ); + + // Assemble the nodes we've created: + meeting1.InsertEndChild( attendee1 ); + meeting1.InsertEndChild( attendee2 ); + + item.InsertEndChild( text ); + item.InsertEndChild( meeting1 ); + item.InsertEndChild( meeting2 ); + + // And add the node to the existing list after the first child. + node = todoElement->FirstChild( "Item" ); + assert( node ); + itemElement = node->ToElement(); + assert( itemElement ); + + todoElement->InsertAfterChild( itemElement, item ); + + printf( "\n** Demo doc processed: ** \n\n" ); + doc.Print( stdout ); + + + #ifdef TIXML_USE_STL + printf( "** Demo doc processed to stream: ** \n\n" ); + cout << doc << endl << endl; + #endif + + // -------------------------------------------------------- + // Different tests...do we have what we expect? + // -------------------------------------------------------- + + int count = 0; + TiXmlElement* element; + + ////////////////////////////////////////////////////// + + #ifdef TIXML_USE_STL + cout << "** Basic structure. **\n"; + ostringstream outputStream( ostringstream::out ); + outputStream << doc; + XmlTest( "Output stream correct.", string( demoEnd ).c_str(), + outputStream.str().c_str(), true ); + #endif + + node = doc.RootElement(); + assert( node ); + XmlTest( "Root element exists.", true, ( node != 0 && node->ToElement() ) ); + XmlTest ( "Root element value is 'ToDo'.", "ToDo", node->Value()); + + node = node->FirstChild(); + XmlTest( "First child exists & is a comment.", true, ( node != 0 && node->ToComment() ) ); + node = node->NextSibling(); + XmlTest( "Sibling element exists & is an element.", true, ( node != 0 && node->ToElement() ) ); + XmlTest ( "Value is 'Item'.", "Item", node->Value() ); + + node = node->FirstChild(); + XmlTest ( "First child exists.", true, ( node != 0 && node->ToText() ) ); + XmlTest ( "Value is 'Go to the'.", "Go to the", node->Value() ); + + + ////////////////////////////////////////////////////// + printf ("\n** Iterators. **\n"); + + // Walk all the top level nodes of the document. + count = 0; + for( node = doc.FirstChild(); + node; + node = node->NextSibling() ) + { + count++; + } + XmlTest( "Top level nodes, using First / Next.", 3, count ); + + count = 0; + for( node = doc.LastChild(); + node; + node = node->PreviousSibling() ) + { + count++; + } + XmlTest( "Top level nodes, using Last / Previous.", 3, count ); + + // Walk all the top level nodes of the document, + // using a different syntax. + count = 0; + for( node = doc.IterateChildren( 0 ); + node; + node = doc.IterateChildren( node ) ) + { + count++; + } + XmlTest( "Top level nodes, using IterateChildren.", 3, count ); + + // Walk all the elements in a node. + count = 0; + for( element = todoElement->FirstChildElement(); + element; + element = element->NextSiblingElement() ) + { + count++; + } + XmlTest( "Children of the 'ToDo' element, using First / Next.", + 3, count ); + + // Walk all the elements in a node by value. + count = 0; + for( node = todoElement->FirstChild( "Item" ); + node; + node = node->NextSibling( "Item" ) ) + { + count++; + } + XmlTest( "'Item' children of the 'ToDo' element, using First/Next.", 3, count ); + + count = 0; + for( node = todoElement->LastChild( "Item" ); + node; + node = node->PreviousSibling( "Item" ) ) + { + count++; + } + XmlTest( "'Item' children of the 'ToDo' element, using Last/Previous.", 3, count ); + + #ifdef TIXML_USE_STL + { + cout << "\n** Parsing. **\n"; + istringstream parse0( "" ); + TiXmlElement element0( "default" ); + parse0 >> element0; + + XmlTest ( "Element parsed, value is 'Element0'.", "Element0", element0.Value() ); + XmlTest ( "Reads attribute 'attribute0=\"foo0\"'.", "foo0", element0.Attribute( "attribute0" )); + XmlTest ( "Reads incorrectly formatted 'attribute1=noquotes'.", "noquotes", element0.Attribute( "attribute1" ) ); + XmlTest ( "Read attribute with entity value '>'.", ">", element0.Attribute( "attribute2" ) ); + } + #endif + + { + const char* error = "\n" + "\n" + " \n" + ""; + + TiXmlDocument docTest; + docTest.Parse( error ); + XmlTest( "Error row", docTest.ErrorRow(), 3 ); + XmlTest( "Error column", docTest.ErrorCol(), 17 ); + //printf( "error=%d id='%s' row %d col%d\n", (int) doc.Error(), doc.ErrorDesc(), doc.ErrorRow()+1, doc.ErrorCol() + 1 ); + + } + + #ifdef TIXML_USE_STL + { + ////////////////////////////////////////////////////// + cout << "\n** Streaming. **\n"; + + // Round trip check: stream in, then stream back out to verify. The stream + // out has already been checked, above. We use the output + + istringstream inputStringStream( outputStream.str() ); + TiXmlDocument document0; + + inputStringStream >> document0; + + ostringstream outputStream0( ostringstream::out ); + outputStream0 << document0; + + XmlTest( "Stream round trip correct.", string( demoEnd ).c_str(), + outputStream0.str().c_str(), true ); + + std::string str; + str << document0; + + XmlTest( "String printing correct.", string( demoEnd ).c_str(), + str.c_str(), true ); + } + #endif + } + + { + const char* str = ""; + + TiXmlDocument doc; + doc.Parse( str ); + + TiXmlElement* ele = doc.FirstChildElement(); + + int iVal, result; + double dVal; + + result = ele->QueryDoubleAttribute( "attr0", &dVal ); + XmlTest( "Query attribute: int as double", result, TIXML_SUCCESS ); + XmlTest( "Query attribute: int as double", (int)dVal, 1 ); + result = ele->QueryDoubleAttribute( "attr1", &dVal ); + XmlTest( "Query attribute: double as double", (int)dVal, 2 ); + result = ele->QueryIntAttribute( "attr1", &iVal ); + XmlTest( "Query attribute: double as int", result, TIXML_SUCCESS ); + XmlTest( "Query attribute: double as int", iVal, 2 ); + result = ele->QueryIntAttribute( "attr2", &iVal ); + XmlTest( "Query attribute: not a number", result, TIXML_WRONG_TYPE ); + result = ele->QueryIntAttribute( "bar", &iVal ); + XmlTest( "Query attribute: does not exist", result, TIXML_NO_ATTRIBUTE ); + } + + { + const char* str = "\t\t\n" + ""; + + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Parse( str ); + + TiXmlHandle docHandle( &doc ); + TiXmlHandle roomHandle = docHandle.FirstChildElement( "room" ); + + assert( docHandle.Node() ); + assert( roomHandle.Element() ); + + TiXmlElement* room = roomHandle.Element(); + assert( room ); + TiXmlAttribute* doors = room->FirstAttribute(); + assert( doors ); + + XmlTest( "Location tracking: Tab 8: room row", room->Row(), 1 ); + XmlTest( "Location tracking: Tab 8: room col", room->Column(), 49 ); + XmlTest( "Location tracking: Tab 8: doors row", doors->Row(), 1 ); + XmlTest( "Location tracking: Tab 8: doors col", doors->Column(), 55 ); + } + + { + const char* str = "\t\t\n" + " \n" + " A great door!\n" + "\t" + ""; + + TiXmlDocument doc; + doc.Parse( str ); + + TiXmlHandle docHandle( &doc ); + TiXmlHandle roomHandle = docHandle.FirstChildElement( "room" ); + TiXmlHandle commentHandle = docHandle.FirstChildElement( "room" ).FirstChild(); + TiXmlHandle textHandle = docHandle.FirstChildElement( "room" ).ChildElement( "door", 0 ).FirstChild(); + TiXmlHandle door0Handle = docHandle.FirstChildElement( "room" ).ChildElement( 0 ); + TiXmlHandle door1Handle = docHandle.FirstChildElement( "room" ).ChildElement( 1 ); + + assert( docHandle.Node() ); + assert( roomHandle.Element() ); + assert( commentHandle.Node() ); + assert( textHandle.Text() ); + assert( door0Handle.Element() ); + assert( door1Handle.Element() ); + + TiXmlDeclaration* declaration = doc.FirstChild()->ToDeclaration(); + assert( declaration ); + TiXmlElement* room = roomHandle.Element(); + assert( room ); + TiXmlAttribute* doors = room->FirstAttribute(); + assert( doors ); + TiXmlText* text = textHandle.Text(); + TiXmlComment* comment = commentHandle.Node()->ToComment(); + assert( comment ); + TiXmlElement* door0 = door0Handle.Element(); + TiXmlElement* door1 = door1Handle.Element(); + + XmlTest( "Location tracking: Declaration row", declaration->Row(), 1 ); + XmlTest( "Location tracking: Declaration col", declaration->Column(), 5 ); + XmlTest( "Location tracking: room row", room->Row(), 1 ); + XmlTest( "Location tracking: room col", room->Column(), 45 ); + XmlTest( "Location tracking: doors row", doors->Row(), 1 ); + XmlTest( "Location tracking: doors col", doors->Column(), 51 ); + XmlTest( "Location tracking: Comment row", comment->Row(), 2 ); + XmlTest( "Location tracking: Comment col", comment->Column(), 3 ); + XmlTest( "Location tracking: text row", text->Row(), 3 ); + XmlTest( "Location tracking: text col", text->Column(), 24 ); + XmlTest( "Location tracking: door0 row", door0->Row(), 3 ); + XmlTest( "Location tracking: door0 col", door0->Column(), 5 ); + XmlTest( "Location tracking: door1 row", door1->Row(), 4 ); + XmlTest( "Location tracking: door1 col", door1->Column(), 5 ); + } + + + // -------------------------------------------------------- + // UTF-8 testing. It is important to test: + // 1. Making sure name, value, and text read correctly + // 2. Row, Col functionality + // 3. Correct output + // -------------------------------------------------------- + printf ("\n** UTF-8 **\n"); + { + TiXmlDocument doc( "utf8test.xml" ); + doc.LoadFile(); + if ( doc.Error() && doc.ErrorId() == TiXmlBase::TIXML_ERROR_OPENING_FILE ) { + printf( "WARNING: File 'utf8test.xml' not found.\n" + "(Are you running the test from the wrong directory?)\n" + "Could not test UTF-8 functionality.\n" ); + } + else + { + TiXmlHandle docH( &doc ); + // Get the attribute "value" from the "Russian" element and check it. + TiXmlElement* element = docH.FirstChildElement( "document" ).FirstChildElement( "Russian" ).Element(); + const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU, + 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 }; + + XmlTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ), true ); + XmlTest( "UTF-8: Russian value row.", 4, element->Row() ); + XmlTest( "UTF-8: Russian value column.", 5, element->Column() ); + + const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U, + 0xd1U, 0x81U, 0xd1U, 0x81U, + 0xd0U, 0xbaU, 0xd0U, 0xb8U, + 0xd0U, 0xb9U, 0 }; + const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>"; + + TiXmlText* text = docH.FirstChildElement( "document" ).FirstChildElement( (const char*) russianElementName ).Child( 0 ).Text(); + XmlTest( "UTF-8: Browsing russian element name.", + russianText, + text->Value(), + true ); + XmlTest( "UTF-8: Russian element name row.", 7, text->Row() ); + XmlTest( "UTF-8: Russian element name column.", 47, text->Column() ); + + TiXmlDeclaration* dec = docH.Child( 0 ).Node()->ToDeclaration(); + XmlTest( "UTF-8: Declaration column.", 1, dec->Column() ); + XmlTest( "UTF-8: Document column.", 1, doc.Column() ); + + // Now try for a round trip. + doc.SaveFile( "utf8testout.xml" ); + + // Check the round trip. + char savedBuf[256]; + char verifyBuf[256]; + int okay = 1; + + FILE* saved = fopen( "utf8testout.xml", "r" ); + FILE* verify = fopen( "utf8testverify.xml", "r" ); + if ( saved && verify ) + { + while ( fgets( verifyBuf, 256, verify ) ) + { + fgets( savedBuf, 256, saved ); + if ( strcmp( verifyBuf, savedBuf ) ) + { + okay = 0; + break; + } + } + fclose( saved ); + fclose( verify ); + } + XmlTest( "UTF-8: Verified multi-language round trip.", 1, okay ); + + // On most Western machines, this is an element that contains + // the word "resume" with the correct accents, in a latin encoding. + // It will be something else completely on non-wester machines, + // which is why TinyXml is switching to UTF-8. + const char latin[] = "r\x82sum\x82"; + + TiXmlDocument latinDoc; + latinDoc.Parse( latin, 0, TIXML_ENCODING_LEGACY ); + + text = latinDoc.FirstChildElement()->FirstChild()->ToText(); + XmlTest( "Legacy encoding: Verify text element.", "r\x82sum\x82", text->Value() ); + } + } + + ////////////////////// + // Copy and assignment + ////////////////////// + printf ("\n** Copy and Assignment **\n"); + { + TiXmlElement element( "foo" ); + element.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); + + TiXmlElement elementCopy( element ); + TiXmlElement elementAssign( "foo" ); + elementAssign.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); + elementAssign = element; + + XmlTest( "Copy/Assign: element copy #1.", "element", elementCopy.Value() ); + XmlTest( "Copy/Assign: element copy #2.", "value", elementCopy.Attribute( "name" ) ); + XmlTest( "Copy/Assign: element assign #1.", "element", elementAssign.Value() ); + XmlTest( "Copy/Assign: element assign #2.", "value", elementAssign.Attribute( "name" ) ); + XmlTest( "Copy/Assign: element assign #3.", true, ( 0 == elementAssign.Attribute( "foo" )) ); + + TiXmlComment comment; + comment.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); + TiXmlComment commentCopy( comment ); + TiXmlComment commentAssign; + commentAssign = commentCopy; + XmlTest( "Copy/Assign: comment copy.", "comment", commentCopy.Value() ); + XmlTest( "Copy/Assign: comment assign.", "comment", commentAssign.Value() ); + + TiXmlUnknown unknown; + unknown.Parse( "<[unknown]>", 0, TIXML_ENCODING_UNKNOWN ); + TiXmlUnknown unknownCopy( unknown ); + TiXmlUnknown unknownAssign; + unknownAssign.Parse( "incorrect", 0, TIXML_ENCODING_UNKNOWN ); + unknownAssign = unknownCopy; + XmlTest( "Copy/Assign: unknown copy.", "[unknown]", unknownCopy.Value() ); + XmlTest( "Copy/Assign: unknown assign.", "[unknown]", unknownAssign.Value() ); + + TiXmlText text( "TextNode" ); + TiXmlText textCopy( text ); + TiXmlText textAssign( "incorrect" ); + textAssign = text; + XmlTest( "Copy/Assign: text copy.", "TextNode", textCopy.Value() ); + XmlTest( "Copy/Assign: text assign.", "TextNode", textAssign.Value() ); + + TiXmlDeclaration dec; + dec.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); + TiXmlDeclaration decCopy( dec ); + TiXmlDeclaration decAssign; + decAssign = dec; + + XmlTest( "Copy/Assign: declaration copy.", "UTF-8", decCopy.Encoding() ); + XmlTest( "Copy/Assign: text assign.", "UTF-8", decAssign.Encoding() ); + + TiXmlDocument doc; + elementCopy.InsertEndChild( textCopy ); + doc.InsertEndChild( decAssign ); + doc.InsertEndChild( elementCopy ); + doc.InsertEndChild( unknownAssign ); + + TiXmlDocument docCopy( doc ); + TiXmlDocument docAssign; + docAssign = docCopy; + + #ifdef TIXML_USE_STL + std::string original, copy, assign; + original << doc; + copy << docCopy; + assign << docAssign; + XmlTest( "Copy/Assign: document copy.", original.c_str(), copy.c_str(), true ); + XmlTest( "Copy/Assign: document assign.", original.c_str(), assign.c_str(), true ); + + #endif + } + + ////////////////////////////////////////////////////// +#ifdef TIXML_USE_STL + printf ("\n** Parsing, no Condense Whitespace **\n"); + TiXmlBase::SetCondenseWhiteSpace( false ); + { + istringstream parse1( "This is \ntext" ); + TiXmlElement text1( "text" ); + parse1 >> text1; + + XmlTest ( "Condense white space OFF.", "This is \ntext", + text1.FirstChild()->Value(), + true ); + } + TiXmlBase::SetCondenseWhiteSpace( true ); +#endif + + ////////////////////////////////////////////////////// + // GetText(); + { + const char* str = "This is text"; + TiXmlDocument doc; + doc.Parse( str ); + const TiXmlElement* element = doc.RootElement(); + + XmlTest( "GetText() normal use.", "This is text", element->GetText() ); + + str = "This is text"; + doc.Clear(); + doc.Parse( str ); + element = doc.RootElement(); + + XmlTest( "GetText() contained element.", element->GetText() == 0, true ); + + str = "This is text"; + doc.Clear(); + TiXmlBase::SetCondenseWhiteSpace( false ); + doc.Parse( str ); + TiXmlBase::SetCondenseWhiteSpace( true ); + element = doc.RootElement(); + + XmlTest( "GetText() partial.", "This is ", element->GetText() ); + } + + + ////////////////////////////////////////////////////// + // CDATA + { + const char* str = "" + " the rules!\n" + "...since I make symbolic puns" + "]]>" + ""; + TiXmlDocument doc; + doc.Parse( str ); + doc.Print(); + + XmlTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(), + "I am > the rules!\n...since I make symbolic puns", + true ); + + #ifdef TIXML_USE_STL + //cout << doc << '\n'; + + doc.Clear(); + + istringstream parse0( str ); + parse0 >> doc; + //cout << doc << '\n'; + + XmlTest( "CDATA stream.", doc.FirstChildElement()->FirstChild()->Value(), + "I am > the rules!\n...since I make symbolic puns", + true ); + #endif + + TiXmlDocument doc1 = doc; + //doc.Print(); + + XmlTest( "CDATA copy.", doc1.FirstChildElement()->FirstChild()->Value(), + "I am > the rules!\n...since I make symbolic puns", + true ); + } + { + // [ 1482728 ] Wrong wide char parsing + char buf[256]; + buf[255] = 0; + for( int i=0; i<255; ++i ) { + buf[i] = (char)((i>=32) ? i : 32); + } + TIXML_STRING str( ""; + + TiXmlDocument doc; + doc.Parse( str.c_str() ); + + TiXmlPrinter printer; + printer.SetStreamPrinting(); + doc.Accept( &printer ); + + XmlTest( "CDATA with all bytes #1.", str.c_str(), printer.CStr(), true ); + + #ifdef TIXML_USE_STL + doc.Clear(); + istringstream iss( printer.Str() ); + iss >> doc; + std::string out; + out << doc; + XmlTest( "CDATA with all bytes #2.", out.c_str(), printer.CStr(), true ); + #endif + } + { + // [ 1480107 ] Bug-fix for STL-streaming of CDATA that contains tags + // CDATA streaming had a couple of bugs, that this tests for. + const char* str = "" + "I am > the rules!\n" + "...since I make symbolic puns" + "]]>" + ""; + TiXmlDocument doc; + doc.Parse( str ); + doc.Print(); + + XmlTest( "CDATA parse. [ 1480107 ]", doc.FirstChildElement()->FirstChild()->Value(), + "I am > the rules!\n...since I make symbolic puns", + true ); + + #ifdef TIXML_USE_STL + + doc.Clear(); + + istringstream parse0( str ); + parse0 >> doc; + + XmlTest( "CDATA stream. [ 1480107 ]", doc.FirstChildElement()->FirstChild()->Value(), + "I am > the rules!\n...since I make symbolic puns", + true ); + #endif + + TiXmlDocument doc1 = doc; + //doc.Print(); + + XmlTest( "CDATA copy. [ 1480107 ]", doc1.FirstChildElement()->FirstChild()->Value(), + "I am > the rules!\n...since I make symbolic puns", + true ); + } + ////////////////////////////////////////////////////// + // Visit() + + + + ////////////////////////////////////////////////////// + printf( "\n** Fuzzing... **\n" ); + + const int FUZZ_ITERATION = 300; + + // The only goal is not to crash on bad input. + int len = (int) strlen( demoStart ); + for( int i=0; i" + "" + " " + ""; + + TiXmlDocument doc( "passages.xml" ); + doc.Parse( passages ); + TiXmlElement* psg = doc.RootElement()->FirstChildElement(); + const char* context = psg->Attribute( "context" ); + const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9."; + + XmlTest( "Entity transformation: read. ", expected, context, true ); + + FILE* textfile = fopen( "textfile.txt", "w" ); + if ( textfile ) + { + psg->Print( textfile, 0 ); + fclose( textfile ); + } + textfile = fopen( "textfile.txt", "r" ); + assert( textfile ); + if ( textfile ) + { + char buf[ 1024 ]; + fgets( buf, 1024, textfile ); + XmlTest( "Entity transformation: write. ", + "", + buf, + true ); + } + fclose( textfile ); + } + + { + FILE* textfile = fopen( "test5.xml", "w" ); + if ( textfile ) + { + fputs("", textfile); + fclose(textfile); + + TiXmlDocument doc; + doc.LoadFile( "test5.xml" ); + XmlTest( "dot in element attributes and names", doc.Error(), 0); + } + } + + { + FILE* textfile = fopen( "test6.xml", "w" ); + if ( textfile ) + { + fputs("1.1 Start easy ignore fin thickness ", textfile ); + fclose(textfile); + + TiXmlDocument doc; + bool result = doc.LoadFile( "test6.xml" ); + XmlTest( "Entity with one digit.", result, true ); + + TiXmlText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText(); + XmlTest( "Entity with one digit.", + text->Value(), "1.1 Start easy ignore fin thickness\n" ); + } + } + + { + // DOCTYPE not preserved (950171) + // + const char* doctype = + "" + "" + "" + "" + ""; + + TiXmlDocument doc; + doc.Parse( doctype ); + doc.SaveFile( "test7.xml" ); + doc.Clear(); + doc.LoadFile( "test7.xml" ); + + TiXmlHandle docH( &doc ); + TiXmlUnknown* unknown = docH.Child( 1 ).Unknown(); + XmlTest( "Correct value of unknown.", "!DOCTYPE PLAY SYSTEM 'play.dtd'", unknown->Value() ); + #ifdef TIXML_USE_STL + TiXmlNode* node = docH.Child( 2 ).Node(); + std::string str; + str << (*node); + XmlTest( "Correct streaming of unknown.", "", str.c_str() ); + #endif + } + + { + // [ 791411 ] Formatting bug + // Comments do not stream out correctly. + const char* doctype = + ""; + TiXmlDocument doc; + doc.Parse( doctype ); + + TiXmlHandle docH( &doc ); + TiXmlComment* comment = docH.Child( 0 ).Node()->ToComment(); + + XmlTest( "Comment formatting.", " Somewhat ", comment->Value() ); + #ifdef TIXML_USE_STL + std::string str; + str << (*comment); + XmlTest( "Comment streaming.", "", str.c_str() ); + #endif + } + + { + // [ 870502 ] White space issues + TiXmlDocument doc; + TiXmlText* text; + TiXmlHandle docH( &doc ); + + const char* doctype0 = " This has leading and trailing space "; + const char* doctype1 = "This has internal space"; + const char* doctype2 = " This has leading, trailing, and internal space "; + + TiXmlBase::SetCondenseWhiteSpace( false ); + doc.Clear(); + doc.Parse( doctype0 ); + text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); + XmlTest( "White space kept.", " This has leading and trailing space ", text->Value() ); + + doc.Clear(); + doc.Parse( doctype1 ); + text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); + XmlTest( "White space kept.", "This has internal space", text->Value() ); + + doc.Clear(); + doc.Parse( doctype2 ); + text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); + XmlTest( "White space kept.", " This has leading, trailing, and internal space ", text->Value() ); + + TiXmlBase::SetCondenseWhiteSpace( true ); + doc.Clear(); + doc.Parse( doctype0 ); + text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); + XmlTest( "White space condensed.", "This has leading and trailing space", text->Value() ); + + doc.Clear(); + doc.Parse( doctype1 ); + text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); + XmlTest( "White space condensed.", "This has internal space", text->Value() ); + + doc.Clear(); + doc.Parse( doctype2 ); + text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); + XmlTest( "White space condensed.", "This has leading, trailing, and internal space", text->Value() ); + } + + { + // Double attributes + const char* doctype = ""; + + TiXmlDocument doc; + doc.Parse( doctype ); + + XmlTest( "Parsing repeated attributes.", 0, (int)doc.Error() ); // not an error to tinyxml + XmlTest( "Parsing repeated attributes.", "blue", doc.FirstChildElement( "element" )->Attribute( "attr" ) ); + } + + { + // Embedded null in stream. + const char* doctype = ""; + + TiXmlDocument doc; + doc.Parse( doctype ); + XmlTest( "Embedded null throws error.", true, doc.Error() ); + + #ifdef TIXML_USE_STL + istringstream strm( doctype ); + doc.Clear(); + doc.ClearError(); + strm >> doc; + XmlTest( "Embedded null throws error.", true, doc.Error() ); + #endif + } + + { + // Legacy mode test. (This test may only pass on a western system) + const char* str = + "" + "<ä>" + "CöntäntßäöüÄÖÜ" + ""; + + TiXmlDocument doc; + doc.Parse( str ); + + TiXmlHandle docHandle( &doc ); + TiXmlHandle aHandle = docHandle.FirstChildElement( "ä" ); + TiXmlHandle tHandle = aHandle.Child( 0 ); + assert( aHandle.Element() ); + assert( tHandle.Text() ); + XmlTest( "ISO-8859-1 Parsing.", "CöntäntßäöüÄÖÜ", tHandle.Text()->Value() ); + } + + { + // Empty documents should return TIXML_ERROR_PARSING_EMPTY, bug 1070717 + const char* str = " "; + TiXmlDocument doc; + doc.Parse( str ); + XmlTest( "Empty document error TIXML_ERROR_DOCUMENT_EMPTY", TiXmlBase::TIXML_ERROR_DOCUMENT_EMPTY, doc.ErrorId() ); + } + #ifndef TIXML_USE_STL + { + // String equality. [ 1006409 ] string operator==/!= no worky in all cases + TiXmlString temp; + XmlTest( "Empty tinyxml string compare equal", ( temp == "" ), true ); + + TiXmlString foo; + TiXmlString bar( "" ); + XmlTest( "Empty tinyxml string compare equal", ( foo == bar ), true ); + } + + #endif + { + // Bug [ 1195696 ] from marlonism + TiXmlBase::SetCondenseWhiteSpace(false); + TiXmlDocument xml; + xml.Parse("This hangs"); + XmlTest( "Test safe error return.", xml.Error(), false ); + } + + { + // Bug [ 1243992 ] - another infinite loop + TiXmlDocument doc; + doc.SetCondenseWhiteSpace(false); + doc.Parse("

test

"); + } + { + // Low entities + TiXmlDocument xml; + xml.Parse( "" ); + const char result[] = { 0x0e, 0 }; + XmlTest( "Low entities.", xml.FirstChildElement()->GetText(), result ); + xml.Print(); + } + { + // Bug [ 1451649 ] Attribute values with trailing quotes not handled correctly + TiXmlDocument xml; + xml.Parse( "" ); + XmlTest( "Throw error with bad end quotes.", xml.Error(), true ); + } + #ifdef TIXML_USE_STL + { + // Bug [ 1449463 ] Consider generic query + TiXmlDocument xml; + xml.Parse( "" ); + + TiXmlElement* ele = xml.FirstChildElement(); + double d; + int i; + float f; + bool b; + //std::string str; + + XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &d ), TIXML_SUCCESS ); + XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &i ), TIXML_SUCCESS ); + XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &f ), TIXML_SUCCESS ); + XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &b ), TIXML_WRONG_TYPE ); + XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "nobar", &b ), TIXML_NO_ATTRIBUTE ); + //XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "barStr", &str ), TIXML_SUCCESS ); + + XmlTest( "QueryValueAttribute", (d==3.0), true ); + XmlTest( "QueryValueAttribute", (i==3), true ); + XmlTest( "QueryValueAttribute", (f==3.0f), true ); + //XmlTest( "QueryValueAttribute", (str==std::string( "a string" )), true ); + } + #endif + + #ifdef TIXML_USE_STL + { + // [ 1505267 ] redundant malloc in TiXmlElement::Attribute + TiXmlDocument xml; + xml.Parse( "" ); + TiXmlElement* ele = xml.FirstChildElement(); + double d; + int i; + + std::string bar = "bar"; + + const std::string* atrrib = ele->Attribute( bar ); + ele->Attribute( bar, &d ); + ele->Attribute( bar, &i ); + + XmlTest( "Attribute", atrrib->empty(), false ); + XmlTest( "Attribute", (d==3.0), true ); + XmlTest( "Attribute", (i==3), true ); + } + #endif + + { + // [ 1356059 ] Allow TiXMLDocument to only be at the top level + TiXmlDocument xml, xml2; + xml.InsertEndChild( xml2 ); + XmlTest( "Document only at top level.", xml.Error(), true ); + XmlTest( "Document only at top level.", xml.ErrorId(), TiXmlBase::TIXML_ERROR_DOCUMENT_TOP_ONLY ); + } + + { + // [ 1663758 ] Failure to report error on bad XML + TiXmlDocument xml; + xml.Parse(""); + XmlTest("Missing end tag at end of input", xml.Error(), true); + xml.Parse(" "); + XmlTest("Missing end tag with trailing whitespace", xml.Error(), true); + } + + { + // [ 1635701 ] fail to parse files with a tag separated into two lines + // I'm not sure this is a bug. Marked 'pending' for feedback. + TiXmlDocument xml; + xml.Parse( "<p>text</p\n><title>" ); + //xml.Print(); + //XmlTest( "Tag split by newline", xml.Error(), false ); + } + + #ifdef TIXML_USE_STL + { + // [ 1475201 ] TinyXML parses entities in comments + TiXmlDocument xml; + istringstream parse1( "<!-- declarations for <head> & <body> -->" + "<!-- far & away -->" ); + parse1 >> xml; + + TiXmlNode* e0 = xml.FirstChild(); + TiXmlNode* e1 = e0->NextSibling(); + TiXmlComment* c0 = e0->ToComment(); + TiXmlComment* c1 = e1->ToComment(); + + XmlTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true ); + XmlTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); + } + #endif + + { + // [ 1475201 ] TinyXML parses entities in comments + TiXmlDocument xml; + xml.Parse("<!-- declarations for <head> & <body> -->" + "<!-- far & away -->" ); + + TiXmlNode* e0 = xml.FirstChild(); + TiXmlNode* e1 = e0->NextSibling(); + TiXmlComment* c0 = e0->ToComment(); + TiXmlComment* c1 = e1->ToComment(); + + XmlTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true ); + XmlTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); + } + /* + { + TiXmlDocument xml; + xml.Parse( "<tag>/</tag>" ); + xml.Print(); + xml.FirstChild()->Print( stdout, 0 ); + xml.FirstChild()->Type(); + } + */ + + /* 1417717 experiment + { + TiXmlDocument xml; + xml.Parse("<text>Dan & Tracie</text>"); + xml.Print(stdout); + } + { + TiXmlDocument xml; + xml.Parse("<text>Dan &foo; Tracie</text>"); + xml.Print(stdout); + } + */ + #if defined( WIN32 ) && defined( TUNE ) + _CrtMemCheckpoint( &endMemState ); + //_CrtMemDumpStatistics( &endMemState ); + + _CrtMemState diffMemState; + _CrtMemDifference( &diffMemState, &startMemState, &endMemState ); + _CrtMemDumpStatistics( &diffMemState ); + #endif + + printf ("\nPass %d, Fail %d\n", gPass, gFail); + return gFail; +} + + diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index bd977eb..d7bf65d 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -46,6 +46,7 @@ AppFrame::AppFrame() : demodModeSelector->addChoice(DEMOD_TYPE_AM,"AM"); demodModeSelector->addChoice(DEMOD_TYPE_LSB,"LSB"); demodModeSelector->addChoice(DEMOD_TYPE_USB,"USB"); + demodModeSelector->addChoice(DEMOD_TYPE_DSB,"DSB"); demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0); // demodTray->AddSpacer(2); diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h index 5d16436..f7c52ba 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -12,6 +12,7 @@ #define DEMOD_TYPE_AM 2 #define DEMOD_TYPE_LSB 3 #define DEMOD_TYPE_USB 4 +#define DEMOD_TYPE_DSB 5 class DemodulatorThread; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 1f12c22..8bcee24 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -16,6 +16,7 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQue demodFM = freqdem_create(0.5); demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1); demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1); + demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1); demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0); demodAM = demodAM_DSB_CSP; @@ -174,6 +175,7 @@ void DemodulatorThread::threadMain() { } break; case DEMOD_TYPE_AM: + case DEMOD_TYPE_DSB: break; } @@ -357,6 +359,9 @@ void DemodulatorThread::threadMain() { case DEMOD_TYPE_USB: demodAM = demodAM_LSB; break; + case DEMOD_TYPE_DSB: + demodAM = demodAM_DSB; + break; case DEMOD_TYPE_AM: demodAM = demodAM_DSB_CSP; break; diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index 898f4d6..01bd5eb 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -62,6 +62,7 @@ protected: freqdem demodFM; ampmodem demodAM; ampmodem demodAM_DSB_CSP; + ampmodem demodAM_DSB; ampmodem demodAM_LSB; ampmodem demodAM_USB; diff --git a/src/util/DataTree.cpp b/src/util/DataTree.cpp new file mode 100755 index 0000000..c8c5f16 --- /dev/null +++ b/src/util/DataTree.cpp @@ -0,0 +1,1780 @@ +/* + * DataElement/DataNode/DataTree -- structured serialization/unserialization system + * designed for the CoolMule project :) + * + Copyright (C) 2003 by Charles J. Cliffe + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +#include "DataTree.h" +#include <fstream> +#include <math.h> + +/* DataElement class */ + +using namespace std; + +DataElement::DataElement() { + data_type = DATA_NULL; + data_val = NULL; + data_size = 0; +} + +DataElement::~DataElement() { + if (data_val) + delete data_val; +} + +void DataElement::data_init(long data_size_in) { + if (data_val) + delete data_val; + data_size = data_size_in; + data_val = new char[data_size]; +} + +int DataElement::getDataType() { + return data_type; +} + +long DataElement::getDataSize() { + return data_size; +} + +//void DataElement::set(const bool &bool_in) +//{ +// data_type = DATA_BOOL; +// data_init(sizeof(bool)); +// memcpy(data_val,&bool_in,data_size); +//} + +void DataElement::set(const char& char_in) { + data_type = DATA_CHAR; + data_init(sizeof(char)); + memcpy(data_val, &char_in, data_size); +} + +void DataElement::set(const unsigned char& uchar_in) { + data_type = DATA_UCHAR; + data_init(sizeof(unsigned char)); + memcpy(data_val, &uchar_in, data_size); +} + +void DataElement::set(const unsigned int& uint_in) { + data_type = DATA_UINT; + data_init(sizeof(unsigned int)); + memcpy(data_val, &uint_in, data_size); +} + +void DataElement::set(const unsigned long & ulong_in) { + data_type = DATA_ULONG; + data_init(sizeof(unsigned long)); + memcpy(data_val, &ulong_in, data_size); +} + +void DataElement::set(const long long & llong_in) { + data_type = DATA_ULONG; + data_init(sizeof(long long)); + memcpy(data_val, &llong_in, data_size); +} + +void DataElement::set(const long double& ldouble_in) { + data_type = DATA_LONGDOUBLE; + data_init(sizeof(long double)); + memcpy(data_val, &ldouble_in, data_size); +} + +void DataElement::set(const int &int_in) { + data_type = DATA_INT; + data_init(sizeof(int)); + memcpy(data_val, &int_in, data_size); +} + +void DataElement::set(const long &long_in) { + data_type = DATA_LONG; + data_init(sizeof(long)); + memcpy(data_val, &long_in, data_size); +} + +void DataElement::set(const float &float_in) { + data_type = DATA_FLOAT; + data_init(sizeof(float)); + memcpy(data_val, &float_in, data_size); +} + +void DataElement::set(const double &double_in) { + data_type = DATA_DOUBLE; + data_init(sizeof(double)); + memcpy(data_val, &double_in, data_size); +} + +void DataElement::set(const char *data_in, long size_in) { + data_type = DATA_FLOAT; + data_init(size_in); + memcpy(data_val, data_in, data_size); +} + +void DataElement::set(const char *data_in) { + data_type = DATA_VOID; + data_init(strlen(data_in) + 1); + memcpy(data_val, data_in, data_size); +} + +void DataElement::set(const string &str_in) { + data_type = DATA_STRING; + data_init(str_in.length() + 1); + memcpy(data_val, str_in.c_str(), data_size); +} + +void DataElement::set(vector<string> &strvect_in) { + vector<string>::iterator i; + long vectsize; + long ptr; + + data_type = DATA_STR_VECTOR; + + vectsize = 0; + + for (i = strvect_in.begin(); i != strvect_in.end(); i++) { + vectsize += (*i).length() + 1; + } + + data_init(vectsize); + + ptr = 0; + + for (i = strvect_in.begin(); i != strvect_in.end(); i++) { + int str_length; + + str_length = (*i).length() + 1; + + memcpy(data_val + ptr, (*i).c_str(), str_length); + ptr += str_length; + } +} + +void DataElement::set(std::set<string> &strset_in) { + std::set<string>::iterator i; + vector<string> tmp_vect; + + for (i = strset_in.begin(); i != strset_in.end(); i++) { + tmp_vect.push_back(*i); + } + + set(tmp_vect); +} + +void DataElement::set(vector<int> &intvect_in) { + long ptr; + int temp_int; + + data_type = DATA_INT_VECTOR; + + data_init(sizeof(int) * intvect_in.size()); + + vector<int>::iterator i; + + ptr = 0; + + for (i = intvect_in.begin(); i != intvect_in.end(); i++) { + temp_int = *i; + memcpy(data_val + ptr, &temp_int, sizeof(int)); + ptr += sizeof(int); + } +} + +void DataElement::set(vector<long> &longvect_in) { + long ptr; + long temp_long; + + data_type = DATA_LONG_VECTOR; + + data_init(sizeof(long) * longvect_in.size()); + + vector<long>::iterator i; + + ptr = 0; + + for (i = longvect_in.begin(); i != longvect_in.end(); i++) { + temp_long = *i; + memcpy(data_val + ptr, &temp_long, sizeof(long)); + ptr += sizeof(long); + } +} + +void DataElement::set(vector<float> &floatvect_in) { + long ptr; + float temp_float; + + data_type = DATA_FLOAT_VECTOR; + + data_init(sizeof(float) * floatvect_in.size()); + + // vector<float>::iterator i; + // + // ptr = 0; + // + // for (i = floatvect_in.begin(); i != floatvect_in.end(); i++) + // { + // temp_float = *i; + // memcpy(data_val+ptr, &temp_float, sizeof(float)); + // ptr += sizeof(float); + // } + + memcpy(data_val, &floatvect_in[0], sizeof(float) * floatvect_in.size()); +} + +void DataElement::set(vector<double> &doublevect_in) { + long ptr; + double temp_double; + + data_type = DATA_DOUBLE_VECTOR; + + data_init(sizeof(double) * doublevect_in.size()); + + vector<double>::iterator i; + + ptr = 0; + + for (i = doublevect_in.begin(); i != doublevect_in.end(); i++) { + temp_double = *i; + memcpy(data_val + ptr, &temp_double, sizeof(double)); + ptr += sizeof(double); + } +} + +//void DataElement::get(bool &bool_in) throw (DataTypeMismatchException) +//{ +// if (!data_type) return; +// if (data_type != DATA_BOOL) throw(new DataTypeMismatchException("Type mismatch, not a BOOL")); +// +// memcpy(&bool_in, data_val, data_size); +//} + +void DataElement::get(char& char_in) throw (DataTypeMismatchException) { + if (!data_type) + return; +} + +void DataElement::get(unsigned char& uchar_in) throw (DataTypeMismatchException) { + if (!data_type) + return; +} + +void DataElement::get(unsigned int& uint_in) throw (DataTypeMismatchException) { + if (!data_type) + return; +} + +void DataElement::get(unsigned long & ulong_in) throw (DataTypeMismatchException) { + if (!data_type) + return; +} + +void DataElement::get(long long & long_in) throw (DataTypeMismatchException) { + if (!data_type) + return; +} + +void DataElement::get(long double& ldouble_in) throw (DataTypeMismatchException) { + if (!data_type) + return; +} + +void DataElement::get(int &int_in) throw (DataTypeMismatchException) { + if (!data_type) + return; + if (data_type != DATA_INT) + throw(new DataTypeMismatchException("Type mismatch, not a INT")); + + memcpy(&int_in, data_val, data_size); +} + +void DataElement::get(long &long_in) throw (DataTypeMismatchException) { + if (!data_type) + return; + if (data_type != DATA_LONG) + throw(new DataTypeMismatchException("Type mismatch, not a LONG")); + + memcpy(&long_in, data_val, data_size); +} + +void DataElement::get(float &float_in) throw (DataTypeMismatchException) { + if (!data_type) + return; + if (data_type != DATA_FLOAT) + throw(new DataTypeMismatchException("Type mismatch, not a FLOAT")); + + memcpy(&float_in, data_val, data_size); +} + +void DataElement::get(double &double_in) throw (DataTypeMismatchException) { + if (!data_type) + return; + if (data_type != DATA_DOUBLE) + throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE")); + + memcpy(&double_in, data_val, data_size); +} + +void DataElement::get(char **data_in) throw (DataTypeMismatchException) { + if (data_type != DATA_VOID) + throw(new DataTypeMismatchException("Type mismatch, not a CHAR*")); + *data_in = new char[data_size]; + memcpy(*data_in, data_val, data_size); +} + +void DataElement::get(string &str_in) throw (DataTypeMismatchException) { + if (!data_type) + return; + + if (data_type != DATA_STRING) + throw(new DataTypeMismatchException("Type mismatch, not a STRING")); + + if (!str_in.empty()) // flush the string + { + str_in.erase(str_in.begin(), str_in.end()); + } + + str_in.append(data_val); +} + +void DataElement::get(vector<string> &strvect_in) throw (DataTypeMismatchException) { + long ptr; + if (!data_type) + return; + + if (data_type != DATA_STR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR")); + + ptr = 0; + + while (ptr != data_size) { + strvect_in.push_back(string(data_val + ptr)); + ptr += strlen(data_val + ptr) + 1; + } + +} + +void DataElement::get(std::set<string> &strset_in) throw (DataTypeMismatchException) { + if (!data_type) + return; + + if (data_type != DATA_STR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR/SET")); + + std::vector<string> tmp_vect; + std::vector<string>::iterator i; + + get(tmp_vect); + + for (i = tmp_vect.begin(); i != tmp_vect.end(); i++) { + strset_in.insert(*i); + } +} + +void DataElement::get(vector<int> &intvect_in) throw (DataTypeMismatchException) { + long ptr; + if (!data_type) + return; + + if (data_type != DATA_INT_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + + ptr = 0; + + int temp_int; + while (ptr < data_size) { + temp_int = 0; + memcpy(&temp_int, data_val + ptr, sizeof(int)); + intvect_in.push_back(temp_int); + ptr += sizeof(int); + } +} + +void DataElement::get(vector<long> &longvect_in) throw (DataTypeMismatchException) { + long ptr; + if (!data_type) + return; + + if (data_type != DATA_LONG_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a LONG VECTOR")); + + ptr = 0; + + long temp_long; + while (ptr < data_size) { + temp_long = 0; + memcpy(&temp_long, data_val + ptr, sizeof(long)); + longvect_in.push_back(temp_long); + ptr += sizeof(long); + } +} + +void DataElement::get(vector<float> &floatvect_in) throw (DataTypeMismatchException) { + long ptr; + if (!data_type) + return; + + if (data_type != DATA_FLOAT_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a FLOAT VECTOR")); + + ptr = 0; + + float temp_float; + while (ptr < data_size) { + temp_float = 0; + memcpy(&temp_float, data_val + ptr, sizeof(float)); + floatvect_in.push_back(temp_float); + ptr += sizeof(float); + } +} + +void DataElement::get(vector<double> &doublevect_in) throw (DataTypeMismatchException) { + long ptr; + if (!data_type) + return; + + if (data_type != DATA_DOUBLE_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE VECTOR")); + + ptr = 0; + + double temp_double; + + while (ptr < data_size) { + temp_double = 0; + memcpy(&temp_double, data_val + ptr, sizeof(double)); + doublevect_in.push_back(temp_double); + ptr += sizeof(double); + } +} + +long DataElement::getSerializedSize() { + return sizeof(unsigned char) + sizeof(unsigned int) + data_size; +} + +long DataElement::getSerialized(char **ser_str) { + long ser_size = getSerializedSize(); + + *ser_str = new char[ser_size]; + + char *ser_pointer; + + ser_pointer = *ser_str; + + memcpy(ser_pointer, &data_type, sizeof(unsigned char)); + ser_pointer += sizeof(unsigned char); + memcpy(ser_pointer, &data_size, sizeof(unsigned int)); + ser_pointer += sizeof(unsigned int); + memcpy(ser_pointer, data_val, data_size); + + return ser_size; +} + +void DataElement::set(vector<char>& charvect_in) { +} + +void DataElement::set(vector<unsigned char>& ucharvect_in) { +} + +void DataElement::set(vector<unsigned int>& uintvect_in) { +} + +void DataElement::set(vector<unsigned long>& ulongvect_in) { +} + +void DataElement::set(vector<long long>& llongvect_in) { +} + +void DataElement::set(vector<long double>& ldoublevect_in) { +} + +void DataElement::get(vector<char>& charvect_in) throw (DataTypeMismatchException) { +} + +void DataElement::get(vector<unsigned char>& ucharvect_in) throw (DataTypeMismatchException) { +} + +void DataElement::get(vector<unsigned int>& uintvect_in) throw (DataTypeMismatchException) { +} + +void DataElement::get(vector<unsigned long>& ulongvect_in) throw (DataTypeMismatchException) { +} + +void DataElement::get(vector<long long>& llongvect_in) throw (DataTypeMismatchException) { +} + +void DataElement::get(vector<long double>& ldoublevect_in) throw (DataTypeMismatchException) { +} + +void DataElement::setSerialized(char *ser_str) { + char *ser_pointer = ser_str; + + memcpy(&data_type, ser_pointer, sizeof(unsigned char)); + ser_pointer += sizeof(unsigned char); + memcpy(&data_size, ser_pointer, sizeof(unsigned int)); + ser_pointer += sizeof(unsigned int); + + data_init(data_size); + memcpy(data_val, ser_pointer, data_size); +} + +/* DataNode class */ + +DataNode::DataNode() { + ptr = 0; + parentNode = NULL; +} + +DataNode::DataNode(const char *name_in) { + ptr = 0; + node_name = name_in; + parentNode = NULL; +} + +DataNode::~DataNode() { + for (vector<DataNode *>::iterator i = children.begin(); i != children.end(); i++) { + delete *i; + } +} + +void DataNode::setName(const char *name_in) { + node_name = name_in; +} + +DataElement & DataNode::element() { + return data_elem; +} + +DataNode &DataNode::newChild(const char *name_in) { + children.push_back(new DataNode(name_in)); + childmap[name_in].push_back(children.back()); + + children.back()->setParentNode(*this); + + return *children.back(); +} + +DataNode &DataNode::child(const char *name_in, int index) throw (DataInvalidChildException) { + DataNode *child_ret; + + child_ret = childmap[name_in][index]; + + if (!child_ret) { + stringstream error_str; + error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; + throw(DataInvalidChildException(error_str.str().c_str())); + } + + return *child_ret; +} + +DataNode &DataNode::child(int index) throw (DataInvalidChildException) { + + DataNode *child_ret; + + child_ret = children[index]; + + if (!child_ret) { + stringstream error_str; + error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; + throw(DataInvalidChildException(error_str.str().c_str())); + } + + return *child_ret; +} + +int DataNode::numChildren() { + return children.size(); +} + +int DataNode::numChildren(const char *name_in) { + return childmap[name_in].size(); +} + +bool DataNode::hasAnother() { + return children.size() != ptr; +} + +bool DataNode::hasAnother(const char *name_in) { + return childmap[name_in].size() != childmap_ptr[name_in]; +} + +DataNode & DataNode::getNext() throw (DataInvalidChildException) { + return child(ptr++); +} + +DataNode &DataNode::getNext(const char *name_in) throw (DataInvalidChildException) { + return child(name_in, childmap_ptr[name_in]++); +} + +void DataNode::rewind() { + ptr = 0; +} + +void DataNode::rewind(const char *name_in) { + childmap_ptr[name_in] = 0; +} + +/* DataTree class */ + +DataTree::DataTree(const char *name_in) { + dn_root.setName(name_in); +} + +DataTree::DataTree() { + +} + +DataTree::~DataTree() { +} +; + +DataNode & DataTree::rootNode() { + return dn_root; +} + +std::string trim(std::string& s, const std::string& drop = " ") { + std::string r = s.erase(s.find_last_not_of(drop) + 1); + return r.erase(0, r.find_first_not_of(drop)); +} + +void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPointPolicy fpp) { + + int tmp_char; + int tmp_int; + long tmp_long; + long long tmp_llong; + double tmp_double; + float tmp_float; + string tmp_str; + string tmp_str2; + std::stringstream tmp_stream; + std::stringstream tmp_stream2; + + vector<char> tmp_charvect; + vector<int> tmp_intvect; + vector<long> tmp_longvect; + vector<long> tmp_llongvect; + vector<long>::iterator tmp_llongvect_i; + vector<double> tmp_doublevect; + vector<double>::iterator tmp_doublevect_i; + vector<float> tmp_floatvect; + + bool vChars = false; + bool vInts = false; + bool vLongs = false; + + string in_text = src_text; + + trim(in_text); + trim(in_text, "\r\n"); + tmp_stream.str(""); + tmp_stream2.str(""); + + if (in_text.find_first_not_of("0123456789-") == string::npos) { + tmp_stream << in_text; + tmp_stream >> tmp_llong; + + tmp_int = tmp_llong; + tmp_long = tmp_llong; + + if (tmp_int == tmp_llong) { + elem->element().set((int) tmp_int); + } else if (tmp_long == tmp_llong) { + elem->element().set((long) tmp_int); + } else { + elem->element().set((long long) tmp_long); + } + } else if (in_text.find_first_not_of("0123456789.e+-") == string::npos) { + tmp_stream << in_text; + + if (fpp == USE_FLOAT) { + tmp_stream >> tmp_float; + + elem->element().set((float) tmp_float); + } else { + tmp_stream >> tmp_double; + + elem->element().set((double) tmp_double); + } + } else if (in_text.find_first_not_of("0123456789- ") == string::npos) { + tmp_stream << in_text; + + vChars = true; + vInts = true; + vLongs = true; + + while (!tmp_stream.eof()) { + tmp_stream >> tmp_llong; + tmp_char = tmp_llong; + tmp_int = tmp_llong; + tmp_long = tmp_llong; + if (tmp_char != tmp_llong) { + vChars = false; + } + if (tmp_int != tmp_llong) { + vInts = false; + } + if (tmp_long != tmp_llong) { + vLongs = false; + } + tmp_llongvect.push_back((long) tmp_long); + } + + if (vChars) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_charvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_charvect); + tmp_charvect.clear(); + + } else if (vInts) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_intvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_intvect); + tmp_intvect.clear(); + } else if (vLongs) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_longvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_longvect); + tmp_longvect.clear(); + } else { + elem->element().set(tmp_llongvect); + } + } else if (in_text.find_first_not_of("0123456789.e-+ ") == string::npos) { + tmp_stream << in_text; + + if (fpp == USE_FLOAT) { + tmp_floatvect.clear(); + } else { + tmp_doublevect.clear(); + } + + while (!tmp_stream.eof()) { + + if (fpp == USE_FLOAT) { + tmp_stream >> tmp_float; + tmp_floatvect.push_back(tmp_float); + } else { + tmp_stream >> tmp_double; + tmp_doublevect.push_back(tmp_double); + } + } + + if (fpp == USE_FLOAT) { + elem->element().set(tmp_floatvect); + } else { + elem->element().set(tmp_doublevect); + } + } else { + elem->element().set(src_text); + // printf( "Unhandled DataTree XML Field: [%s]", tmp_str.c_str() ); + } + +} + +void DataTree::setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node, DT_FloatingPointPolicy fpp) { + TiXmlText *pText; + int t = elxml->Type(); + string tmp_str; + + switch (t) { + case TiXmlNode::DOCUMENT: + // printf( "Document" ); + break; + + case TiXmlNode::ELEMENT: + if (!root_node) + elem = &elem->newChild(elxml->Value()); + + const TiXmlAttribute *attribs; + attribs = elxml->ToElement()->FirstAttribute(); + + while (attribs) { + + // following badgerfish xml->json and xml->ruby convention for attributes.. + string attrName("@"); + attrName.append(attribs->Name()); + + decodeXMLText(&elem->newChild(attrName.c_str()), attribs->Value(), fpp); + + attribs = attribs->Next(); + } + + // printf( "Element \"%s\"", elxml->Value()); + break; + + case TiXmlNode::COMMENT: + // printf( "Comment: \"%s\"", elxml->Value()); + break; + + case TiXmlNode::UNKNOWN: + // printf( "Unknown" ); + break; + + case TiXmlNode::TEXT: + pText = elxml->ToText(); + + decodeXMLText(elem, pText->Value(), fpp); + + // pText = elxml->ToText(); + // printf( "Text: [%s]", pText->Value() ); + break; + + case TiXmlNode::DECLARATION: + // printf( "Declaration" ); + break; + default: + break; + } + + // printf( "\n" ); + + TiXmlNode * pChild; + + if (!elxml->NoChildren()) { + if (elxml->FirstChild()->Type() == TiXmlNode::ELEMENT) { + if (elxml->FirstChild()->Value() == TIXML_STRING("str")) { + std::vector<std::string> tmp_strvect; + + for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { + if (pChild->Value() == TIXML_STRING("str")) { + if (!pChild->FirstChild()) { + tmp_strvect.push_back(""); + continue; + } + + pText = pChild->FirstChild()->ToText(); + + if (pText) { + tmp_str = pText->Value(); + tmp_strvect.push_back(tmp_str); + } + } + } + + elem->element().set(tmp_strvect); + + return; + } + } + } + + for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { + setFromXML(elem, pChild, false, fpp); + } + +} + +void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { + DataNode *child; + + elem->rewind(); + + while (elem->hasAnother()) { + child = &elem->getNext(); + + std::string nodeName = child->getName(); + + TiXmlElement *element; + + element = new TiXmlElement(nodeName.length() ? nodeName.c_str() : "node"); + std::string tmp; + std::stringstream tmp_stream; + TiXmlText *text; + std::vector<float> tmp_floatvect; + std::vector<float>::iterator tmp_floatvect_i; + std::vector<double> tmp_doublevect; + std::vector<double>::iterator tmp_doublevect_i; + std::vector<int> tmp_intvect; + std::vector<int>::iterator tmp_intvect_i; + std::vector<char> tmp_charvect; + std::vector<char>::iterator tmp_charvect_i; + std::vector<unsigned char> tmp_ucharvect; + std::vector<unsigned char>::iterator tmp_ucharvect_i; + std::vector<unsigned int> tmp_uintvect; + std::vector<unsigned int>::iterator tmp_uintvect_i; + std::vector<long> tmp_longvect; + std::vector<long>::iterator tmp_longvect_i; + std::vector<unsigned long> tmp_ulongvect; + std::vector<unsigned long>::iterator tmp_ulongvect_i; + std::vector<long long> tmp_llongvect; + std::vector<long long>::iterator tmp_llongvect_i; + std::vector<unsigned long long> tmp_ullongvect; + std::vector<unsigned long long>::iterator tmp_ullongvect_i; + std::vector<string> tmp_stringvect; + std::vector<string>::iterator tmp_stringvect_i; + TiXmlElement *tmp_node; + char *tmp_pstr; + double tmp_double; + long double tmp_ldouble; + float tmp_float; + char tmp_char; + unsigned char tmp_uchar; + int tmp_int; + unsigned int tmp_uint; + long tmp_long; + unsigned long tmp_ulong; + long long tmp_llong; + + switch (child->element().getDataType()) { + case DATA_NULL: + break; + case DATA_VOID: + child->element().get(&tmp_pstr); + // following badgerfish xml->json and xml->ruby convention for attributes.. + if (nodeName.substr(0, 1) == string("@")) { + elxml->SetAttribute(nodeName.substr(1).c_str(), tmp_pstr); + delete element; + element = NULL; + } else { + text = new TiXmlText(tmp_pstr); + element->LinkEndChild(text); + } + delete tmp_pstr; + break; + case DATA_CHAR: + child->element().get(tmp_char); + + tmp_stream.str(""); + + tmp_stream << tmp_char; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_UCHAR: + child->element().get(tmp_uchar); + + tmp_stream.str(""); + + tmp_stream << tmp_uchar; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_INT: + child->element().get(tmp_int); + + tmp_stream.str(""); + + tmp_stream << tmp_int; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_UINT: + child->element().get(tmp_uint); + + tmp_stream.str(""); + + tmp_stream << tmp_uint; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONG: + child->element().get(tmp_long); + + tmp_stream.str(""); + + tmp_stream << tmp_long; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_ULONG: + child->element().get(tmp_ulong); + + tmp_stream.str(""); + + tmp_stream << tmp_ulong; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONGLONG: + child->element().get(tmp_llong); + + tmp_stream.str(""); + + tmp_stream << tmp_llong; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_FLOAT: + child->element().get(tmp_float); + + tmp_stream.str(""); + + tmp_stream << tmp_float; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_DOUBLE: + child->element().get(tmp_double); + + tmp_stream.str(""); + + tmp_stream << tmp_double; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONGDOUBLE: + child->element().get(tmp_ldouble); + + tmp_stream.str(""); + + tmp_stream << tmp_ldouble; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_STRING: + child->element().get(tmp); + if (nodeName.substr(0, 1) == string("@")) { + elxml->SetAttribute(nodeName.substr(1).c_str(), tmp.c_str()); + delete element; + element = NULL; + } else { + text = new TiXmlText(tmp.c_str()); + element->LinkEndChild(text); + } + break; + + case DATA_STR_VECTOR: + child->element().get(tmp_stringvect); + + tmp_stream.str(""); + + for (tmp_stringvect_i = tmp_stringvect.begin(); tmp_stringvect_i != tmp_stringvect.end(); tmp_stringvect_i++) { + tmp_node = new TiXmlElement("str"); + text = new TiXmlText((*tmp_stringvect_i).c_str()); + tmp_node->LinkEndChild(text); + element->LinkEndChild(tmp_node); + } + + tmp_stringvect.clear(); + break; + case DATA_CHAR_VECTOR: + child->element().get(tmp_charvect); + + tmp_stream.str(""); + + for (tmp_charvect_i = tmp_charvect.begin(); tmp_charvect_i != tmp_charvect.end(); tmp_charvect_i++) { + tmp_stream << (*tmp_charvect_i); + if (tmp_charvect_i != tmp_charvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_charvect.clear(); + break; + case DATA_UCHAR_VECTOR: + child->element().get(tmp_ucharvect); + + tmp_stream.str(""); + + for (tmp_ucharvect_i = tmp_ucharvect.begin(); tmp_ucharvect_i != tmp_ucharvect.end(); tmp_ucharvect_i++) { + tmp_stream << (*tmp_ucharvect_i); + if (tmp_ucharvect_i != tmp_ucharvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_ucharvect.clear(); + break; + case DATA_INT_VECTOR: + child->element().get(tmp_intvect); + + tmp_stream.str(""); + + for (tmp_intvect_i = tmp_intvect.begin(); tmp_intvect_i != tmp_intvect.end(); tmp_intvect_i++) { + tmp_stream << (*tmp_intvect_i); + if (tmp_intvect_i != tmp_intvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_intvect.clear(); + break; + case DATA_UINT_VECTOR: + child->element().get(tmp_uintvect); + + tmp_stream.str(""); + + for (tmp_uintvect_i = tmp_uintvect.begin(); tmp_uintvect_i != tmp_uintvect.end(); tmp_uintvect_i++) { + tmp_stream << (*tmp_intvect_i); + if (tmp_uintvect_i != tmp_uintvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_uintvect.clear(); + break; + case DATA_LONG_VECTOR: + child->element().get(tmp_longvect); + + tmp_stream.str(""); + + for (tmp_longvect_i = tmp_longvect.begin(); tmp_longvect_i != tmp_longvect.end(); tmp_longvect_i++) { + tmp_stream << (*tmp_longvect_i); + if (tmp_longvect_i != tmp_longvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_longvect.clear(); + break; + case DATA_ULONG_VECTOR: + child->element().get(tmp_ulongvect); + + tmp_stream.str(""); + + for (tmp_ulongvect_i = tmp_ulongvect.begin(); tmp_ulongvect_i != tmp_ulongvect.end(); tmp_ulongvect_i++) { + tmp_stream << (*tmp_ulongvect_i); + if (tmp_ulongvect_i != tmp_ulongvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_ulongvect.clear(); + break; + case DATA_LONGLONG_VECTOR: + child->element().get(tmp_llongvect); + + tmp_stream.str(""); + + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_stream << (*tmp_llongvect_i); + if (tmp_llongvect_i != tmp_llongvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_llongvect.clear(); + break; + case DATA_FLOAT_VECTOR: + child->element().get(tmp_floatvect); + + tmp_stream.str(""); + + for (tmp_floatvect_i = tmp_floatvect.begin(); tmp_floatvect_i != tmp_floatvect.end(); tmp_floatvect_i++) { + tmp_stream << (*tmp_floatvect_i); + if (tmp_floatvect_i != tmp_floatvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_floatvect.clear(); + break; + case DATA_DOUBLE_VECTOR: + child->element().get(tmp_doublevect); + + tmp_stream.str(""); + + for (tmp_doublevect_i = tmp_doublevect.begin(); tmp_doublevect_i != tmp_doublevect.end(); tmp_doublevect_i++) { + tmp_stream << (*tmp_doublevect_i); + if (tmp_doublevect_i != tmp_doublevect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_doublevect.clear(); + break; + } + + if (element) { + elxml->LinkEndChild(element); + + if (child->numChildren()) { + nodeToXML(child, element); + } + } + } + + elem->rewind(); +} + +void DataTree::printXML() /* get serialized size + return node names header */ +{ + TiXmlDocument doc; + TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); + doc.LinkEndChild(decl); + + DataNode *root = &rootNode(); + + string rootName = root->getName(); + + TiXmlElement *element = new TiXmlElement(rootName.empty() ? "root" : rootName.c_str()); + doc.LinkEndChild(element); + + if (!root->numChildren()) + doc.Print(); + + nodeToXML(root, element); + + root->rewind(); + + doc.Print(); +} + +long DataTree::getSerializedSize(DataElement &de_node_names, bool debug) /* get serialized size + return node names header */ +{ + long total_size = 0; + + stack<DataNode *> dn_stack; + vector<string> node_names; + map<string, int, string_less> node_name_index_map; + + DataElement de_name_index; // just used for sizing purposes + DataElement de_num_children; + + de_name_index.set((int) 0); + de_num_children.set((int) 0); + + int de_name_index_size = de_name_index.getSerializedSize(); + int de_num_children_size = de_num_children.getSerializedSize(); + + dn_stack.push(&dn_root); + + while (!dn_stack.empty()) { + int name_index; + // int num_children; + + /* build the name list */ + if (dn_stack.top()->getName().empty()) { + name_index = 0; /* empty string */ + } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { + node_names.push_back(string(dn_stack.top()->getName())); + name_index = node_names.size(); + node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; + } else { + name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; + } + + /* add on the size of the name index and number of children */ + total_size += de_name_index_size; + total_size += de_num_children_size; + total_size += dn_stack.top()->element().getSerializedSize(); + + /* debug output */ + if (debug) { + for (unsigned int i = 0; i < dn_stack.size() - 1; i++) + cout << "--"; + cout << (dn_stack.top()->getName().empty() ? "NULL" : dn_stack.top()->getName()) << "(" << dn_stack.top()->element().getSerializedSize() + << ")"; + cout << " type: " << dn_stack.top()->element().getDataType() << endl; + //cout << " index: " << name_index << endl; + } + /* end debug output */ + + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } + } + } + + /* set the header for use in serialization */ + de_node_names.set(node_names); + + total_size += de_node_names.getSerializedSize(); + + return total_size; +} + +void DataNode::findAll(const char *name_in, vector<DataNode *> &node_list_out) { + stack<DataNode *> dn_stack; + + /* start at the root */ + dn_stack.push(this); + + if (string(getName()) == string(name_in)) + node_list_out.push_back(this); + + while (!dn_stack.empty()) { + while (dn_stack.top()->hasAnother(name_in)) { + node_list_out.push_back(&dn_stack.top()->getNext(name_in)); + } + + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } + } + } + +} + +long DataTree::getSerialized(char **ser_str, bool debug) { + long data_ptr = 0; + long data_size = 0; + + stack<DataNode *> dn_stack; + vector<string> node_names; + map<string, int, string_less> node_name_index_map; + + /* header of node names, grabbed from getserializedsize to avoid having to memmove() or realloc() */ + DataElement de_node_names; + + data_size = getSerializedSize(de_node_names, debug); + + *ser_str = (char *) malloc(data_size); + + char *data_out = *ser_str; + + /* name list header */ + char *de_node_names_serialized; + long de_node_names_serialized_size; + + de_node_names.getSerialized(&de_node_names_serialized); + de_node_names_serialized_size = de_node_names.getSerializedSize(); + + /* copy the header and increase the pointer */ + memcpy(data_out, de_node_names_serialized, de_node_names_serialized_size); + data_ptr += de_node_names_serialized_size; + + /* start at the root */ + dn_stack.push(&dn_root); + + while (!dn_stack.empty()) { + int name_index; + int num_children; + + DataElement de_name_index; + DataElement de_num_children; + + char *de_name_index_serialized; + char *de_num_children_serialized; + char *element_serialized; + + long de_name_index_serialized_size; + long de_num_children_serialized_size; + long element_serialized_size; + + /* build the name list */ + if (dn_stack.top()->getName().empty()) { + name_index = 0; /* empty string */ + } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { + node_names.push_back(string(dn_stack.top()->getName())); + name_index = node_names.size(); + node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; + } else { + name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; + } + + num_children = dn_stack.top()->numChildren(); + + de_name_index.set(name_index); + de_num_children.set(num_children); + + de_name_index_serialized_size = de_name_index.getSerializedSize(); + de_num_children_serialized_size = de_num_children.getSerializedSize(); + element_serialized_size = dn_stack.top()->element().getSerializedSize(); + + de_name_index.getSerialized(&de_name_index_serialized); + de_num_children.getSerialized(&de_num_children_serialized); + dn_stack.top()->element().getSerialized(&element_serialized); + + /* add on the name index and number of children */ + memcpy(data_out + data_ptr, de_name_index_serialized, de_name_index_serialized_size); + data_ptr += de_name_index_serialized_size; + + memcpy(data_out + data_ptr, de_num_children_serialized, de_num_children_serialized_size); + data_ptr += de_num_children_serialized_size; + + /* add on the data element */ + memcpy(data_out + data_ptr, element_serialized, element_serialized_size); + data_ptr += element_serialized_size; + + delete de_name_index_serialized; + delete de_num_children_serialized; + delete element_serialized; + + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } + } + } + + return data_size; +} + +void DataTree::setSerialized(char *ser_str, bool debug) { + long data_ptr = 0; + // long data_size = 0; + + stack<DataNode *> dn_stack; + stack<int> dn_childcount_stack; + vector<string> node_names; + + DataElement de_node_names; + + de_node_names.setSerialized(ser_str); + data_ptr += de_node_names.getSerializedSize(); + de_node_names.get(node_names); + + DataElement de_name_index; + DataElement de_num_children; + DataElement de_element; + + dn_stack.push(&dn_root); + dn_childcount_stack.push(0); /* root (parent null) has no siblings */ + + /* unserialization is a little less straightforward since we have to do a countdown of remaining children */ + while (!dn_stack.empty()) { + int name_index; + int num_children; + + /* pull the index of the name of this node */ + de_name_index.setSerialized(ser_str + data_ptr); + data_ptr += de_name_index.getSerializedSize(); + + /* pull the number of children this node has */ + de_num_children.setSerialized(ser_str + data_ptr); + data_ptr += de_num_children.getSerializedSize(); + + /* get values from the temp dataelements */ + de_name_index.get(name_index); + de_num_children.get(num_children); + + /* pull the node's element */ + dn_stack.top()->element().setSerialized(ser_str + data_ptr); + data_ptr += dn_stack.top()->element().getSerializedSize(); + + /* debug output */ + if (debug) { + for (unsigned int i = 0; i < dn_stack.size() - 1; i++) + cout << "--"; + cout << (name_index ? node_names[name_index - 1] : "NULL") << "(" << dn_stack.top()->element().getSerializedSize() << ")"; + cout << " index: " << name_index << endl; + } + /* end debug output */ + + /* name index >= 1 means it has a name */ + if (name_index) { + dn_stack.top()->setName(node_names[name_index - 1].c_str()); + + } else /* name is nil */ + { + dn_stack.top()->setName(""); + } + + if (num_children) /* Has children, create first child and push it to the top */ + { + dn_childcount_stack.push(num_children); /* push the child count onto the stack */ + + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ + de_name_index.get(name_index); + /* add this child onto the top of the stack */ + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); + dn_childcount_stack.top()--; /* decrement to count the new child */ + } + else /* No children, move on to the next sibling */ + { + if (dn_childcount_stack.top()) /* any siblings remaining? */ + { + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ + de_name_index.get(name_index); + + dn_stack.pop(); + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* create the next sibling and throw it on the stack */ + dn_childcount_stack.top()--; /* decrement to count the new sibling */ + } + else /* This is the last sibling, move up the stack and find the next */ + { + while (!dn_stack.empty()) /* move up the stack until we find the next sibling */ + { + if (dn_childcount_stack.top()) { + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ + de_name_index.get(name_index); + + dn_stack.pop(); + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* throw it on the stack */ + dn_childcount_stack.top()--; /* count it */ + break +; } + else + { + dn_childcount_stack.pop(); + dn_stack.pop(); /* if no more siblings found the stack will empty naturally */ + } + } + } + } + } +} + +bool DataTree::LoadFromFileXML(const std::string& filename, DT_FloatingPointPolicy fpp) { + TiXmlDocument doc(filename.c_str()); + bool loadOkay = doc.LoadFile(); + + if (!loadOkay) { + std::cout << "LoadFromFileXML[error loading]: " << filename << std::endl; + return false; + } + + TiXmlNode *xml_root_node = doc.RootElement(); + + if (!xml_root_node) { + std::cout << "LoadFromFileXML[error no root]: " << filename << std::endl; + return false; + } + + rootNode().setName(xml_root_node->ToElement()->Value()); + + setFromXML(&rootNode(), xml_root_node, true, fpp); + + return true; +} + +bool DataTree::SaveToFileXML(const std::string& filename) { + TiXmlDocument doc; + TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); + doc.LinkEndChild(decl); + + string rootName = rootNode().getName(); + + TiXmlElement *element = new TiXmlElement(rootName.empty() ? "root" : rootName.c_str()); + + doc.LinkEndChild(element); + + nodeToXML(&rootNode(), element); + + doc.SaveFile(filename.c_str()); + + return true; +} + +/* + bool DataTree::SaveToFile(const std::string& filename) + { + char *serialized; + + long dataSize = getSerialized(&serialized); + + std::ofstream fout(filename.c_str(), ios::binary); + + fout.write(serialized, dataSize); + + fout << flush; + fout.close(); + + delete serialized; + + return true; + } + + bool DataTree::LoadFromFile(const std::string& filename) + { + char *serialized; + long dataSize; + + ifstream fin(filename.c_str(), ios::binary); + + fin.seekg (0, ios::end); + dataSize = fin.tellg(); + fin.seekg (0, ios::beg); + + serialized = new char[dataSize]; + fin.read(serialized,dataSize); + + fin.close(); + + setSerialized(serialized); + + delete serialized; + + return true; + } + */ + +bool DataTree::SaveToFile(const std::string& filename, bool compress, int compress_level) { + long dataSize, compressedSize, headerSize; + char *serialized, *hdr_serialized, *compressed; + DataTree dtHeader; + + dataSize = getSerialized(&serialized); + +#if USE_FASTLZ + if (compress) { + compressed = new char[(int) ceil(dataSize * 1.5)]; + + compressedSize = fastlz_compress_level(compress_level, serialized, dataSize, compressed); + + compressed = (char *) realloc(compressed, compressedSize); + + delete serialized; + } +#else + if (compress) { + std::cout << "Can't compress, FASTLZ disabled"; + compress = false; + } +#endif + DataNode &header = dtHeader.rootNode(); + + header ^ "version" = 1.0f; + header ^ "compression" = string(compress ? "FastLZ" : "none"); + header ^ "uncompressed_size" = dataSize; + + headerSize = dtHeader.getSerialized(&hdr_serialized); + + std::ofstream fout(filename.c_str(), ios::binary); + + fout.write((char *) &headerSize, sizeof(long)); + fout.write((char *) &(compress ? compressedSize : dataSize), sizeof(long)); + + fout.write(hdr_serialized, headerSize); + fout.write(compress ? compressed : serialized, compress ? compressedSize : dataSize); + + fout << flush; + fout.close(); + + delete hdr_serialized; + + if (!compress) { + delete serialized; + } else { + delete compressed; + } + + return true; +} + +bool DataTree::LoadFromFile(const std::string& filename) { + char *compressed, *serialized, *hdr_serialized; + long dataSize, headerSize, compressedSize; + + ifstream fin(filename.c_str(), ios::binary); + + fin.read((char *) &headerSize, sizeof(long)); + fin.read((char *) &compressedSize, sizeof(long)); + + hdr_serialized = new char[headerSize]; + fin.read(hdr_serialized, headerSize); + + DataTree dtHeader; + dtHeader.setSerialized(hdr_serialized); + DataNode &header = dtHeader.rootNode(); + + string compressionType = header["compression"]; + dataSize = header["uncompressed_size"]; + + bool uncompress = false; +#if USE_FASTLZ + if (compressionType == "FastLZ") { + uncompress = true; + } + + if (uncompress) { + compressed = new char[compressedSize]; + fin.read(compressed, compressedSize); + + serialized = new char[dataSize]; + fastlz_decompress(compressed, compressedSize, serialized, dataSize); + + delete compressed; + } else { + serialized = new char[dataSize]; + fin.read(serialized, dataSize); + } +#else + if (compressionType == "FastLZ") { + std::cout << "DataTree Unable to load FastLZ compressed file -- FastLZ is disabled"; + return false; + } + + serialized = new char[dataSize]; + fin.read(serialized, dataSize); +#endif + + fin.close(); + + setSerialized(serialized); + + delete serialized; + delete hdr_serialized; + + return true; +} + diff --git a/src/util/DataTree.h b/src/util/DataTree.h new file mode 100755 index 0000000..ed1cb2d --- /dev/null +++ b/src/util/DataTree.h @@ -0,0 +1,335 @@ +#pragma once +/* + * DataElement/DataNode/DataTree -- structured serialization/deserialization system + * designed for the CoolMule project :) + * + Copyright (C) 2003 by Charles J. Cliffe + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +#define USE_FASTLZ 0 + +#include <vector> +#include <map> +#include <set> +#include <string> +#include <sstream> +#include <stack> +#include <iostream> +#include "tinyxml.h" + +#if USE_FASTLZ +#include "fastlz.h" +#endif + +using namespace std; + + +/* type defines */ +#define DATA_NULL 0 +#define DATA_CHAR 1 +#define DATA_UCHAR 2 +#define DATA_INT 3 +#define DATA_UINT 4 +#define DATA_LONG 5 +#define DATA_ULONG 6 +#define DATA_LONGLONG 7 +#define DATA_ULONGLONG 8 +#define DATA_FLOAT 9 +#define DATA_DOUBLE 10 +#define DATA_LONGDOUBLE 11 +#define DATA_STRING 12 +#define DATA_STR_VECTOR 13 +#define DATA_CHAR_VECTOR 14 +#define DATA_UCHAR_VECTOR 15 +#define DATA_INT_VECTOR 16 +#define DATA_UINT_VECTOR 17 +#define DATA_LONG_VECTOR 18 +#define DATA_ULONG_VECTOR 19 +#define DATA_LONGLONG_VECTOR 20 +#define DATA_ULONGLONG_VECTOR 21 +#define DATA_FLOAT_VECTOR 22 +#define DATA_DOUBLE_VECTOR 23 +#define DATA_LONGDOUBLE_VECTOR 24 +#define DATA_VOID 25 + + +/* map comparison function */ +struct string_less : public std::binary_function<std::string,std::string,bool> +{ + bool operator()(const std::string& a,const std::string& b) const + { + return a.compare(b) < 0; + } +}; + +/* int comparison function */ +struct int_less : public std::binary_function<int,int,bool> +{ + bool operator()(int a,int b) const + { + return a < b; + } +}; + + +/* Data Exceptions */ +class DataException +{ +private: + string reason; + +public: + DataException(const char *why) : reason(why) {} + string what() { return reason; } + operator string() { return reason; } +}; + + +class DataTypeMismatchException : public DataException +{ +public: + DataTypeMismatchException(const char *why) : DataException(why) { } +}; + + +class DataInvalidChildException : public DataException +{ +public: + DataInvalidChildException(const char *why) : DataException(why) { } +}; + + +class DataElement +{ +private: + unsigned char data_type; + unsigned int data_size; + + char *data_val; + + void data_init(long data_size_in); + +public: + DataElement(); + ~DataElement(); + + int getDataType(); + long getDataSize(); + + /* set overloads */ + // void set(const bool &bool_in); + void set(const char &char_in); + void set(const unsigned char &uchar_in); + void set(const int &int_in); + void set(const unsigned int &uint_in); + void set(const long &long_in); + void set(const unsigned long &ulong_in); + void set(const long long &llong_in); + void set(const float &float_in); + void set(const double &double_in); + void set(const long double &ldouble_in); + + void set(const char *data_in, long size_in); /* voids, file chunks anyone? */ + void set(const char *data_in); /* strings, stops at NULL, returns as string */ + + void set(const string &str_in); + + void set(vector<string> &strvect_in); + void set(std::set<string> &strset_in); + void set(vector<char> &charvect_in); + void set(vector<unsigned char> &ucharvect_in); + void set(vector<int> &intvect_in); + void set(vector<unsigned int> &uintvect_in); + void set(vector<long> &longvect_in); + void set(vector<unsigned long> &ulongvect_in); + void set(vector<long long> &llongvect_in); + void set(vector<float> &floatvect_in); + void set(vector<double> &doublevect_in); + void set(vector<long double> &ldoublevect_in); + + + /* get overloads */ + void get(char &char_in) throw (DataTypeMismatchException); + void get(unsigned char &uchar_in) throw (DataTypeMismatchException); + void get(int &int_in) throw (DataTypeMismatchException); + void get(unsigned int &uint_in) throw (DataTypeMismatchException); + void get(long &long_in) throw (DataTypeMismatchException); + void get(unsigned long &ulong_in) throw (DataTypeMismatchException); + void get(long long &long_in) throw (DataTypeMismatchException); + void get(float &float_in) throw (DataTypeMismatchException); + void get(double &double_in) throw (DataTypeMismatchException); + void get(long double &ldouble_in) throw (DataTypeMismatchException); + + void get(char **data_in) throw (DataTypeMismatchException); /* getting a void or string */ + void get(string &str_in) throw (DataTypeMismatchException); + void get(std::set<string> &strset_in) throw (DataTypeMismatchException); + + void get(vector<string> &strvect_in) throw (DataTypeMismatchException); + void get(vector<char> &charvect_in) throw (DataTypeMismatchException); + void get(vector<unsigned char> &ucharvect_in) throw (DataTypeMismatchException); + void get(vector<int> &intvect_in) throw (DataTypeMismatchException); + void get(vector<unsigned int> &uintvect_in) throw (DataTypeMismatchException); + void get(vector<long> &longvect_in) throw (DataTypeMismatchException); + void get(vector<unsigned long> &ulongvect_in) throw (DataTypeMismatchException); + void get(vector<long long> &llongvect_in) throw (DataTypeMismatchException); + void get(vector<float> &floatvect_in) throw (DataTypeMismatchException); + void get(vector<double> &doublevect_in) throw (DataTypeMismatchException); + void get(vector<long double> &ldoublevect_in) throw (DataTypeMismatchException); + + + /* special get functions, saves creating unnecessary vars */ + int getChar() throw (DataTypeMismatchException) { char i_get; get(i_get); return i_get; }; + unsigned int getUChar() throw (DataTypeMismatchException) { unsigned char i_get; get(i_get); return i_get; }; + int getInt() throw (DataTypeMismatchException) { int i_get; get(i_get); return i_get; }; + unsigned int getUInt() throw (DataTypeMismatchException) { unsigned int i_get; get(i_get); return i_get; }; + long getLong() throw (DataTypeMismatchException) { long l_get; get(l_get); return l_get; }; + unsigned long getULong() throw (DataTypeMismatchException) { unsigned long l_get; get(l_get); return l_get; }; + long getLongLong() throw (DataTypeMismatchException) { long long l_get; get(l_get); return l_get; }; + float getFloat() throw (DataTypeMismatchException) { float f_get; get(f_get); return f_get; }; + double getDouble() throw (DataTypeMismatchException) { double d_get; get(d_get); return d_get; }; + long double getLongDouble() throw (DataTypeMismatchException) { long double d_get; get(d_get); return d_get; }; + + + /* serialize functions */ + long getSerializedSize(); + long getSerialized(char **ser_str); + + void setSerialized(char *ser_str); +}; + + +class DataNode +{ +private: + DataNode *parentNode; + vector<DataNode *> children; + map<string, vector<DataNode *>, string_less> childmap; + map<string, unsigned int, string_less> childmap_ptr; + + string node_name; + DataElement data_elem; + unsigned int ptr; + + +public: + DataNode(); + DataNode(const char *name_in); + + ~DataNode(); + + void setName(const char *name_in); + string &getName() { return node_name; } + + DataNode *getParentNode() { return parentNode; }; + void setParentNode(DataNode &parentNode_in) { parentNode = &parentNode_in; }; + + int numChildren(); /* Number of children */ + int numChildren(const char *name_in); /* Number of children named 'name_in' */ + + DataElement &element(); /* DataElement at this node */ + + DataNode &newChild(const char *name_in); + DataNode &child(const char *name_in, int index = 0) throw (DataInvalidChildException); + DataNode &child(int index) throw (DataInvalidChildException); + + + bool hasAnother(const char *name_in); /* useful for while() loops in conjunction with getNext() */ + bool hasAnother(); + DataNode &getNext(const char *name_in) throw (DataInvalidChildException); /* get next of specified name */ + DataNode &getNext() throw (DataInvalidChildException); /* get next child */ + void rewind(const char *name_in); /* rewind specific */ + void rewind(); /* rewind generic */ + + void findAll(const char *name_in, vector<DataNode *> &node_list_out); + + operator string () { string s; element().get(s); return s; } + operator int () { int v; element().get(v); return v; } + operator long () { long v; element().get(v); return v; } + operator float () { float v; element().get(v); return v; } + operator double () { double v; element().get(v); return v; } + + operator vector<int> () { vector<int> v; element().get(v); return v; } + operator vector<long> () { vector<long> v; element().get(v); return v; } + operator vector<float> () { vector<float> v; element().get(v); return v; } + operator vector<double> () { vector<double> v; element().get(v); return v; } + + const string &operator= (const string &s) { element().set(s); return s; } + + int operator= (int i) { element().set(i); return i; } + long operator= (long i) { element().set(i); return i; } + float operator= (float i) { element().set(i); return i; } + double operator= (double i) { element().set(i); return i; } + + + vector<int> &operator= (vector<int> &v) { element().set(v); return v; } + vector<long> &operator= (vector<long> &v) { element().set(v); return v; } + vector<float> &operator= (vector<float> &v) { element().set(v); return v; } + vector<double> &operator= (vector<double> &v) { element().set(v); return v; } + + DataNode &operator[] (const char *name_in) { return getNext(name_in); } + DataNode &operator[] (int idx) { return child(idx); } + + bool operator() (const char *name_in) { return hasAnother(name_in); } + bool operator() () { return hasAnother(); } + + DataNode &operator ^(const char *name_in) { return newChild(name_in); } + +}; + + +typedef vector<DataNode *> DataNodeList; + +enum DT_FloatingPointPolicy { + USE_FLOAT, + USE_DOUBLE +}; + +class DataTree +{ +private: + DataNode dn_root; + +public: + DataTree(const char *name_in); + DataTree(); + ~DataTree(); + + DataNode &rootNode(); + + void nodeToXML(DataNode *elem, TiXmlElement *elxml); + void setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node=true, DT_FloatingPointPolicy fpp=USE_FLOAT); + void decodeXMLText(DataNode *elem, const char *in_text, DT_FloatingPointPolicy fpp); + + void printXML(); /* print datatree as XML */ + long getSerializedSize(DataElement &de_node_names, bool debug=false); /* get serialized size + return node names header */ + long getSerialized(char **ser_str, bool debug=false); + void setSerialized(char *ser_str, bool debug=false); + + bool LoadFromFileXML(const std::string& filename, DT_FloatingPointPolicy fpp=USE_FLOAT); + bool SaveToFileXML(const std::string& filename); + +// bool SaveToFile(const std::string& filename); +// bool LoadFromFile(const std::string& filename); + + bool SaveToFile(const std::string& filename, bool compress = true, int compress_level = 2); + bool LoadFromFile(const std::string& filename); +}; + diff --git a/src/visual/TuningCanvas.cpp b/src/visual/TuningCanvas.cpp index c7d4276..c8acc42 100644 --- a/src/visual/TuningCanvas.cpp +++ b/src/visual/TuningCanvas.cpp @@ -25,7 +25,7 @@ EVT_ENTER_WINDOW(TuningCanvas::OnMouseEnterWindow) wxEND_EVENT_TABLE() TuningCanvas::TuningCanvas(wxWindow *parent, int *attribList) : - InteractiveCanvas(parent, attribList), dragAccum(0) { +InteractiveCanvas(parent, attribList), dragAccum(0) { glContext = new TuningContext(this, &wxGetApp().GetContext(this)); } @@ -51,40 +51,46 @@ void TuningCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->DrawDemodFreqBw(0, 0, wxGetApp().getFrequency()); } + if (mouseTracker.mouseDown()) { + glContext->Draw(0.2, 0.2, 0.9, 0.6, mouseTracker.getOriginMouseX(), mouseTracker.getMouseX()); + } + glContext->DrawEnd(); SwapBuffers(); } void TuningCanvas::OnIdle(wxIdleEvent &event) { + if (mouseTracker.mouseDown()) { + DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); + + dragAccum += mouseTracker.getMouseX() - mouseTracker.getOriginMouseX(); + + if (uxDown > 0.275) { + wxGetApp().setFrequency(wxGetApp().getFrequency() + (int) (mouseTracker.getOriginDeltaMouseX() * SRATE * 15.0)); + } + + if (abs(dragAccum * 10.0) >= 1) { + if (uxDown < -0.275 && activeDemod != NULL) { + activeDemod->setFrequency(activeDemod->getFrequency() + (int) (dragAccum * 10.0)); + } else if (activeDemod != NULL) { + activeDemod->setBandwidth(activeDemod->getBandwidth() + (int) (dragAccum * 10.0)); + } + + while (dragAccum * 10.0 >= 1.0) { + dragAccum -= 1.0 / 10.0; + } + while (dragAccum * -10.0 <= -1.0) { + dragAccum += 1.0 / 10.0; + } + } + } + Refresh(false); } void TuningCanvas::OnMouseMoved(wxMouseEvent& event) { InteractiveCanvas::OnMouseMoved(event); - - if (mouseTracker.mouseDown()) { - DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); - - float uxPos = 2.0 * (mouseTracker.getMouseX() - 0.5); - - dragAccum += mouseTracker.getDeltaMouseX(); - - if (uxPos < -0.275 && activeDemod != NULL) { - if (abs(dragAccum * 100.0) >= 1) { - activeDemod->setFrequency(activeDemod->getFrequency() + (int) (dragAccum * 100.0)); - dragAccum = 0; - } - } else if (uxPos > 0.275) { - wxGetApp().setFrequency(wxGetApp().getFrequency() + (int) (mouseTracker.getDeltaMouseX() * SRATE * 100.0)); - dragAccum = 0; - } else if (activeDemod != NULL) { - if (abs(dragAccum * 100.0) >= 1) { - activeDemod->setBandwidth(activeDemod->getBandwidth() + (int) (dragAccum * 100.0)); - dragAccum = 0; - } - } - } } void TuningCanvas::OnMouseDown(wxMouseEvent& event) { @@ -92,8 +98,10 @@ void TuningCanvas::OnMouseDown(wxMouseEvent& event) { mouseTracker.setHorizDragLock(true); mouseTracker.setVertDragLock(true); + uxDown = 2.0 * (mouseTracker.getMouseX() - 0.5); + dragAccum = 0; - SetCursor(wxCURSOR_IBEAM); + SetCursor (wxCURSOR_IBEAM); } void TuningCanvas::OnMouseWheelMoved(wxMouseEvent& event) { @@ -104,17 +112,17 @@ void TuningCanvas::OnMouseReleased(wxMouseEvent& event) { InteractiveCanvas::OnMouseReleased(event); mouseTracker.setHorizDragLock(false); mouseTracker.setVertDragLock(false); - SetCursor(wxCURSOR_SIZEWE); + SetCursor (wxCURSOR_SIZEWE); } void TuningCanvas::OnMouseLeftWindow(wxMouseEvent& event) { InteractiveCanvas::OnMouseLeftWindow(event); - SetCursor(wxCURSOR_CROSS); + SetCursor (wxCURSOR_CROSS); } void TuningCanvas::OnMouseEnterWindow(wxMouseEvent& event) { InteractiveCanvas::mouseTracker.OnMouseEnterWindow(event); - SetCursor(wxCURSOR_SIZEWE); + SetCursor (wxCURSOR_SIZEWE); } void TuningCanvas::setHelpTip(std::string tip) { diff --git a/src/visual/TuningCanvas.h b/src/visual/TuningCanvas.h index 13c7de2..1bd23ee 100644 --- a/src/visual/TuningCanvas.h +++ b/src/visual/TuningCanvas.h @@ -35,6 +35,7 @@ private: std::string helpTip; float dragAccum; + float uxDown; // wxDECLARE_EVENT_TABLE(); }; diff --git a/src/visual/TuningContext.cpp b/src/visual/TuningContext.cpp index 85446a1..a51f2cb 100644 --- a/src/visual/TuningContext.cpp +++ b/src/visual/TuningContext.cpp @@ -34,15 +34,15 @@ void TuningContext::DrawBegin() { glDisable(GL_TEXTURE_2D); } -void TuningContext::Draw(float r, float g, float b, float a, float level) { +void TuningContext::Draw(float r, float g, float b, float a, float p1, float p2) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glColor4f(r, g, b, a); glBegin(GL_QUADS); - glVertex2f(1.0, -1.0 + 2.0 * level); - glVertex2f(-1.0, -1.0 + 2.0 * level); - glVertex2f(-1.0, -1.0); - glVertex2f(1.0, -1.0); + glVertex2f(-1.0+p2*2.0, 1.0); + glVertex2f(-1.0+p1*2.0, 1.0); + glVertex2f(-1.0+p1*2.0, -1.0); + glVertex2f(-1.0+p2*2.0, -1.0); glEnd(); glDisable(GL_BLEND); } @@ -69,6 +69,8 @@ void TuningContext::DrawDemodFreqBw(long long freq, unsigned int bw, long long c fontHeight = 12; } + glColor3f(0.85, 0.85, 0.85); + getFont(fontSize).drawString("Freq: ", -0.75, 0, fontHeight, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); if (bw) { freqStr.str(""); @@ -78,11 +80,6 @@ void TuningContext::DrawDemodFreqBw(long long freq, unsigned int bw, long long c } getFont(fontSize).drawString(freqStr.str(), -0.75, 0, fontHeight, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER); - glColor3f(0.65, 0.65, 0.65); - glBegin(GL_LINES); - glVertex2f(-0.275, -1.0); - glVertex2f(-0.275, 1.0); - glEnd(); getFont(fontSize).drawString("BW: ", -0.10, 0, fontHeight, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); if (bw) { @@ -93,11 +90,6 @@ void TuningContext::DrawDemodFreqBw(long long freq, unsigned int bw, long long c } getFont(fontSize).drawString(freqStr.str(), -0.10, 0, fontHeight, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER); - glColor3f(0.65, 0.65, 0.65); - glBegin(GL_LINES); - glVertex2f(0.275, -1.0); - glVertex2f(0.275, 1.0); - glEnd(); getFont(fontSize).drawString("CTR: ", 0.50, 0, fontHeight, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); if (center) { @@ -107,5 +99,15 @@ void TuningContext::DrawDemodFreqBw(long long freq, unsigned int bw, long long c freqStr.str("---"); } getFont(fontSize).drawString(freqStr.str(), 0.50, 0, fontHeight, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER); + + + glColor3f(0.65, 0.65, 0.65); + glBegin(GL_LINES); + glVertex2f(-0.275, -1.0); + glVertex2f(-0.275, 1.0); + glVertex2f(0.275, -1.0); + glVertex2f(0.275, 1.0); + glEnd(); + } diff --git a/src/visual/TuningContext.h b/src/visual/TuningContext.h index a1c1316..f64a351 100644 --- a/src/visual/TuningContext.h +++ b/src/visual/TuningContext.h @@ -12,7 +12,7 @@ public: TuningContext(TuningCanvas *canvas, wxGLContext *sharedContext); void DrawBegin(); - void Draw(float r, float g, float b, float a, float level); + void Draw(float r, float g, float b, float a, float p1, float p2); void DrawDemodFreqBw(long long freq, unsigned int bw, long long center); void DrawEnd(); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 39a3659..8a2d3a9 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -30,6 +30,7 @@ EVT_RIGHT_DOWN(WaterfallCanvas::OnMouseRightDown) EVT_RIGHT_UP(WaterfallCanvas::OnMouseRightReleased) EVT_LEAVE_WINDOW(WaterfallCanvas::OnMouseLeftWindow) EVT_ENTER_WINDOW(WaterfallCanvas::OnMouseEnterWindow) +EVT_MOUSEWHEEL(WaterfallCanvas::OnMouseWheelMoved) wxEND_EVENT_TABLE() WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : @@ -302,6 +303,9 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { if (mouseZoom != 1) { currentZoom = mouseZoom; mouseZoom = mouseZoom + (1.0 - mouseZoom) * 0.2; + if (fabs(mouseZoom-1.0)<0.01) { + mouseZoom = 1; + } } long long bw; @@ -674,6 +678,9 @@ void WaterfallCanvas::OnMouseDown(wxMouseEvent& event) { void WaterfallCanvas::OnMouseWheelMoved(wxMouseEvent& event) { InteractiveCanvas::OnMouseWheelMoved(event); + float movement = (float)event.GetWheelRotation() / (float)event.GetLinesPerAction(); + + mouseZoom = 1.0f - movement/100.0f; } void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { From aa13aa2e16bd5862570422a27978d1cc4f40d763 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Wed, 7 Jan 2015 21:25:35 -0500 Subject: [PATCH 02/11] Mousewheel fix for non-OSX, AM reset tweak --- src/demod/DemodulatorThread.cpp | 11 ++++++++--- src/visual/TuningCanvas.cpp | 2 -- src/visual/WaterfallCanvas.cpp | 4 ++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 8bcee24..e67a7b8 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -113,9 +113,9 @@ void DemodulatorThread::threadMain() { audioResampler = inp->audioResampler; stereoResampler = inp->stereoResampler; - ampmodem_reset(demodAM_USB); - ampmodem_reset(demodAM_LSB); - ampmodem_reset(demodAM_DSB_CSP); + if (demodAM) { + ampmodem_reset(demodAM); + } freqdem_reset(demodFM); } @@ -352,18 +352,23 @@ void DemodulatorThread::threadMain() { if (newDemodType != DEMOD_TYPE_NULL) { switch (newDemodType) { case DEMOD_TYPE_FM: + freqdem_reset(demodFM); break; case DEMOD_TYPE_LSB: demodAM = demodAM_USB; + ampmodem_reset(demodAM); break; case DEMOD_TYPE_USB: demodAM = demodAM_LSB; + ampmodem_reset(demodAM); break; case DEMOD_TYPE_DSB: demodAM = demodAM_DSB; + ampmodem_reset(demodAM); break; case DEMOD_TYPE_AM: demodAM = demodAM_DSB_CSP; + ampmodem_reset(demodAM); break; } demodulatorType = newDemodType; diff --git a/src/visual/TuningCanvas.cpp b/src/visual/TuningCanvas.cpp index c8acc42..eec0293 100644 --- a/src/visual/TuningCanvas.cpp +++ b/src/visual/TuningCanvas.cpp @@ -95,7 +95,6 @@ void TuningCanvas::OnMouseMoved(wxMouseEvent& event) { void TuningCanvas::OnMouseDown(wxMouseEvent& event) { InteractiveCanvas::OnMouseDown(event); - mouseTracker.setHorizDragLock(true); mouseTracker.setVertDragLock(true); uxDown = 2.0 * (mouseTracker.getMouseX() - 0.5); @@ -110,7 +109,6 @@ void TuningCanvas::OnMouseWheelMoved(wxMouseEvent& event) { void TuningCanvas::OnMouseReleased(wxMouseEvent& event) { InteractiveCanvas::OnMouseReleased(event); - mouseTracker.setHorizDragLock(false); mouseTracker.setVertDragLock(false); SetCursor (wxCURSOR_SIZEWE); } diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 8a2d3a9..9a502db 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -680,7 +680,11 @@ void WaterfallCanvas::OnMouseWheelMoved(wxMouseEvent& event) { InteractiveCanvas::OnMouseWheelMoved(event); float movement = (float)event.GetWheelRotation() / (float)event.GetLinesPerAction(); +#ifdef __APPLE__ mouseZoom = 1.0f - movement/100.0f; +#else + mouseZoom = 1.0f - movement/1000.0f; +#endif } void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { From cf2b11f49680a089f966b9891e88719a02369ae1 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Thu, 8 Jan 2015 18:33:37 -0500 Subject: [PATCH 03/11] DataTree refactoring / 64-bit expansion --- src/util/DataTree.cpp | 2348 ++++++++++++++++++++++------------------- 1 file changed, 1291 insertions(+), 1057 deletions(-) diff --git a/src/util/DataTree.cpp b/src/util/DataTree.cpp index c8c5f16..11adcde 100755 --- a/src/util/DataTree.cpp +++ b/src/util/DataTree.cpp @@ -31,6 +31,8 @@ using namespace std; +#define STRINGIFY(A) #A + DataElement::DataElement() { data_type = DATA_NULL; data_val = NULL; @@ -180,6 +182,120 @@ void DataElement::set(std::set<string> &strset_in) { set(tmp_vect); } +void DataElement::set(vector<char>& charvect_in) { + long ptr; + char temp_char; + + data_type = DATA_CHAR_VECTOR; + + data_init(sizeof(char) * charvect_in.size()); + + vector<char>::iterator i; + + ptr = 0; + + for (i = charvect_in.begin(); i != charvect_in.end(); i++) { + temp_char = *i; + memcpy(data_val + ptr, &temp_char, sizeof(char)); + ptr += sizeof(char); + } +} + +void DataElement::set(vector<unsigned char>& ucharvect_in) { + long ptr; + unsigned char temp_uchar; + + data_type = DATA_UCHAR_VECTOR; + + data_init(sizeof(unsigned char) * ucharvect_in.size()); + + vector<unsigned char>::iterator i; + + ptr = 0; + + for (i = ucharvect_in.begin(); i != ucharvect_in.end(); i++) { + temp_uchar = *i; + memcpy(data_val + ptr, &temp_uchar, sizeof(unsigned char)); + ptr += sizeof(unsigned char); + } +} + +void DataElement::set(vector<unsigned int>& uintvect_in) { + long ptr; + unsigned int temp_uint; + + data_type = DATA_UCHAR_VECTOR; + + data_init(sizeof(unsigned int) * uintvect_in.size()); + + vector<unsigned int>::iterator i; + + ptr = 0; + + for (i = uintvect_in.begin(); i != uintvect_in.end(); i++) { + temp_uint = *i; + memcpy(data_val + ptr, &temp_uint, sizeof(unsigned int)); + ptr += sizeof(unsigned int); + } +} + +void DataElement::set(vector<unsigned long>& ulongvect_in) { + long ptr; + unsigned long temp_ulong; + + data_type = DATA_ULONG_VECTOR; + + data_init(sizeof(unsigned long) * ulongvect_in.size()); + + vector<unsigned long>::iterator i; + + ptr = 0; + + for (i = ulongvect_in.begin(); i != ulongvect_in.end(); i++) { + temp_ulong = *i; + memcpy(data_val + ptr, &temp_ulong, sizeof(unsigned long)); + ptr += sizeof(unsigned long); + } +} + +void DataElement::set(vector<long long>& llongvect_in) { + long ptr; + long long temp_llong; + + data_type = DATA_CHAR_VECTOR; + + data_init(sizeof(long long) * llongvect_in.size()); + + vector<long long>::iterator i; + + ptr = 0; + + for (i = llongvect_in.begin(); i != llongvect_in.end(); i++) { + temp_llong = *i; + memcpy(data_val + ptr, &temp_llong, sizeof(long long)); + ptr += sizeof(long long); + } +} + +void DataElement::set(vector<long double>& ldoublevect_in) { + long ptr; + long double temp_ldouble; + + data_type = DATA_CHAR_VECTOR; + + data_init(sizeof(long double) * ldoublevect_in.size()); + + vector<long double>::iterator i; + + ptr = 0; + + for (i = ldoublevect_in.begin(); i != ldoublevect_in.end(); i++) { + temp_ldouble = *i; + memcpy(data_val + ptr, &temp_ldouble, sizeof(long double)); + ptr += sizeof(long double); + } +} + void DataElement::set(vector<int> &intvect_in) { long ptr; int temp_int; @@ -259,384 +375,502 @@ void DataElement::set(vector<double> &doublevect_in) { } } -//void DataElement::get(bool &bool_in) throw (DataTypeMismatchException) -//{ -// if (!data_type) return; -// if (data_type != DATA_BOOL) throw(new DataTypeMismatchException("Type mismatch, not a BOOL")); +#define DataElementGetNumericDef(enumtype, datatype) void DataElement::get(datatype& val_out) throw (DataTypeMismatchException) { \ +if (!data_type) \ +return; \ + if (data_type != enumtype) { \ + if (sizeof(datatype) < data_size) { \ + std::cout << "Warning, data type mismatch requested size for '" << #datatype << "(" << sizeof(datatype) << ")' < data size '" << data_size << "'; possible loss of data."; \ + } \ + memset(&val_out, 0, sizeof(datatype)); \ + memcpy(&val_out, data_val, (sizeof(datatype) < data_size) ? sizeof(datatype) : data_size); \ + } \ + memcpy(&val_out, data_val, data_size); \ +} + +DataElementGetNumericDef(DATA_CHAR, char) +DataElementGetNumericDef(DATA_UCHAR, unsigned char) +DataElementGetNumericDef(DATA_UINT, unsigned int) +DataElementGetNumericDef(DATA_ULONG, unsigned long) +DataElementGetNumericDef(DATA_LONGLONG, long long) +DataElementGetNumericDef(DATA_LONGDOUBLE, long double) +DataElementGetNumericDef(DATA_INT, int) +DataElementGetNumericDef(DATA_LONG, long) +DataElementGetNumericDef(DATA_FLOAT, float) +DataElementGetNumericDef(DATA_DOUBLE, double) + +////void DataElement::get(char& char_in) throw (DataTypeMismatchException) { +////if (!data_type) +//// return; +////if (data_type != DATA_CHAR) +//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); +//// +////memcpy(&char_in, data_val, data_size); +////} // -// memcpy(&bool_in, data_val, data_size); +////void DataElement::get(unsigned char& uchar_in) throw (DataTypeMismatchException) { +////if (!data_type) +//// return; +////if (data_type != DATA_UCHAR) +//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); +//// +////memcpy(&uchar_in, data_val, data_size); +////} +// +////void DataElement::get(unsigned int& uint_in) throw (DataTypeMismatchException) { +////if (!data_type) +//// return; +////if (data_type != DATA_UINT) +//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); +//// +////memcpy(&uint_in, data_val, data_size); +////} +// +////void DataElement::get(unsigned long & ulong_in) throw (DataTypeMismatchException) { +////if (!data_type) +//// return; +////if (data_type != DATA_ULONG) +//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); +//// +////memcpy(&ulong_in, data_val, data_size); +////} +// +////void DataElement::get(long long & long_in) throw (DataTypeMismatchException) { +////if (!data_type) +//// return; +////if (data_type != DATA_LONG) +//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); +//// +////memcpy(&long_in, data_val, data_size); +////} +// +////void DataElement::get(long double& ldouble_in) throw (DataTypeMismatchException) { +////if (!data_type) +//// return; +////if (data_type != DATA_LONGDOUBLE) +//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); +//// +////memcpy(&ldouble_in, data_val, data_size); +////} +// +//void DataElement::get(int &int_in) throw (DataTypeMismatchException) { +//if (!data_type) +// return; +//if (data_type != DATA_INT) +// throw(new DataTypeMismatchException("Type mismatch, not a INT")); +// +//memcpy(&int_in, data_val, data_size); +//} +// +//void DataElement::get(long &long_in) throw (DataTypeMismatchException) { +//if (!data_type) +// return; +//if (data_type != DATA_LONG) +// throw(new DataTypeMismatchException("Type mismatch, not a LONG")); +// +//memcpy(&long_in, data_val, data_size); +//} +// +//void DataElement::get(float &float_in) throw (DataTypeMismatchException) { +//if (!data_type) +// return; +//if (data_type != DATA_FLOAT) +// throw(new DataTypeMismatchException("Type mismatch, not a FLOAT")); +// +//memcpy(&float_in, data_val, data_size); +//} +// +//void DataElement::get(double &double_in) throw (DataTypeMismatchException) { +//if (!data_type) +// return; +//if (data_type != DATA_DOUBLE) +// throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE")); +// +//memcpy(&double_in, data_val, data_size); //} -void DataElement::get(char& char_in) throw (DataTypeMismatchException) { - if (!data_type) - return; -} - -void DataElement::get(unsigned char& uchar_in) throw (DataTypeMismatchException) { - if (!data_type) - return; -} - -void DataElement::get(unsigned int& uint_in) throw (DataTypeMismatchException) { - if (!data_type) - return; -} - -void DataElement::get(unsigned long & ulong_in) throw (DataTypeMismatchException) { - if (!data_type) - return; -} - -void DataElement::get(long long & long_in) throw (DataTypeMismatchException) { - if (!data_type) - return; -} - -void DataElement::get(long double& ldouble_in) throw (DataTypeMismatchException) { - if (!data_type) - return; -} - -void DataElement::get(int &int_in) throw (DataTypeMismatchException) { - if (!data_type) - return; - if (data_type != DATA_INT) - throw(new DataTypeMismatchException("Type mismatch, not a INT")); - - memcpy(&int_in, data_val, data_size); -} - -void DataElement::get(long &long_in) throw (DataTypeMismatchException) { - if (!data_type) - return; - if (data_type != DATA_LONG) - throw(new DataTypeMismatchException("Type mismatch, not a LONG")); - - memcpy(&long_in, data_val, data_size); -} - -void DataElement::get(float &float_in) throw (DataTypeMismatchException) { - if (!data_type) - return; - if (data_type != DATA_FLOAT) - throw(new DataTypeMismatchException("Type mismatch, not a FLOAT")); - - memcpy(&float_in, data_val, data_size); -} - -void DataElement::get(double &double_in) throw (DataTypeMismatchException) { - if (!data_type) - return; - if (data_type != DATA_DOUBLE) - throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE")); - - memcpy(&double_in, data_val, data_size); -} - void DataElement::get(char **data_in) throw (DataTypeMismatchException) { - if (data_type != DATA_VOID) - throw(new DataTypeMismatchException("Type mismatch, not a CHAR*")); - *data_in = new char[data_size]; - memcpy(*data_in, data_val, data_size); +if (data_type != DATA_VOID) + throw(new DataTypeMismatchException("Type mismatch, not a CHAR*")); +*data_in = new char[data_size]; +memcpy(*data_in, data_val, data_size); } void DataElement::get(string &str_in) throw (DataTypeMismatchException) { - if (!data_type) - return; +if (!data_type) + return; - if (data_type != DATA_STRING) - throw(new DataTypeMismatchException("Type mismatch, not a STRING")); +if (data_type != DATA_STRING) + throw(new DataTypeMismatchException("Type mismatch, not a STRING")); - if (!str_in.empty()) // flush the string - { - str_in.erase(str_in.begin(), str_in.end()); - } +if (!str_in.empty()) // flush the string +{ + str_in.erase(str_in.begin(), str_in.end()); +} - str_in.append(data_val); +str_in.append(data_val); } void DataElement::get(vector<string> &strvect_in) throw (DataTypeMismatchException) { - long ptr; - if (!data_type) - return; +long ptr; +if (!data_type) + return; - if (data_type != DATA_STR_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR")); +if (data_type != DATA_STR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR")); - ptr = 0; +ptr = 0; - while (ptr != data_size) { - strvect_in.push_back(string(data_val + ptr)); - ptr += strlen(data_val + ptr) + 1; - } +while (ptr != data_size) { + strvect_in.push_back(string(data_val + ptr)); + ptr += strlen(data_val + ptr) + 1; +} } void DataElement::get(std::set<string> &strset_in) throw (DataTypeMismatchException) { - if (!data_type) - return; +if (!data_type) + return; - if (data_type != DATA_STR_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR/SET")); +if (data_type != DATA_STR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR/SET")); - std::vector<string> tmp_vect; - std::vector<string>::iterator i; +std::vector<string> tmp_vect; +std::vector<string>::iterator i; - get(tmp_vect); +get(tmp_vect); - for (i = tmp_vect.begin(); i != tmp_vect.end(); i++) { - strset_in.insert(*i); - } +for (i = tmp_vect.begin(); i != tmp_vect.end(); i++) { + strset_in.insert(*i); } - -void DataElement::get(vector<int> &intvect_in) throw (DataTypeMismatchException) { - long ptr; - if (!data_type) - return; - - if (data_type != DATA_INT_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - - ptr = 0; - - int temp_int; - while (ptr < data_size) { - temp_int = 0; - memcpy(&temp_int, data_val + ptr, sizeof(int)); - intvect_in.push_back(temp_int); - ptr += sizeof(int); - } -} - -void DataElement::get(vector<long> &longvect_in) throw (DataTypeMismatchException) { - long ptr; - if (!data_type) - return; - - if (data_type != DATA_LONG_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a LONG VECTOR")); - - ptr = 0; - - long temp_long; - while (ptr < data_size) { - temp_long = 0; - memcpy(&temp_long, data_val + ptr, sizeof(long)); - longvect_in.push_back(temp_long); - ptr += sizeof(long); - } -} - -void DataElement::get(vector<float> &floatvect_in) throw (DataTypeMismatchException) { - long ptr; - if (!data_type) - return; - - if (data_type != DATA_FLOAT_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a FLOAT VECTOR")); - - ptr = 0; - - float temp_float; - while (ptr < data_size) { - temp_float = 0; - memcpy(&temp_float, data_val + ptr, sizeof(float)); - floatvect_in.push_back(temp_float); - ptr += sizeof(float); - } -} - -void DataElement::get(vector<double> &doublevect_in) throw (DataTypeMismatchException) { - long ptr; - if (!data_type) - return; - - if (data_type != DATA_DOUBLE_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE VECTOR")); - - ptr = 0; - - double temp_double; - - while (ptr < data_size) { - temp_double = 0; - memcpy(&temp_double, data_val + ptr, sizeof(double)); - doublevect_in.push_back(temp_double); - ptr += sizeof(double); - } -} - -long DataElement::getSerializedSize() { - return sizeof(unsigned char) + sizeof(unsigned int) + data_size; -} - -long DataElement::getSerialized(char **ser_str) { - long ser_size = getSerializedSize(); - - *ser_str = new char[ser_size]; - - char *ser_pointer; - - ser_pointer = *ser_str; - - memcpy(ser_pointer, &data_type, sizeof(unsigned char)); - ser_pointer += sizeof(unsigned char); - memcpy(ser_pointer, &data_size, sizeof(unsigned int)); - ser_pointer += sizeof(unsigned int); - memcpy(ser_pointer, data_val, data_size); - - return ser_size; -} - -void DataElement::set(vector<char>& charvect_in) { -} - -void DataElement::set(vector<unsigned char>& ucharvect_in) { -} - -void DataElement::set(vector<unsigned int>& uintvect_in) { -} - -void DataElement::set(vector<unsigned long>& ulongvect_in) { -} - -void DataElement::set(vector<long long>& llongvect_in) { -} - -void DataElement::set(vector<long double>& ldoublevect_in) { } void DataElement::get(vector<char>& charvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_CHAR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + +ptr = 0; + +char temp_char; +while (ptr < data_size) { + temp_char = 0; + memcpy(&temp_char, data_val + ptr, sizeof(char)); + charvect_in.push_back(temp_char); + ptr += sizeof(char); +} } void DataElement::get(vector<unsigned char>& ucharvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_UCHAR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + +ptr = 0; + +unsigned char temp_char; +while (ptr < data_size) { + temp_char = 0; + memcpy(&temp_char, data_val + ptr, sizeof(unsigned char)); + ucharvect_in.push_back(temp_char); + ptr += sizeof(unsigned char); +} } void DataElement::get(vector<unsigned int>& uintvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_UINT_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + +ptr = 0; + +unsigned int temp_char; +while (ptr < data_size) { + temp_char = 0; + memcpy(&temp_char, data_val + ptr, sizeof(unsigned int)); + uintvect_in.push_back(temp_char); + ptr += sizeof(unsigned int); +} } void DataElement::get(vector<unsigned long>& ulongvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_ULONG_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + +ptr = 0; + +unsigned long temp_char; +while (ptr < data_size) { + temp_char = 0; + memcpy(&temp_char, data_val + ptr, sizeof(unsigned long)); + ulongvect_in.push_back(temp_char); + ptr += sizeof(unsigned long); +} } void DataElement::get(vector<long long>& llongvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_LONGLONG_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + +ptr = 0; + +long long temp_char; +while (ptr < data_size) { + temp_char = 0; + memcpy(&temp_char, data_val + ptr, sizeof(long long)); + llongvect_in.push_back(temp_char); + ptr += sizeof(long long); +} } void DataElement::get(vector<long double>& ldoublevect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_LONGDOUBLE_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + +ptr = 0; + +long double temp_char; +while (ptr < data_size) { + temp_char = 0; + memcpy(&temp_char, data_val + ptr, sizeof(long double)); + ldoublevect_in.push_back(temp_char); + ptr += sizeof(long double); +} +} + +void DataElement::get(vector<int> &intvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_INT_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); + +ptr = 0; + +int temp_int; +while (ptr < data_size) { + temp_int = 0; + memcpy(&temp_int, data_val + ptr, sizeof(int)); + intvect_in.push_back(temp_int); + ptr += sizeof(int); +} +} + +void DataElement::get(vector<long> &longvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_LONG_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a LONG VECTOR")); + +ptr = 0; + +long temp_long; +while (ptr < data_size) { + temp_long = 0; + memcpy(&temp_long, data_val + ptr, sizeof(long)); + longvect_in.push_back(temp_long); + ptr += sizeof(long); +} +} + +void DataElement::get(vector<float> &floatvect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_FLOAT_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a FLOAT VECTOR")); + +ptr = 0; + +float temp_float; +while (ptr < data_size) { + temp_float = 0; + memcpy(&temp_float, data_val + ptr, sizeof(float)); + floatvect_in.push_back(temp_float); + ptr += sizeof(float); +} +} + +void DataElement::get(vector<double> &doublevect_in) throw (DataTypeMismatchException) { +long ptr; +if (!data_type) + return; + +if (data_type != DATA_DOUBLE_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE VECTOR")); + +ptr = 0; + +double temp_double; + +while (ptr < data_size) { + temp_double = 0; + memcpy(&temp_double, data_val + ptr, sizeof(double)); + doublevect_in.push_back(temp_double); + ptr += sizeof(double); +} +} + +long DataElement::getSerializedSize() { +return sizeof(unsigned char) + sizeof(unsigned int) + data_size; +} + +long DataElement::getSerialized(char **ser_str) { +long ser_size = getSerializedSize(); + +*ser_str = new char[ser_size]; + +char *ser_pointer; + +ser_pointer = *ser_str; + +memcpy(ser_pointer, &data_type, sizeof(unsigned char)); +ser_pointer += sizeof(unsigned char); +memcpy(ser_pointer, &data_size, sizeof(unsigned int)); +ser_pointer += sizeof(unsigned int); +memcpy(ser_pointer, data_val, data_size); + +return ser_size; } void DataElement::setSerialized(char *ser_str) { - char *ser_pointer = ser_str; +char *ser_pointer = ser_str; - memcpy(&data_type, ser_pointer, sizeof(unsigned char)); - ser_pointer += sizeof(unsigned char); - memcpy(&data_size, ser_pointer, sizeof(unsigned int)); - ser_pointer += sizeof(unsigned int); +memcpy(&data_type, ser_pointer, sizeof(unsigned char)); +ser_pointer += sizeof(unsigned char); +memcpy(&data_size, ser_pointer, sizeof(unsigned int)); +ser_pointer += sizeof(unsigned int); - data_init(data_size); - memcpy(data_val, ser_pointer, data_size); +data_init(data_size); +memcpy(data_val, ser_pointer, data_size); } /* DataNode class */ DataNode::DataNode() { - ptr = 0; - parentNode = NULL; +ptr = 0; +parentNode = NULL; } DataNode::DataNode(const char *name_in) { - ptr = 0; - node_name = name_in; - parentNode = NULL; +ptr = 0; +node_name = name_in; +parentNode = NULL; } DataNode::~DataNode() { - for (vector<DataNode *>::iterator i = children.begin(); i != children.end(); i++) { - delete *i; - } +for (vector<DataNode *>::iterator i = children.begin(); i != children.end(); i++) { + delete *i; +} } void DataNode::setName(const char *name_in) { - node_name = name_in; +node_name = name_in; } DataElement & DataNode::element() { - return data_elem; +return data_elem; } DataNode &DataNode::newChild(const char *name_in) { - children.push_back(new DataNode(name_in)); - childmap[name_in].push_back(children.back()); +children.push_back(new DataNode(name_in)); +childmap[name_in].push_back(children.back()); - children.back()->setParentNode(*this); +children.back()->setParentNode(*this); - return *children.back(); +return *children.back(); } DataNode &DataNode::child(const char *name_in, int index) throw (DataInvalidChildException) { - DataNode *child_ret; +DataNode *child_ret; - child_ret = childmap[name_in][index]; +child_ret = childmap[name_in][index]; - if (!child_ret) { - stringstream error_str; - error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; - throw(DataInvalidChildException(error_str.str().c_str())); - } +if (!child_ret) { + stringstream error_str; + error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; + throw(DataInvalidChildException(error_str.str().c_str())); +} - return *child_ret; +return *child_ret; } DataNode &DataNode::child(int index) throw (DataInvalidChildException) { - DataNode *child_ret; +DataNode *child_ret; - child_ret = children[index]; +child_ret = children[index]; - if (!child_ret) { - stringstream error_str; - error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; - throw(DataInvalidChildException(error_str.str().c_str())); - } +if (!child_ret) { + stringstream error_str; + error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; + throw(DataInvalidChildException(error_str.str().c_str())); +} - return *child_ret; +return *child_ret; } int DataNode::numChildren() { - return children.size(); +return children.size(); } int DataNode::numChildren(const char *name_in) { - return childmap[name_in].size(); +return childmap[name_in].size(); } bool DataNode::hasAnother() { - return children.size() != ptr; +return children.size() != ptr; } bool DataNode::hasAnother(const char *name_in) { - return childmap[name_in].size() != childmap_ptr[name_in]; +return childmap[name_in].size() != childmap_ptr[name_in]; } DataNode & DataNode::getNext() throw (DataInvalidChildException) { - return child(ptr++); +return child(ptr++); } DataNode &DataNode::getNext(const char *name_in) throw (DataInvalidChildException) { - return child(name_in, childmap_ptr[name_in]++); +return child(name_in, childmap_ptr[name_in]++); } void DataNode::rewind() { - ptr = 0; +ptr = 0; } void DataNode::rewind(const char *name_in) { - childmap_ptr[name_in] = 0; +childmap_ptr[name_in] = 0; } /* DataTree class */ DataTree::DataTree(const char *name_in) { - dn_root.setName(name_in); +dn_root.setName(name_in); } DataTree::DataTree() { @@ -648,941 +882,941 @@ DataTree::~DataTree() { ; DataNode & DataTree::rootNode() { - return dn_root; +return dn_root; } std::string trim(std::string& s, const std::string& drop = " ") { - std::string r = s.erase(s.find_last_not_of(drop) + 1); - return r.erase(0, r.find_first_not_of(drop)); +std::string r = s.erase(s.find_last_not_of(drop) + 1); +return r.erase(0, r.find_first_not_of(drop)); } void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPointPolicy fpp) { - int tmp_char; - int tmp_int; - long tmp_long; - long long tmp_llong; - double tmp_double; - float tmp_float; - string tmp_str; - string tmp_str2; - std::stringstream tmp_stream; - std::stringstream tmp_stream2; +int tmp_char; +int tmp_int; +long tmp_long; +long long tmp_llong; +double tmp_double; +float tmp_float; +string tmp_str; +string tmp_str2; +std::stringstream tmp_stream; +std::stringstream tmp_stream2; - vector<char> tmp_charvect; - vector<int> tmp_intvect; - vector<long> tmp_longvect; - vector<long> tmp_llongvect; - vector<long>::iterator tmp_llongvect_i; - vector<double> tmp_doublevect; - vector<double>::iterator tmp_doublevect_i; - vector<float> tmp_floatvect; +vector<char> tmp_charvect; +vector<int> tmp_intvect; +vector<long> tmp_longvect; +vector<long> tmp_llongvect; +vector<long>::iterator tmp_llongvect_i; +vector<double> tmp_doublevect; +vector<double>::iterator tmp_doublevect_i; +vector<float> tmp_floatvect; - bool vChars = false; - bool vInts = false; - bool vLongs = false; +bool vChars = false; +bool vInts = false; +bool vLongs = false; - string in_text = src_text; +string in_text = src_text; - trim(in_text); - trim(in_text, "\r\n"); - tmp_stream.str(""); - tmp_stream2.str(""); +trim(in_text); +trim(in_text, "\r\n"); +tmp_stream.str(""); +tmp_stream2.str(""); - if (in_text.find_first_not_of("0123456789-") == string::npos) { - tmp_stream << in_text; +if (in_text.find_first_not_of("0123456789-") == string::npos) { + tmp_stream << in_text; + tmp_stream >> tmp_llong; + + tmp_int = tmp_llong; + tmp_long = tmp_llong; + + if (tmp_int == tmp_llong) { + elem->element().set((int) tmp_int); + } else if (tmp_long == tmp_llong) { + elem->element().set((long) tmp_int); + } else { + elem->element().set((long long) tmp_long); + } +} else if (in_text.find_first_not_of("0123456789.e+-") == string::npos) { + tmp_stream << in_text; + + if (fpp == USE_FLOAT) { + tmp_stream >> tmp_float; + + elem->element().set((float) tmp_float); + } else { + tmp_stream >> tmp_double; + + elem->element().set((double) tmp_double); + } +} else if (in_text.find_first_not_of("0123456789- ") == string::npos) { + tmp_stream << in_text; + + vChars = true; + vInts = true; + vLongs = true; + + while (!tmp_stream.eof()) { tmp_stream >> tmp_llong; - + tmp_char = tmp_llong; tmp_int = tmp_llong; tmp_long = tmp_llong; - - if (tmp_int == tmp_llong) { - elem->element().set((int) tmp_int); - } else if (tmp_long == tmp_llong) { - elem->element().set((long) tmp_int); - } else { - elem->element().set((long long) tmp_long); + if (tmp_char != tmp_llong) { + vChars = false; } - } else if (in_text.find_first_not_of("0123456789.e+-") == string::npos) { - tmp_stream << in_text; + if (tmp_int != tmp_llong) { + vInts = false; + } + if (tmp_long != tmp_llong) { + vLongs = false; + } + tmp_llongvect.push_back((long) tmp_long); + } + + if (vChars) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_charvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_charvect); + tmp_charvect.clear(); + + } else if (vInts) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_intvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_intvect); + tmp_intvect.clear(); + } else if (vLongs) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_longvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_longvect); + tmp_longvect.clear(); + } else { + elem->element().set(tmp_llongvect); + } +} else if (in_text.find_first_not_of("0123456789.e-+ ") == string::npos) { + tmp_stream << in_text; + + if (fpp == USE_FLOAT) { + tmp_floatvect.clear(); + } else { + tmp_doublevect.clear(); + } + + while (!tmp_stream.eof()) { if (fpp == USE_FLOAT) { tmp_stream >> tmp_float; - - elem->element().set((float) tmp_float); + tmp_floatvect.push_back(tmp_float); } else { tmp_stream >> tmp_double; - - elem->element().set((double) tmp_double); + tmp_doublevect.push_back(tmp_double); } - } else if (in_text.find_first_not_of("0123456789- ") == string::npos) { - tmp_stream << in_text; - - vChars = true; - vInts = true; - vLongs = true; - - while (!tmp_stream.eof()) { - tmp_stream >> tmp_llong; - tmp_char = tmp_llong; - tmp_int = tmp_llong; - tmp_long = tmp_llong; - if (tmp_char != tmp_llong) { - vChars = false; - } - if (tmp_int != tmp_llong) { - vInts = false; - } - if (tmp_long != tmp_llong) { - vLongs = false; - } - tmp_llongvect.push_back((long) tmp_long); - } - - if (vChars) { - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_charvect.push_back(*tmp_llongvect_i); - } - tmp_llongvect.clear(); - elem->element().set(tmp_charvect); - tmp_charvect.clear(); - - } else if (vInts) { - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_intvect.push_back(*tmp_llongvect_i); - } - tmp_llongvect.clear(); - elem->element().set(tmp_intvect); - tmp_intvect.clear(); - } else if (vLongs) { - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_longvect.push_back(*tmp_llongvect_i); - } - tmp_llongvect.clear(); - elem->element().set(tmp_longvect); - tmp_longvect.clear(); - } else { - elem->element().set(tmp_llongvect); - } - } else if (in_text.find_first_not_of("0123456789.e-+ ") == string::npos) { - tmp_stream << in_text; - - if (fpp == USE_FLOAT) { - tmp_floatvect.clear(); - } else { - tmp_doublevect.clear(); - } - - while (!tmp_stream.eof()) { - - if (fpp == USE_FLOAT) { - tmp_stream >> tmp_float; - tmp_floatvect.push_back(tmp_float); - } else { - tmp_stream >> tmp_double; - tmp_doublevect.push_back(tmp_double); - } - } - - if (fpp == USE_FLOAT) { - elem->element().set(tmp_floatvect); - } else { - elem->element().set(tmp_doublevect); - } - } else { - elem->element().set(src_text); - // printf( "Unhandled DataTree XML Field: [%s]", tmp_str.c_str() ); } + if (fpp == USE_FLOAT) { + elem->element().set(tmp_floatvect); + } else { + elem->element().set(tmp_doublevect); + } +} else { + elem->element().set(src_text); + // printf( "Unhandled DataTree XML Field: [%s]", tmp_str.c_str() ); +} + } void DataTree::setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node, DT_FloatingPointPolicy fpp) { - TiXmlText *pText; - int t = elxml->Type(); - string tmp_str; +TiXmlText *pText; +int t = elxml->Type(); +string tmp_str; - switch (t) { - case TiXmlNode::DOCUMENT: - // printf( "Document" ); - break; +switch (t) { +case TiXmlNode::DOCUMENT: + // printf( "Document" ); + break; - case TiXmlNode::ELEMENT: - if (!root_node) - elem = &elem->newChild(elxml->Value()); +case TiXmlNode::ELEMENT: + if (!root_node) + elem = &elem->newChild(elxml->Value()); - const TiXmlAttribute *attribs; - attribs = elxml->ToElement()->FirstAttribute(); + const TiXmlAttribute *attribs; + attribs = elxml->ToElement()->FirstAttribute(); - while (attribs) { + while (attribs) { - // following badgerfish xml->json and xml->ruby convention for attributes.. - string attrName("@"); - attrName.append(attribs->Name()); + // following badgerfish xml->json and xml->ruby convention for attributes.. + string attrName("@"); + attrName.append(attribs->Name()); - decodeXMLText(&elem->newChild(attrName.c_str()), attribs->Value(), fpp); + decodeXMLText(&elem->newChild(attrName.c_str()), attribs->Value(), fpp); - attribs = attribs->Next(); - } - - // printf( "Element \"%s\"", elxml->Value()); - break; - - case TiXmlNode::COMMENT: - // printf( "Comment: \"%s\"", elxml->Value()); - break; - - case TiXmlNode::UNKNOWN: - // printf( "Unknown" ); - break; - - case TiXmlNode::TEXT: - pText = elxml->ToText(); - - decodeXMLText(elem, pText->Value(), fpp); - - // pText = elxml->ToText(); - // printf( "Text: [%s]", pText->Value() ); - break; - - case TiXmlNode::DECLARATION: - // printf( "Declaration" ); - break; - default: - break; + attribs = attribs->Next(); } - // printf( "\n" ); + // printf( "Element \"%s\"", elxml->Value()); + break; - TiXmlNode * pChild; +case TiXmlNode::COMMENT: + // printf( "Comment: \"%s\"", elxml->Value()); + break; - if (!elxml->NoChildren()) { - if (elxml->FirstChild()->Type() == TiXmlNode::ELEMENT) { - if (elxml->FirstChild()->Value() == TIXML_STRING("str")) { - std::vector<std::string> tmp_strvect; +case TiXmlNode::UNKNOWN: + // printf( "Unknown" ); + break; - for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { - if (pChild->Value() == TIXML_STRING("str")) { - if (!pChild->FirstChild()) { - tmp_strvect.push_back(""); - continue; - } +case TiXmlNode::TEXT: + pText = elxml->ToText(); - pText = pChild->FirstChild()->ToText(); + decodeXMLText(elem, pText->Value(), fpp); - if (pText) { - tmp_str = pText->Value(); - tmp_strvect.push_back(tmp_str); - } + // pText = elxml->ToText(); + // printf( "Text: [%s]", pText->Value() ); + break; + +case TiXmlNode::DECLARATION: + // printf( "Declaration" ); + break; +default: + break; +} + +// printf( "\n" ); + +TiXmlNode * pChild; + +if (!elxml->NoChildren()) { + if (elxml->FirstChild()->Type() == TiXmlNode::ELEMENT) { + if (elxml->FirstChild()->Value() == TIXML_STRING("str")) { + std::vector<std::string> tmp_strvect; + + for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { + if (pChild->Value() == TIXML_STRING("str")) { + if (!pChild->FirstChild()) { + tmp_strvect.push_back(""); + continue; + } + + pText = pChild->FirstChild()->ToText(); + + if (pText) { + tmp_str = pText->Value(); + tmp_strvect.push_back(tmp_str); } } - - elem->element().set(tmp_strvect); - - return; } + + elem->element().set(tmp_strvect); + + return; } } +} - for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { - setFromXML(elem, pChild, false, fpp); - } +for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { + setFromXML(elem, pChild, false, fpp); +} } void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { - DataNode *child; +DataNode *child; - elem->rewind(); +elem->rewind(); - while (elem->hasAnother()) { - child = &elem->getNext(); +while (elem->hasAnother()) { + child = &elem->getNext(); - std::string nodeName = child->getName(); + std::string nodeName = child->getName(); - TiXmlElement *element; + TiXmlElement *element; - element = new TiXmlElement(nodeName.length() ? nodeName.c_str() : "node"); - std::string tmp; - std::stringstream tmp_stream; - TiXmlText *text; - std::vector<float> tmp_floatvect; - std::vector<float>::iterator tmp_floatvect_i; - std::vector<double> tmp_doublevect; - std::vector<double>::iterator tmp_doublevect_i; - std::vector<int> tmp_intvect; - std::vector<int>::iterator tmp_intvect_i; - std::vector<char> tmp_charvect; - std::vector<char>::iterator tmp_charvect_i; - std::vector<unsigned char> tmp_ucharvect; - std::vector<unsigned char>::iterator tmp_ucharvect_i; - std::vector<unsigned int> tmp_uintvect; - std::vector<unsigned int>::iterator tmp_uintvect_i; - std::vector<long> tmp_longvect; - std::vector<long>::iterator tmp_longvect_i; - std::vector<unsigned long> tmp_ulongvect; - std::vector<unsigned long>::iterator tmp_ulongvect_i; - std::vector<long long> tmp_llongvect; - std::vector<long long>::iterator tmp_llongvect_i; - std::vector<unsigned long long> tmp_ullongvect; - std::vector<unsigned long long>::iterator tmp_ullongvect_i; - std::vector<string> tmp_stringvect; - std::vector<string>::iterator tmp_stringvect_i; - TiXmlElement *tmp_node; - char *tmp_pstr; - double tmp_double; - long double tmp_ldouble; - float tmp_float; - char tmp_char; - unsigned char tmp_uchar; - int tmp_int; - unsigned int tmp_uint; - long tmp_long; - unsigned long tmp_ulong; - long long tmp_llong; + element = new TiXmlElement(nodeName.length() ? nodeName.c_str() : "node"); + std::string tmp; + std::stringstream tmp_stream; + TiXmlText *text; + std::vector<float> tmp_floatvect; + std::vector<float>::iterator tmp_floatvect_i; + std::vector<double> tmp_doublevect; + std::vector<double>::iterator tmp_doublevect_i; + std::vector<int> tmp_intvect; + std::vector<int>::iterator tmp_intvect_i; + std::vector<char> tmp_charvect; + std::vector<char>::iterator tmp_charvect_i; + std::vector<unsigned char> tmp_ucharvect; + std::vector<unsigned char>::iterator tmp_ucharvect_i; + std::vector<unsigned int> tmp_uintvect; + std::vector<unsigned int>::iterator tmp_uintvect_i; + std::vector<long> tmp_longvect; + std::vector<long>::iterator tmp_longvect_i; + std::vector<unsigned long> tmp_ulongvect; + std::vector<unsigned long>::iterator tmp_ulongvect_i; + std::vector<long long> tmp_llongvect; + std::vector<long long>::iterator tmp_llongvect_i; + std::vector<unsigned long long> tmp_ullongvect; + std::vector<unsigned long long>::iterator tmp_ullongvect_i; + std::vector<string> tmp_stringvect; + std::vector<string>::iterator tmp_stringvect_i; + TiXmlElement *tmp_node; + char *tmp_pstr; + double tmp_double; + long double tmp_ldouble; + float tmp_float; + char tmp_char; + unsigned char tmp_uchar; + int tmp_int; + unsigned int tmp_uint; + long tmp_long; + unsigned long tmp_ulong; + long long tmp_llong; - switch (child->element().getDataType()) { - case DATA_NULL: - break; - case DATA_VOID: - child->element().get(&tmp_pstr); - // following badgerfish xml->json and xml->ruby convention for attributes.. - if (nodeName.substr(0, 1) == string("@")) { - elxml->SetAttribute(nodeName.substr(1).c_str(), tmp_pstr); - delete element; - element = NULL; - } else { - text = new TiXmlText(tmp_pstr); - element->LinkEndChild(text); - } - delete tmp_pstr; - break; - case DATA_CHAR: - child->element().get(tmp_char); - - tmp_stream.str(""); - - tmp_stream << tmp_char; - - text = new TiXmlText(tmp_stream.str().c_str()); + switch (child->element().getDataType()) { + case DATA_NULL: + break; + case DATA_VOID: + child->element().get(&tmp_pstr); + // following badgerfish xml->json and xml->ruby convention for attributes.. + if (nodeName.substr(0, 1) == string("@")) { + elxml->SetAttribute(nodeName.substr(1).c_str(), tmp_pstr); + delete element; + element = NULL; + } else { + text = new TiXmlText(tmp_pstr); element->LinkEndChild(text); - break; - case DATA_UCHAR: - child->element().get(tmp_uchar); + } + delete tmp_pstr; + break; + case DATA_CHAR: + child->element().get(tmp_char); - tmp_stream.str(""); + tmp_stream.str(""); - tmp_stream << tmp_uchar; + tmp_stream << tmp_char; - text = new TiXmlText(tmp_stream.str().c_str()); + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_UCHAR: + child->element().get(tmp_uchar); + + tmp_stream.str(""); + + tmp_stream << tmp_uchar; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_INT: + child->element().get(tmp_int); + + tmp_stream.str(""); + + tmp_stream << tmp_int; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_UINT: + child->element().get(tmp_uint); + + tmp_stream.str(""); + + tmp_stream << tmp_uint; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONG: + child->element().get(tmp_long); + + tmp_stream.str(""); + + tmp_stream << tmp_long; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_ULONG: + child->element().get(tmp_ulong); + + tmp_stream.str(""); + + tmp_stream << tmp_ulong; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONGLONG: + child->element().get(tmp_llong); + + tmp_stream.str(""); + + tmp_stream << tmp_llong; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_FLOAT: + child->element().get(tmp_float); + + tmp_stream.str(""); + + tmp_stream << tmp_float; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_DOUBLE: + child->element().get(tmp_double); + + tmp_stream.str(""); + + tmp_stream << tmp_double; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONGDOUBLE: + child->element().get(tmp_ldouble); + + tmp_stream.str(""); + + tmp_stream << tmp_ldouble; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_STRING: + child->element().get(tmp); + if (nodeName.substr(0, 1) == string("@")) { + elxml->SetAttribute(nodeName.substr(1).c_str(), tmp.c_str()); + delete element; + element = NULL; + } else { + text = new TiXmlText(tmp.c_str()); element->LinkEndChild(text); - break; - case DATA_INT: - child->element().get(tmp_int); + } + break; - tmp_stream.str(""); + case DATA_STR_VECTOR: + child->element().get(tmp_stringvect); - tmp_stream << tmp_int; + tmp_stream.str(""); - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_UINT: - child->element().get(tmp_uint); - - tmp_stream.str(""); - - tmp_stream << tmp_uint; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_LONG: - child->element().get(tmp_long); - - tmp_stream.str(""); - - tmp_stream << tmp_long; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_ULONG: - child->element().get(tmp_ulong); - - tmp_stream.str(""); - - tmp_stream << tmp_ulong; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_LONGLONG: - child->element().get(tmp_llong); - - tmp_stream.str(""); - - tmp_stream << tmp_llong; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_FLOAT: - child->element().get(tmp_float); - - tmp_stream.str(""); - - tmp_stream << tmp_float; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_DOUBLE: - child->element().get(tmp_double); - - tmp_stream.str(""); - - tmp_stream << tmp_double; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_LONGDOUBLE: - child->element().get(tmp_ldouble); - - tmp_stream.str(""); - - tmp_stream << tmp_ldouble; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_STRING: - child->element().get(tmp); - if (nodeName.substr(0, 1) == string("@")) { - elxml->SetAttribute(nodeName.substr(1).c_str(), tmp.c_str()); - delete element; - element = NULL; - } else { - text = new TiXmlText(tmp.c_str()); - element->LinkEndChild(text); - } - break; - - case DATA_STR_VECTOR: - child->element().get(tmp_stringvect); - - tmp_stream.str(""); - - for (tmp_stringvect_i = tmp_stringvect.begin(); tmp_stringvect_i != tmp_stringvect.end(); tmp_stringvect_i++) { - tmp_node = new TiXmlElement("str"); - text = new TiXmlText((*tmp_stringvect_i).c_str()); - tmp_node->LinkEndChild(text); - element->LinkEndChild(tmp_node); - } - - tmp_stringvect.clear(); - break; - case DATA_CHAR_VECTOR: - child->element().get(tmp_charvect); - - tmp_stream.str(""); - - for (tmp_charvect_i = tmp_charvect.begin(); tmp_charvect_i != tmp_charvect.end(); tmp_charvect_i++) { - tmp_stream << (*tmp_charvect_i); - if (tmp_charvect_i != tmp_charvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_charvect.clear(); - break; - case DATA_UCHAR_VECTOR: - child->element().get(tmp_ucharvect); - - tmp_stream.str(""); - - for (tmp_ucharvect_i = tmp_ucharvect.begin(); tmp_ucharvect_i != tmp_ucharvect.end(); tmp_ucharvect_i++) { - tmp_stream << (*tmp_ucharvect_i); - if (tmp_ucharvect_i != tmp_ucharvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_ucharvect.clear(); - break; - case DATA_INT_VECTOR: - child->element().get(tmp_intvect); - - tmp_stream.str(""); - - for (tmp_intvect_i = tmp_intvect.begin(); tmp_intvect_i != tmp_intvect.end(); tmp_intvect_i++) { - tmp_stream << (*tmp_intvect_i); - if (tmp_intvect_i != tmp_intvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_intvect.clear(); - break; - case DATA_UINT_VECTOR: - child->element().get(tmp_uintvect); - - tmp_stream.str(""); - - for (tmp_uintvect_i = tmp_uintvect.begin(); tmp_uintvect_i != tmp_uintvect.end(); tmp_uintvect_i++) { - tmp_stream << (*tmp_intvect_i); - if (tmp_uintvect_i != tmp_uintvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_uintvect.clear(); - break; - case DATA_LONG_VECTOR: - child->element().get(tmp_longvect); - - tmp_stream.str(""); - - for (tmp_longvect_i = tmp_longvect.begin(); tmp_longvect_i != tmp_longvect.end(); tmp_longvect_i++) { - tmp_stream << (*tmp_longvect_i); - if (tmp_longvect_i != tmp_longvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_longvect.clear(); - break; - case DATA_ULONG_VECTOR: - child->element().get(tmp_ulongvect); - - tmp_stream.str(""); - - for (tmp_ulongvect_i = tmp_ulongvect.begin(); tmp_ulongvect_i != tmp_ulongvect.end(); tmp_ulongvect_i++) { - tmp_stream << (*tmp_ulongvect_i); - if (tmp_ulongvect_i != tmp_ulongvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_ulongvect.clear(); - break; - case DATA_LONGLONG_VECTOR: - child->element().get(tmp_llongvect); - - tmp_stream.str(""); - - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_stream << (*tmp_llongvect_i); - if (tmp_llongvect_i != tmp_llongvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_llongvect.clear(); - break; - case DATA_FLOAT_VECTOR: - child->element().get(tmp_floatvect); - - tmp_stream.str(""); - - for (tmp_floatvect_i = tmp_floatvect.begin(); tmp_floatvect_i != tmp_floatvect.end(); tmp_floatvect_i++) { - tmp_stream << (*tmp_floatvect_i); - if (tmp_floatvect_i != tmp_floatvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_floatvect.clear(); - break; - case DATA_DOUBLE_VECTOR: - child->element().get(tmp_doublevect); - - tmp_stream.str(""); - - for (tmp_doublevect_i = tmp_doublevect.begin(); tmp_doublevect_i != tmp_doublevect.end(); tmp_doublevect_i++) { - tmp_stream << (*tmp_doublevect_i); - if (tmp_doublevect_i != tmp_doublevect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_doublevect.clear(); - break; + for (tmp_stringvect_i = tmp_stringvect.begin(); tmp_stringvect_i != tmp_stringvect.end(); tmp_stringvect_i++) { + tmp_node = new TiXmlElement("str"); + text = new TiXmlText((*tmp_stringvect_i).c_str()); + tmp_node->LinkEndChild(text); + element->LinkEndChild(tmp_node); } - if (element) { - elxml->LinkEndChild(element); + tmp_stringvect.clear(); + break; + case DATA_CHAR_VECTOR: + child->element().get(tmp_charvect); - if (child->numChildren()) { - nodeToXML(child, element); - } + tmp_stream.str(""); + + for (tmp_charvect_i = tmp_charvect.begin(); tmp_charvect_i != tmp_charvect.end(); tmp_charvect_i++) { + tmp_stream << (*tmp_charvect_i); + if (tmp_charvect_i != tmp_charvect.end() - 1) + tmp_stream << " "; } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_charvect.clear(); + break; + case DATA_UCHAR_VECTOR: + child->element().get(tmp_ucharvect); + + tmp_stream.str(""); + + for (tmp_ucharvect_i = tmp_ucharvect.begin(); tmp_ucharvect_i != tmp_ucharvect.end(); tmp_ucharvect_i++) { + tmp_stream << (*tmp_ucharvect_i); + if (tmp_ucharvect_i != tmp_ucharvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_ucharvect.clear(); + break; + case DATA_INT_VECTOR: + child->element().get(tmp_intvect); + + tmp_stream.str(""); + + for (tmp_intvect_i = tmp_intvect.begin(); tmp_intvect_i != tmp_intvect.end(); tmp_intvect_i++) { + tmp_stream << (*tmp_intvect_i); + if (tmp_intvect_i != tmp_intvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_intvect.clear(); + break; + case DATA_UINT_VECTOR: + child->element().get(tmp_uintvect); + + tmp_stream.str(""); + + for (tmp_uintvect_i = tmp_uintvect.begin(); tmp_uintvect_i != tmp_uintvect.end(); tmp_uintvect_i++) { + tmp_stream << (*tmp_intvect_i); + if (tmp_uintvect_i != tmp_uintvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_uintvect.clear(); + break; + case DATA_LONG_VECTOR: + child->element().get(tmp_longvect); + + tmp_stream.str(""); + + for (tmp_longvect_i = tmp_longvect.begin(); tmp_longvect_i != tmp_longvect.end(); tmp_longvect_i++) { + tmp_stream << (*tmp_longvect_i); + if (tmp_longvect_i != tmp_longvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_longvect.clear(); + break; + case DATA_ULONG_VECTOR: + child->element().get(tmp_ulongvect); + + tmp_stream.str(""); + + for (tmp_ulongvect_i = tmp_ulongvect.begin(); tmp_ulongvect_i != tmp_ulongvect.end(); tmp_ulongvect_i++) { + tmp_stream << (*tmp_ulongvect_i); + if (tmp_ulongvect_i != tmp_ulongvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_ulongvect.clear(); + break; + case DATA_LONGLONG_VECTOR: + child->element().get(tmp_llongvect); + + tmp_stream.str(""); + + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_stream << (*tmp_llongvect_i); + if (tmp_llongvect_i != tmp_llongvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_llongvect.clear(); + break; + case DATA_FLOAT_VECTOR: + child->element().get(tmp_floatvect); + + tmp_stream.str(""); + + for (tmp_floatvect_i = tmp_floatvect.begin(); tmp_floatvect_i != tmp_floatvect.end(); tmp_floatvect_i++) { + tmp_stream << (*tmp_floatvect_i); + if (tmp_floatvect_i != tmp_floatvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_floatvect.clear(); + break; + case DATA_DOUBLE_VECTOR: + child->element().get(tmp_doublevect); + + tmp_stream.str(""); + + for (tmp_doublevect_i = tmp_doublevect.begin(); tmp_doublevect_i != tmp_doublevect.end(); tmp_doublevect_i++) { + tmp_stream << (*tmp_doublevect_i); + if (tmp_doublevect_i != tmp_doublevect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_doublevect.clear(); + break; } - elem->rewind(); + if (element) { + elxml->LinkEndChild(element); + + if (child->numChildren()) { + nodeToXML(child, element); + } + } +} + +elem->rewind(); } void DataTree::printXML() /* get serialized size + return node names header */ { - TiXmlDocument doc; - TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); - doc.LinkEndChild(decl); +TiXmlDocument doc; +TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); +doc.LinkEndChild(decl); - DataNode *root = &rootNode(); +DataNode *root = &rootNode(); - string rootName = root->getName(); +string rootName = root->getName(); - TiXmlElement *element = new TiXmlElement(rootName.empty() ? "root" : rootName.c_str()); - doc.LinkEndChild(element); - - if (!root->numChildren()) - doc.Print(); - - nodeToXML(root, element); - - root->rewind(); +TiXmlElement *element = new TiXmlElement(rootName.empty() ? "root" : rootName.c_str()); +doc.LinkEndChild(element); +if (!root->numChildren()) doc.Print(); + +nodeToXML(root, element); + +root->rewind(); + +doc.Print(); } long DataTree::getSerializedSize(DataElement &de_node_names, bool debug) /* get serialized size + return node names header */ { - long total_size = 0; +long total_size = 0; - stack<DataNode *> dn_stack; - vector<string> node_names; - map<string, int, string_less> node_name_index_map; +stack<DataNode *> dn_stack; +vector<string> node_names; +map<string, int, string_less> node_name_index_map; - DataElement de_name_index; // just used for sizing purposes - DataElement de_num_children; +DataElement de_name_index; // just used for sizing purposes +DataElement de_num_children; - de_name_index.set((int) 0); - de_num_children.set((int) 0); +de_name_index.set((int) 0); +de_num_children.set((int) 0); - int de_name_index_size = de_name_index.getSerializedSize(); - int de_num_children_size = de_num_children.getSerializedSize(); +int de_name_index_size = de_name_index.getSerializedSize(); +int de_num_children_size = de_num_children.getSerializedSize(); - dn_stack.push(&dn_root); +dn_stack.push(&dn_root); - while (!dn_stack.empty()) { - int name_index; - // int num_children; +while (!dn_stack.empty()) { + int name_index; + // int num_children; - /* build the name list */ - if (dn_stack.top()->getName().empty()) { - name_index = 0; /* empty string */ - } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { - node_names.push_back(string(dn_stack.top()->getName())); - name_index = node_names.size(); - node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; - } else { - name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; - } - - /* add on the size of the name index and number of children */ - total_size += de_name_index_size; - total_size += de_num_children_size; - total_size += dn_stack.top()->element().getSerializedSize(); - - /* debug output */ - if (debug) { - for (unsigned int i = 0; i < dn_stack.size() - 1; i++) - cout << "--"; - cout << (dn_stack.top()->getName().empty() ? "NULL" : dn_stack.top()->getName()) << "(" << dn_stack.top()->element().getSerializedSize() - << ")"; - cout << " type: " << dn_stack.top()->element().getDataType() << endl; - //cout << " index: " << name_index << endl; - } - /* end debug output */ - - /* if it has children, traverse into them */ - if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } else { - /* no more children, back out until we have children, then add next child to the top */ - while (!dn_stack.empty()) { - if (!dn_stack.top()->hasAnother()) { - dn_stack.top()->rewind(); - dn_stack.pop(); - } else - break; - } - - if (!dn_stack.empty()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } - } + /* build the name list */ + if (dn_stack.top()->getName().empty()) { + name_index = 0; /* empty string */ + } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { + node_names.push_back(string(dn_stack.top()->getName())); + name_index = node_names.size(); + node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; + } else { + name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; } - /* set the header for use in serialization */ - de_node_names.set(node_names); + /* add on the size of the name index and number of children */ + total_size += de_name_index_size; + total_size += de_num_children_size; + total_size += dn_stack.top()->element().getSerializedSize(); - total_size += de_node_names.getSerializedSize(); + /* debug output */ + if (debug) { + for (unsigned int i = 0; i < dn_stack.size() - 1; i++) + cout << "--"; + cout << (dn_stack.top()->getName().empty() ? "NULL" : dn_stack.top()->getName()) << "(" << dn_stack.top()->element().getSerializedSize() + << ")"; + cout << " type: " << dn_stack.top()->element().getDataType() << endl; + //cout << " index: " << name_index << endl; + } + /* end debug output */ - return total_size; + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } + } +} + +/* set the header for use in serialization */ +de_node_names.set(node_names); + +total_size += de_node_names.getSerializedSize(); + +return total_size; } void DataNode::findAll(const char *name_in, vector<DataNode *> &node_list_out) { - stack<DataNode *> dn_stack; +stack<DataNode *> dn_stack; - /* start at the root */ - dn_stack.push(this); +/* start at the root */ +dn_stack.push(this); - if (string(getName()) == string(name_in)) - node_list_out.push_back(this); +if (string(getName()) == string(name_in)) + node_list_out.push_back(this); - while (!dn_stack.empty()) { - while (dn_stack.top()->hasAnother(name_in)) { - node_list_out.push_back(&dn_stack.top()->getNext(name_in)); +while (!dn_stack.empty()) { + while (dn_stack.top()->hasAnother(name_in)) { + node_list_out.push_back(&dn_stack.top()->getNext(name_in)); + } + + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; } - /* if it has children, traverse into them */ - if (dn_stack.top()->hasAnother()) { + if (!dn_stack.empty()) { dn_stack.push(&dn_stack.top()->getNext()); dn_stack.top()->rewind(); - } else { - /* no more children, back out until we have children, then add next child to the top */ - while (!dn_stack.empty()) { - if (!dn_stack.top()->hasAnother()) { - dn_stack.top()->rewind(); - dn_stack.pop(); - } else - break; - } - - if (!dn_stack.empty()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } } } +} } long DataTree::getSerialized(char **ser_str, bool debug) { - long data_ptr = 0; - long data_size = 0; +long data_ptr = 0; +long data_size = 0; - stack<DataNode *> dn_stack; - vector<string> node_names; - map<string, int, string_less> node_name_index_map; +stack<DataNode *> dn_stack; +vector<string> node_names; +map<string, int, string_less> node_name_index_map; - /* header of node names, grabbed from getserializedsize to avoid having to memmove() or realloc() */ - DataElement de_node_names; +/* header of node names, grabbed from getserializedsize to avoid having to memmove() or realloc() */ +DataElement de_node_names; - data_size = getSerializedSize(de_node_names, debug); +data_size = getSerializedSize(de_node_names, debug); - *ser_str = (char *) malloc(data_size); +*ser_str = (char *) malloc(data_size); - char *data_out = *ser_str; +char *data_out = *ser_str; - /* name list header */ - char *de_node_names_serialized; - long de_node_names_serialized_size; +/* name list header */ +char *de_node_names_serialized; +long de_node_names_serialized_size; - de_node_names.getSerialized(&de_node_names_serialized); - de_node_names_serialized_size = de_node_names.getSerializedSize(); +de_node_names.getSerialized(&de_node_names_serialized); +de_node_names_serialized_size = de_node_names.getSerializedSize(); - /* copy the header and increase the pointer */ - memcpy(data_out, de_node_names_serialized, de_node_names_serialized_size); - data_ptr += de_node_names_serialized_size; +/* copy the header and increase the pointer */ +memcpy(data_out, de_node_names_serialized, de_node_names_serialized_size); +data_ptr += de_node_names_serialized_size; - /* start at the root */ - dn_stack.push(&dn_root); +/* start at the root */ +dn_stack.push(&dn_root); - while (!dn_stack.empty()) { - int name_index; - int num_children; - - DataElement de_name_index; - DataElement de_num_children; - - char *de_name_index_serialized; - char *de_num_children_serialized; - char *element_serialized; - - long de_name_index_serialized_size; - long de_num_children_serialized_size; - long element_serialized_size; - - /* build the name list */ - if (dn_stack.top()->getName().empty()) { - name_index = 0; /* empty string */ - } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { - node_names.push_back(string(dn_stack.top()->getName())); - name_index = node_names.size(); - node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; - } else { - name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; - } - - num_children = dn_stack.top()->numChildren(); - - de_name_index.set(name_index); - de_num_children.set(num_children); - - de_name_index_serialized_size = de_name_index.getSerializedSize(); - de_num_children_serialized_size = de_num_children.getSerializedSize(); - element_serialized_size = dn_stack.top()->element().getSerializedSize(); - - de_name_index.getSerialized(&de_name_index_serialized); - de_num_children.getSerialized(&de_num_children_serialized); - dn_stack.top()->element().getSerialized(&element_serialized); - - /* add on the name index and number of children */ - memcpy(data_out + data_ptr, de_name_index_serialized, de_name_index_serialized_size); - data_ptr += de_name_index_serialized_size; - - memcpy(data_out + data_ptr, de_num_children_serialized, de_num_children_serialized_size); - data_ptr += de_num_children_serialized_size; - - /* add on the data element */ - memcpy(data_out + data_ptr, element_serialized, element_serialized_size); - data_ptr += element_serialized_size; - - delete de_name_index_serialized; - delete de_num_children_serialized; - delete element_serialized; - - /* if it has children, traverse into them */ - if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } else { - /* no more children, back out until we have children, then add next child to the top */ - while (!dn_stack.empty()) { - if (!dn_stack.top()->hasAnother()) { - dn_stack.top()->rewind(); - dn_stack.pop(); - } else - break; - } - - if (!dn_stack.empty()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } - } - } - - return data_size; -} - -void DataTree::setSerialized(char *ser_str, bool debug) { - long data_ptr = 0; - // long data_size = 0; - - stack<DataNode *> dn_stack; - stack<int> dn_childcount_stack; - vector<string> node_names; - - DataElement de_node_names; - - de_node_names.setSerialized(ser_str); - data_ptr += de_node_names.getSerializedSize(); - de_node_names.get(node_names); +while (!dn_stack.empty()) { + int name_index; + int num_children; DataElement de_name_index; DataElement de_num_children; - DataElement de_element; - dn_stack.push(&dn_root); - dn_childcount_stack.push(0); /* root (parent null) has no siblings */ + char *de_name_index_serialized; + char *de_num_children_serialized; + char *element_serialized; - /* unserialization is a little less straightforward since we have to do a countdown of remaining children */ - while (!dn_stack.empty()) { - int name_index; - int num_children; + long de_name_index_serialized_size; + long de_num_children_serialized_size; + long element_serialized_size; - /* pull the index of the name of this node */ - de_name_index.setSerialized(ser_str + data_ptr); - data_ptr += de_name_index.getSerializedSize(); + /* build the name list */ + if (dn_stack.top()->getName().empty()) { + name_index = 0; /* empty string */ + } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { + node_names.push_back(string(dn_stack.top()->getName())); + name_index = node_names.size(); + node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; + } else { + name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; + } - /* pull the number of children this node has */ - de_num_children.setSerialized(ser_str + data_ptr); - data_ptr += de_num_children.getSerializedSize(); + num_children = dn_stack.top()->numChildren(); - /* get values from the temp dataelements */ + de_name_index.set(name_index); + de_num_children.set(num_children); + + de_name_index_serialized_size = de_name_index.getSerializedSize(); + de_num_children_serialized_size = de_num_children.getSerializedSize(); + element_serialized_size = dn_stack.top()->element().getSerializedSize(); + + de_name_index.getSerialized(&de_name_index_serialized); + de_num_children.getSerialized(&de_num_children_serialized); + dn_stack.top()->element().getSerialized(&element_serialized); + + /* add on the name index and number of children */ + memcpy(data_out + data_ptr, de_name_index_serialized, de_name_index_serialized_size); + data_ptr += de_name_index_serialized_size; + + memcpy(data_out + data_ptr, de_num_children_serialized, de_num_children_serialized_size); + data_ptr += de_num_children_serialized_size; + + /* add on the data element */ + memcpy(data_out + data_ptr, element_serialized, element_serialized_size); + data_ptr += element_serialized_size; + + delete de_name_index_serialized; + delete de_num_children_serialized; + delete element_serialized; + + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } + } +} + +return data_size; +} + +void DataTree::setSerialized(char *ser_str, bool debug) { +long data_ptr = 0; +// long data_size = 0; + +stack<DataNode *> dn_stack; +stack<int> dn_childcount_stack; +vector<string> node_names; + +DataElement de_node_names; + +de_node_names.setSerialized(ser_str); +data_ptr += de_node_names.getSerializedSize(); +de_node_names.get(node_names); + +DataElement de_name_index; +DataElement de_num_children; +DataElement de_element; + +dn_stack.push(&dn_root); +dn_childcount_stack.push(0); /* root (parent null) has no siblings */ + +/* unserialization is a little less straightforward since we have to do a countdown of remaining children */ +while (!dn_stack.empty()) { + int name_index; + int num_children; + + /* pull the index of the name of this node */ + de_name_index.setSerialized(ser_str + data_ptr); + data_ptr += de_name_index.getSerializedSize(); + + /* pull the number of children this node has */ + de_num_children.setSerialized(ser_str + data_ptr); + data_ptr += de_num_children.getSerializedSize(); + + /* get values from the temp dataelements */ + de_name_index.get(name_index); + de_num_children.get(num_children); + + /* pull the node's element */ + dn_stack.top()->element().setSerialized(ser_str + data_ptr); + data_ptr += dn_stack.top()->element().getSerializedSize(); + + /* debug output */ + if (debug) { + for (unsigned int i = 0; i < dn_stack.size() - 1; i++) + cout << "--"; + cout << (name_index ? node_names[name_index - 1] : "NULL") << "(" << dn_stack.top()->element().getSerializedSize() << ")"; + cout << " index: " << name_index << endl; + } + /* end debug output */ + + /* name index >= 1 means it has a name */ + if (name_index) { + dn_stack.top()->setName(node_names[name_index - 1].c_str()); + + } else /* name is nil */ + { + dn_stack.top()->setName(""); + } + + if (num_children) /* Has children, create first child and push it to the top */ + { + dn_childcount_stack.push(num_children); /* push the child count onto the stack */ + + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ de_name_index.get(name_index); - de_num_children.get(num_children); - - /* pull the node's element */ - dn_stack.top()->element().setSerialized(ser_str + data_ptr); - data_ptr += dn_stack.top()->element().getSerializedSize(); - - /* debug output */ - if (debug) { - for (unsigned int i = 0; i < dn_stack.size() - 1; i++) - cout << "--"; - cout << (name_index ? node_names[name_index - 1] : "NULL") << "(" << dn_stack.top()->element().getSerializedSize() << ")"; - cout << " index: " << name_index << endl; + /* add this child onto the top of the stack */ + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); + dn_childcount_stack.top()--; /* decrement to count the new child */ } - /* end debug output */ - - /* name index >= 1 means it has a name */ - if (name_index) { - dn_stack.top()->setName(node_names[name_index - 1].c_str()); - - } else /* name is nil */ + else /* No children, move on to the next sibling */ + { + if (dn_childcount_stack.top()) /* any siblings remaining? */ { - dn_stack.top()->setName(""); - } - - if (num_children) /* Has children, create first child and push it to the top */ - { - dn_childcount_stack.push(num_children); /* push the child count onto the stack */ - de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ de_name_index.get(name_index); - /* add this child onto the top of the stack */ - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); - dn_childcount_stack.top()--; /* decrement to count the new child */ + + dn_stack.pop(); + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* create the next sibling and throw it on the stack */ + dn_childcount_stack.top()--; /* decrement to count the new sibling */ } - else /* No children, move on to the next sibling */ + else /* This is the last sibling, move up the stack and find the next */ { - if (dn_childcount_stack.top()) /* any siblings remaining? */ + while (!dn_stack.empty()) /* move up the stack until we find the next sibling */ { - de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ - de_name_index.get(name_index); + if (dn_childcount_stack.top()) { + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ + de_name_index.get(name_index); - dn_stack.pop(); - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* create the next sibling and throw it on the stack */ - dn_childcount_stack.top()--; /* decrement to count the new sibling */ - } - else /* This is the last sibling, move up the stack and find the next */ - { - while (!dn_stack.empty()) /* move up the stack until we find the next sibling */ + dn_stack.pop(); + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* throw it on the stack */ + dn_childcount_stack.top()--; /* count it */ + break +; } + else { - if (dn_childcount_stack.top()) { - de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ - de_name_index.get(name_index); - - dn_stack.pop(); - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* throw it on the stack */ - dn_childcount_stack.top()--; /* count it */ - break -; } - else - { - dn_childcount_stack.pop(); - dn_stack.pop(); /* if no more siblings found the stack will empty naturally */ - } + dn_childcount_stack.pop(); + dn_stack.pop(); /* if no more siblings found the stack will empty naturally */ } } } } } +} bool DataTree::LoadFromFileXML(const std::string& filename, DT_FloatingPointPolicy fpp) { TiXmlDocument doc(filename.c_str()); From 36ff762d3ace4d44220ac516806f0a655ce2e9b4 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Thu, 8 Jan 2015 19:56:44 -0500 Subject: [PATCH 04/11] DataTree cleanup/refactor.. --- src/util/DataTree.cpp | 2358 +++++++++++++++++------------------------ src/util/DataTree.h | 14 +- 2 files changed, 968 insertions(+), 1404 deletions(-) diff --git a/src/util/DataTree.cpp b/src/util/DataTree.cpp index 11adcde..be428fb 100755 --- a/src/util/DataTree.cpp +++ b/src/util/DataTree.cpp @@ -37,6 +37,7 @@ DataElement::DataElement() { data_type = DATA_NULL; data_val = NULL; data_size = 0; + unit_size = 0; } DataElement::~DataElement() { @@ -59,75 +60,30 @@ long DataElement::getDataSize() { return data_size; } -//void DataElement::set(const bool &bool_in) -//{ -// data_type = DATA_BOOL; -// data_init(sizeof(bool)); -// memcpy(data_val,&bool_in,data_size); -//} - -void DataElement::set(const char& char_in) { - data_type = DATA_CHAR; - data_init(sizeof(char)); - memcpy(data_val, &char_in, data_size); +int DataElement::getUnitSize() { + return unit_size; } -void DataElement::set(const unsigned char& uchar_in) { - data_type = DATA_UCHAR; - data_init(sizeof(unsigned char)); - memcpy(data_val, &uchar_in, data_size); +#define DataElementSetNumericDef(enumtype, datatype) void DataElement::set(const datatype& val_in) { \ + data_type = enumtype; \ + unit_size = sizeof(char); \ + data_init(unit_size); \ + memcpy(data_val, &val_in, data_size); \ } -void DataElement::set(const unsigned int& uint_in) { - data_type = DATA_UINT; - data_init(sizeof(unsigned int)); - memcpy(data_val, &uint_in, data_size); -} - -void DataElement::set(const unsigned long & ulong_in) { - data_type = DATA_ULONG; - data_init(sizeof(unsigned long)); - memcpy(data_val, &ulong_in, data_size); -} - -void DataElement::set(const long long & llong_in) { - data_type = DATA_ULONG; - data_init(sizeof(long long)); - memcpy(data_val, &llong_in, data_size); -} - -void DataElement::set(const long double& ldouble_in) { - data_type = DATA_LONGDOUBLE; - data_init(sizeof(long double)); - memcpy(data_val, &ldouble_in, data_size); -} - -void DataElement::set(const int &int_in) { - data_type = DATA_INT; - data_init(sizeof(int)); - memcpy(data_val, &int_in, data_size); -} - -void DataElement::set(const long &long_in) { - data_type = DATA_LONG; - data_init(sizeof(long)); - memcpy(data_val, &long_in, data_size); -} - -void DataElement::set(const float &float_in) { - data_type = DATA_FLOAT; - data_init(sizeof(float)); - memcpy(data_val, &float_in, data_size); -} - -void DataElement::set(const double &double_in) { - data_type = DATA_DOUBLE; - data_init(sizeof(double)); - memcpy(data_val, &double_in, data_size); -} +DataElementSetNumericDef(DATA_CHAR, char) +DataElementSetNumericDef(DATA_UCHAR, unsigned char) +DataElementSetNumericDef(DATA_INT, int) +DataElementSetNumericDef(DATA_UINT, unsigned int) +DataElementSetNumericDef(DATA_LONG, long) +DataElementSetNumericDef(DATA_ULONG, unsigned long) +DataElementSetNumericDef(DATA_LONGLONG, long long) +DataElementSetNumericDef(DATA_FLOAT, float) +DataElementSetNumericDef(DATA_DOUBLE, double) +DataElementSetNumericDef(DATA_LONGDOUBLE, long double) void DataElement::set(const char *data_in, long size_in) { - data_type = DATA_FLOAT; + data_type = DATA_VOID; data_init(size_in); memcpy(data_val, data_in, data_size); } @@ -182,695 +138,303 @@ void DataElement::set(std::set<string> &strset_in) { set(tmp_vect); } -void DataElement::set(vector<char>& charvect_in) { - long ptr; - char temp_char; - - data_type = DATA_CHAR_VECTOR; - - data_init(sizeof(char) * charvect_in.size()); - - vector<char>::iterator i; - - ptr = 0; - - for (i = charvect_in.begin(); i != charvect_in.end(); i++) { - temp_char = *i; - memcpy(data_val + ptr, &temp_char, sizeof(char)); - ptr += sizeof(char); - } +#define DataElementSetNumericVectorDef(enumtype, datatype) void DataElement::set(vector<datatype>& val_in) { \ + data_type = enumtype; \ + unit_size = sizeof(char); \ + data_init(unit_size * val_in.size()); \ + memcpy(data_val, &val_in[0], data_size); \ } -void DataElement::set(vector<unsigned char>& ucharvect_in) { - long ptr; - unsigned char temp_uchar; +DataElementSetNumericVectorDef(DATA_CHAR_VECTOR, char) +DataElementSetNumericVectorDef(DATA_UCHAR_VECTOR, unsigned char) +DataElementSetNumericVectorDef(DATA_INT_VECTOR, int) +DataElementSetNumericVectorDef(DATA_UINT_VECTOR, unsigned int) +DataElementSetNumericVectorDef(DATA_LONG_VECTOR, long) +DataElementSetNumericVectorDef(DATA_ULONG_VECTOR, unsigned long) +DataElementSetNumericVectorDef(DATA_LONGLONG_VECTOR, long long) +DataElementSetNumericVectorDef(DATA_FLOAT_VECTOR, float) +DataElementSetNumericVectorDef(DATA_DOUBLE_VECTOR, double) +DataElementSetNumericVectorDef(DATA_LONGDOUBLE_VECTOR, long double) - data_type = DATA_UCHAR_VECTOR; - data_init(sizeof(unsigned char) * ucharvect_in.size()); - - vector<unsigned char>::iterator i; - - ptr = 0; - - for (i = ucharvect_in.begin(); i != ucharvect_in.end(); i++) { - temp_uchar = *i; - memcpy(data_val + ptr, &temp_uchar, sizeof(unsigned char)); - ptr += sizeof(unsigned char); - } -} - -void DataElement::set(vector<unsigned int>& uintvect_in) { - long ptr; - unsigned int temp_uint; - - data_type = DATA_UCHAR_VECTOR; - - data_init(sizeof(unsigned int) * uintvect_in.size()); - - vector<unsigned int>::iterator i; - - ptr = 0; - - for (i = uintvect_in.begin(); i != uintvect_in.end(); i++) { - temp_uint = *i; - memcpy(data_val + ptr, &temp_uint, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - } -} - -void DataElement::set(vector<unsigned long>& ulongvect_in) { - long ptr; - unsigned long temp_ulong; - - data_type = DATA_ULONG_VECTOR; - - data_init(sizeof(unsigned long) * ulongvect_in.size()); - - vector<unsigned long>::iterator i; - - ptr = 0; - - for (i = ulongvect_in.begin(); i != ulongvect_in.end(); i++) { - temp_ulong = *i; - memcpy(data_val + ptr, &temp_ulong, sizeof(unsigned long)); - ptr += sizeof(unsigned long); - } -} - -void DataElement::set(vector<long long>& llongvect_in) { - long ptr; - long long temp_llong; - - data_type = DATA_CHAR_VECTOR; - - data_init(sizeof(long long) * llongvect_in.size()); - - vector<long long>::iterator i; - - ptr = 0; - - for (i = llongvect_in.begin(); i != llongvect_in.end(); i++) { - temp_llong = *i; - memcpy(data_val + ptr, &temp_llong, sizeof(long long)); - ptr += sizeof(long long); - } -} - -void DataElement::set(vector<long double>& ldoublevect_in) { - long ptr; - long double temp_ldouble; - - data_type = DATA_CHAR_VECTOR; - - data_init(sizeof(long double) * ldoublevect_in.size()); - - vector<long double>::iterator i; - - ptr = 0; - - for (i = ldoublevect_in.begin(); i != ldoublevect_in.end(); i++) { - temp_ldouble = *i; - memcpy(data_val + ptr, &temp_ldouble, sizeof(long double)); - ptr += sizeof(long double); - } -} - -void DataElement::set(vector<int> &intvect_in) { - long ptr; - int temp_int; - - data_type = DATA_INT_VECTOR; - - data_init(sizeof(int) * intvect_in.size()); - - vector<int>::iterator i; - - ptr = 0; - - for (i = intvect_in.begin(); i != intvect_in.end(); i++) { - temp_int = *i; - memcpy(data_val + ptr, &temp_int, sizeof(int)); - ptr += sizeof(int); - } -} - -void DataElement::set(vector<long> &longvect_in) { - long ptr; - long temp_long; - - data_type = DATA_LONG_VECTOR; - - data_init(sizeof(long) * longvect_in.size()); - - vector<long>::iterator i; - - ptr = 0; - - for (i = longvect_in.begin(); i != longvect_in.end(); i++) { - temp_long = *i; - memcpy(data_val + ptr, &temp_long, sizeof(long)); - ptr += sizeof(long); - } -} - -void DataElement::set(vector<float> &floatvect_in) { - long ptr; - float temp_float; - - data_type = DATA_FLOAT_VECTOR; - - data_init(sizeof(float) * floatvect_in.size()); - - // vector<float>::iterator i; - // - // ptr = 0; - // - // for (i = floatvect_in.begin(); i != floatvect_in.end(); i++) - // { - // temp_float = *i; - // memcpy(data_val+ptr, &temp_float, sizeof(float)); - // ptr += sizeof(float); - // } - - memcpy(data_val, &floatvect_in[0], sizeof(float) * floatvect_in.size()); -} - -void DataElement::set(vector<double> &doublevect_in) { - long ptr; - double temp_double; - - data_type = DATA_DOUBLE_VECTOR; - - data_init(sizeof(double) * doublevect_in.size()); - - vector<double>::iterator i; - - ptr = 0; - - for (i = doublevect_in.begin(); i != doublevect_in.end(); i++) { - temp_double = *i; - memcpy(data_val + ptr, &temp_double, sizeof(double)); - ptr += sizeof(double); - } -} - -#define DataElementGetNumericDef(enumtype, datatype) void DataElement::get(datatype& val_out) throw (DataTypeMismatchException) { \ +#define DataElementGetNumericDef(enumtype, datatype, ...) void DataElement::get(datatype& val_out) throw (DataTypeMismatchException) { \ if (!data_type) \ return; \ + int _compat[] = {__VA_ARGS__}; \ if (data_type != enumtype) { \ + bool compat = false; \ + for (int i = 0; i < sizeof(_compat)/sizeof(int); i++) { \ + if (_compat[i] == data_type) { \ + compat = true; \ + break; \ + } \ + } \ + if (!compat) { \ + throw(new DataTypeMismatchException("Type mismatch, element type " #enumtype " is not compatible with a " #datatype)); \ + } \ if (sizeof(datatype) < data_size) { \ std::cout << "Warning, data type mismatch requested size for '" << #datatype << "(" << sizeof(datatype) << ")' < data size '" << data_size << "'; possible loss of data."; \ } \ memset(&val_out, 0, sizeof(datatype)); \ memcpy(&val_out, data_val, (sizeof(datatype) < data_size) ? sizeof(datatype) : data_size); \ + return; \ } \ memcpy(&val_out, data_val, data_size); \ } -DataElementGetNumericDef(DATA_CHAR, char) -DataElementGetNumericDef(DATA_UCHAR, unsigned char) -DataElementGetNumericDef(DATA_UINT, unsigned int) -DataElementGetNumericDef(DATA_ULONG, unsigned long) -DataElementGetNumericDef(DATA_LONGLONG, long long) -DataElementGetNumericDef(DATA_LONGDOUBLE, long double) -DataElementGetNumericDef(DATA_INT, int) -DataElementGetNumericDef(DATA_LONG, long) -DataElementGetNumericDef(DATA_FLOAT, float) -DataElementGetNumericDef(DATA_DOUBLE, double) - -////void DataElement::get(char& char_in) throw (DataTypeMismatchException) { -////if (!data_type) -//// return; -////if (data_type != DATA_CHAR) -//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); -//// -////memcpy(&char_in, data_val, data_size); -////} -// -////void DataElement::get(unsigned char& uchar_in) throw (DataTypeMismatchException) { -////if (!data_type) -//// return; -////if (data_type != DATA_UCHAR) -//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); -//// -////memcpy(&uchar_in, data_val, data_size); -////} -// -////void DataElement::get(unsigned int& uint_in) throw (DataTypeMismatchException) { -////if (!data_type) -//// return; -////if (data_type != DATA_UINT) -//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); -//// -////memcpy(&uint_in, data_val, data_size); -////} -// -////void DataElement::get(unsigned long & ulong_in) throw (DataTypeMismatchException) { -////if (!data_type) -//// return; -////if (data_type != DATA_ULONG) -//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); -//// -////memcpy(&ulong_in, data_val, data_size); -////} -// -////void DataElement::get(long long & long_in) throw (DataTypeMismatchException) { -////if (!data_type) -//// return; -////if (data_type != DATA_LONG) -//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); -//// -////memcpy(&long_in, data_val, data_size); -////} -// -////void DataElement::get(long double& ldouble_in) throw (DataTypeMismatchException) { -////if (!data_type) -//// return; -////if (data_type != DATA_LONGDOUBLE) -//// throw(new DataTypeMismatchException("Type mismatch, not a INT")); -//// -////memcpy(&ldouble_in, data_val, data_size); -////} -// -//void DataElement::get(int &int_in) throw (DataTypeMismatchException) { -//if (!data_type) -// return; -//if (data_type != DATA_INT) -// throw(new DataTypeMismatchException("Type mismatch, not a INT")); -// -//memcpy(&int_in, data_val, data_size); -//} -// -//void DataElement::get(long &long_in) throw (DataTypeMismatchException) { -//if (!data_type) -// return; -//if (data_type != DATA_LONG) -// throw(new DataTypeMismatchException("Type mismatch, not a LONG")); -// -//memcpy(&long_in, data_val, data_size); -//} -// -//void DataElement::get(float &float_in) throw (DataTypeMismatchException) { -//if (!data_type) -// return; -//if (data_type != DATA_FLOAT) -// throw(new DataTypeMismatchException("Type mismatch, not a FLOAT")); -// -//memcpy(&float_in, data_val, data_size); -//} -// -//void DataElement::get(double &double_in) throw (DataTypeMismatchException) { -//if (!data_type) -// return; -//if (data_type != DATA_DOUBLE) -// throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE")); -// -//memcpy(&double_in, data_val, data_size); -//} +DataElementGetNumericDef(DATA_CHAR, char, DATA_UCHAR, DATA_UINT, DATA_ULONG, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_INT, DATA_LONG) +DataElementGetNumericDef(DATA_UCHAR, unsigned char, DATA_CHAR, DATA_UINT, DATA_ULONG, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_INT, DATA_LONG) +DataElementGetNumericDef(DATA_UINT, unsigned int, DATA_CHAR, DATA_UCHAR, DATA_ULONG, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_INT, DATA_LONG) +DataElementGetNumericDef(DATA_ULONG, unsigned long, DATA_CHAR, DATA_UCHAR, DATA_UINT, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_INT, DATA_LONG) +DataElementGetNumericDef(DATA_LONGLONG, long long, DATA_CHAR, DATA_UCHAR, DATA_UINT, DATA_ULONG, DATA_LONGDOUBLE, DATA_INT, DATA_LONG) +DataElementGetNumericDef(DATA_LONGDOUBLE, long double, DATA_CHAR, DATA_UCHAR, DATA_UINT, DATA_ULONG, DATA_LONGLONG, DATA_INT, DATA_LONG) +DataElementGetNumericDef(DATA_INT, int, DATA_CHAR, DATA_UCHAR, DATA_UINT, DATA_ULONG, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_LONG) +DataElementGetNumericDef(DATA_LONG, long, DATA_CHAR, DATA_UCHAR, DATA_UINT, DATA_ULONG, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_INT) +DataElementGetNumericDef(DATA_FLOAT, float, DATA_DOUBLE, DATA_CHAR, DATA_UCHAR, DATA_UINT, DATA_ULONG, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_INT, + DATA_LONG) +DataElementGetNumericDef(DATA_DOUBLE, double, DATA_FLOAT, DATA_CHAR, DATA_UCHAR, DATA_UINT, DATA_ULONG, DATA_LONGLONG, DATA_LONGDOUBLE, DATA_INT, + DATA_LONG) void DataElement::get(char **data_in) throw (DataTypeMismatchException) { -if (data_type != DATA_VOID) - throw(new DataTypeMismatchException("Type mismatch, not a CHAR*")); -*data_in = new char[data_size]; -memcpy(*data_in, data_val, data_size); + if (data_type != DATA_VOID) + throw(new DataTypeMismatchException("Type mismatch, not a CHAR*")); + *data_in = new char[data_size]; + memcpy(*data_in, data_val, data_size); } void DataElement::get(string &str_in) throw (DataTypeMismatchException) { -if (!data_type) - return; + if (!data_type) + return; -if (data_type != DATA_STRING) - throw(new DataTypeMismatchException("Type mismatch, not a STRING")); + if (data_type != DATA_STRING) + throw(new DataTypeMismatchException("Type mismatch, not a STRING")); -if (!str_in.empty()) // flush the string -{ - str_in.erase(str_in.begin(), str_in.end()); -} + if (!str_in.empty()) // flush the string + { + str_in.erase(str_in.begin(), str_in.end()); + } -str_in.append(data_val); + str_in.append(data_val); } void DataElement::get(vector<string> &strvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; + long ptr; + if (!data_type) + return; -if (data_type != DATA_STR_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR")); + if (data_type != DATA_STR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR")); -ptr = 0; + ptr = 0; -while (ptr != data_size) { - strvect_in.push_back(string(data_val + ptr)); - ptr += strlen(data_val + ptr) + 1; -} + while (ptr != data_size) { + strvect_in.push_back(string(data_val + ptr)); + ptr += strlen(data_val + ptr) + 1; + } } void DataElement::get(std::set<string> &strset_in) throw (DataTypeMismatchException) { -if (!data_type) - return; + if (!data_type) + return; -if (data_type != DATA_STR_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR/SET")); + if (data_type != DATA_STR_VECTOR) + throw(new DataTypeMismatchException("Type mismatch, not a STRING VECTOR/SET")); -std::vector<string> tmp_vect; -std::vector<string>::iterator i; + std::vector<string> tmp_vect; + std::vector<string>::iterator i; -get(tmp_vect); + get(tmp_vect); -for (i = tmp_vect.begin(); i != tmp_vect.end(); i++) { - strset_in.insert(*i); -} + for (i = tmp_vect.begin(); i != tmp_vect.end(); i++) { + strset_in.insert(*i); + } } -void DataElement::get(vector<char>& charvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_CHAR_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - -ptr = 0; - -char temp_char; -while (ptr < data_size) { - temp_char = 0; - memcpy(&temp_char, data_val + ptr, sizeof(char)); - charvect_in.push_back(temp_char); - ptr += sizeof(char); -} +#define DataElementGetNumericVectorDef(enumtype, datatype, ...) void DataElement::get(vector<datatype>& val_out) throw (DataTypeMismatchException) { \ +if (!data_type || !unit_size) return; \ +if (data_type != enumtype) { \ + int _compat[] = {__VA_ARGS__}; \ + bool compat = false; \ + for (int i = 0; i < sizeof(_compat)/sizeof(int); i++) { \ + if (_compat[i] == data_type) { \ + compat = true; \ + break; \ + } \ + } \ + if (!compat) { \ + throw(new DataTypeMismatchException("Type mismatch, element type is not compatible with a " #datatype)); \ + } \ + if (sizeof(datatype) < unit_size) { \ + std::cout << "Warning, data type mismatch for vector<" #datatype ">; " #datatype " size " << sizeof(datatype) << " is less than unit size " << unit_size << "; possible loss of data."; \ + } \ + datatype temp_val; \ + long ptr = 0; \ + while (ptr < data_size) { \ + temp_val = 0; \ + memcpy(&temp_val, data_val + ptr, (unit_size > sizeof(datatype))?sizeof(datatype):unit_size); \ + val_out.push_back(temp_val); \ + ptr += unit_size; \ + } \ + return; \ + } \ + val_out.assign(data_val, data_val + (data_size / sizeof(datatype))); \ } -void DataElement::get(vector<unsigned char>& ucharvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; +DataElementGetNumericVectorDef(DATA_CHAR_VECTOR, char, DATA_UCHAR_VECTOR, DATA_INT_VECTOR, DATA_UINT_VECTOR, DATA_LONG_VECTOR, DATA_ULONG_VECTOR, + DATA_LONGLONG_VECTOR); +DataElementGetNumericVectorDef(DATA_UCHAR_VECTOR, unsigned char, DATA_CHAR_VECTOR, DATA_INT_VECTOR, DATA_UINT_VECTOR, DATA_LONG_VECTOR, + DATA_ULONG_VECTOR, DATA_LONGLONG_VECTOR); +DataElementGetNumericVectorDef(DATA_INT_VECTOR, int, DATA_CHAR_VECTOR, DATA_UCHAR_VECTOR, DATA_UINT_VECTOR, DATA_LONG_VECTOR, DATA_ULONG_VECTOR, + DATA_LONGLONG_VECTOR); +DataElementGetNumericVectorDef(DATA_UINT_VECTOR, unsigned int, DATA_CHAR_VECTOR, DATA_UCHAR_VECTOR, DATA_INT_VECTOR, DATA_LONG_VECTOR, + DATA_ULONG_VECTOR, DATA_LONGLONG_VECTOR); +DataElementGetNumericVectorDef(DATA_LONG_VECTOR, long, DATA_CHAR_VECTOR, DATA_UCHAR_VECTOR, DATA_INT_VECTOR, DATA_UINT_VECTOR, DATA_ULONG_VECTOR, + DATA_LONGLONG_VECTOR); +DataElementGetNumericVectorDef(DATA_ULONG_VECTOR, unsigned long, DATA_CHAR_VECTOR, DATA_UCHAR_VECTOR, DATA_INT_VECTOR, DATA_UINT_VECTOR, + DATA_LONG_VECTOR, DATA_LONGLONG_VECTOR); +DataElementGetNumericVectorDef(DATA_LONGLONG_VECTOR, long long, DATA_CHAR_VECTOR, DATA_UCHAR_VECTOR, DATA_INT_VECTOR, DATA_UINT_VECTOR, + DATA_LONG_VECTOR, DATA_ULONG_VECTOR); +DataElementGetNumericVectorDef(DATA_FLOAT_VECTOR, float, DATA_DOUBLE_VECTOR, DATA_LONGDOUBLE_VECTOR); +DataElementGetNumericVectorDef(DATA_DOUBLE_VECTOR, double, DATA_FLOAT_VECTOR, DATA_LONGDOUBLE_VECTOR); +DataElementGetNumericVectorDef(DATA_LONGDOUBLE_VECTOR, long double, DATA_DOUBLE_VECTOR, DATA_FLOAT_VECTOR); -if (data_type != DATA_UCHAR_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - -ptr = 0; - -unsigned char temp_char; -while (ptr < data_size) { - temp_char = 0; - memcpy(&temp_char, data_val + ptr, sizeof(unsigned char)); - ucharvect_in.push_back(temp_char); - ptr += sizeof(unsigned char); -} -} - -void DataElement::get(vector<unsigned int>& uintvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_UINT_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - -ptr = 0; - -unsigned int temp_char; -while (ptr < data_size) { - temp_char = 0; - memcpy(&temp_char, data_val + ptr, sizeof(unsigned int)); - uintvect_in.push_back(temp_char); - ptr += sizeof(unsigned int); -} -} - -void DataElement::get(vector<unsigned long>& ulongvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_ULONG_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - -ptr = 0; - -unsigned long temp_char; -while (ptr < data_size) { - temp_char = 0; - memcpy(&temp_char, data_val + ptr, sizeof(unsigned long)); - ulongvect_in.push_back(temp_char); - ptr += sizeof(unsigned long); -} -} - -void DataElement::get(vector<long long>& llongvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_LONGLONG_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - -ptr = 0; - -long long temp_char; -while (ptr < data_size) { - temp_char = 0; - memcpy(&temp_char, data_val + ptr, sizeof(long long)); - llongvect_in.push_back(temp_char); - ptr += sizeof(long long); -} -} - -void DataElement::get(vector<long double>& ldoublevect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_LONGDOUBLE_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - -ptr = 0; - -long double temp_char; -while (ptr < data_size) { - temp_char = 0; - memcpy(&temp_char, data_val + ptr, sizeof(long double)); - ldoublevect_in.push_back(temp_char); - ptr += sizeof(long double); -} -} - -void DataElement::get(vector<int> &intvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_INT_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a INT VECTOR")); - -ptr = 0; - -int temp_int; -while (ptr < data_size) { - temp_int = 0; - memcpy(&temp_int, data_val + ptr, sizeof(int)); - intvect_in.push_back(temp_int); - ptr += sizeof(int); -} -} - -void DataElement::get(vector<long> &longvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_LONG_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a LONG VECTOR")); - -ptr = 0; - -long temp_long; -while (ptr < data_size) { - temp_long = 0; - memcpy(&temp_long, data_val + ptr, sizeof(long)); - longvect_in.push_back(temp_long); - ptr += sizeof(long); -} -} - -void DataElement::get(vector<float> &floatvect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_FLOAT_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a FLOAT VECTOR")); - -ptr = 0; - -float temp_float; -while (ptr < data_size) { - temp_float = 0; - memcpy(&temp_float, data_val + ptr, sizeof(float)); - floatvect_in.push_back(temp_float); - ptr += sizeof(float); -} -} - -void DataElement::get(vector<double> &doublevect_in) throw (DataTypeMismatchException) { -long ptr; -if (!data_type) - return; - -if (data_type != DATA_DOUBLE_VECTOR) - throw(new DataTypeMismatchException("Type mismatch, not a DOUBLE VECTOR")); - -ptr = 0; - -double temp_double; - -while (ptr < data_size) { - temp_double = 0; - memcpy(&temp_double, data_val + ptr, sizeof(double)); - doublevect_in.push_back(temp_double); - ptr += sizeof(double); -} -} long DataElement::getSerializedSize() { -return sizeof(unsigned char) + sizeof(unsigned int) + data_size; + return sizeof(unsigned char) + sizeof(unsigned int) + data_size; } long DataElement::getSerialized(char **ser_str) { -long ser_size = getSerializedSize(); + long ser_size = getSerializedSize(); -*ser_str = new char[ser_size]; + *ser_str = new char[ser_size]; -char *ser_pointer; + char *ser_pointer; -ser_pointer = *ser_str; + ser_pointer = *ser_str; -memcpy(ser_pointer, &data_type, sizeof(unsigned char)); -ser_pointer += sizeof(unsigned char); -memcpy(ser_pointer, &data_size, sizeof(unsigned int)); -ser_pointer += sizeof(unsigned int); -memcpy(ser_pointer, data_val, data_size); + memcpy(ser_pointer, &data_type, sizeof(unsigned char)); + ser_pointer += sizeof(unsigned char); + memcpy(ser_pointer, &data_size, sizeof(unsigned int)); + ser_pointer += sizeof(unsigned int); + memcpy(ser_pointer, data_val, data_size); -return ser_size; + return ser_size; } void DataElement::setSerialized(char *ser_str) { -char *ser_pointer = ser_str; + char *ser_pointer = ser_str; -memcpy(&data_type, ser_pointer, sizeof(unsigned char)); -ser_pointer += sizeof(unsigned char); -memcpy(&data_size, ser_pointer, sizeof(unsigned int)); -ser_pointer += sizeof(unsigned int); + memcpy(&data_type, ser_pointer, sizeof(unsigned char)); + ser_pointer += sizeof(unsigned char); + memcpy(&data_size, ser_pointer, sizeof(unsigned int)); + ser_pointer += sizeof(unsigned int); -data_init(data_size); -memcpy(data_val, ser_pointer, data_size); + data_init(data_size); + memcpy(data_val, ser_pointer, data_size); } /* DataNode class */ DataNode::DataNode() { -ptr = 0; -parentNode = NULL; + ptr = 0; + parentNode = NULL; } DataNode::DataNode(const char *name_in) { -ptr = 0; -node_name = name_in; -parentNode = NULL; + ptr = 0; + node_name = name_in; + parentNode = NULL; } DataNode::~DataNode() { -for (vector<DataNode *>::iterator i = children.begin(); i != children.end(); i++) { - delete *i; -} + for (vector<DataNode *>::iterator i = children.begin(); i != children.end(); i++) { + delete *i; + } } void DataNode::setName(const char *name_in) { -node_name = name_in; + node_name = name_in; } DataElement & DataNode::element() { -return data_elem; + return data_elem; } DataNode &DataNode::newChild(const char *name_in) { -children.push_back(new DataNode(name_in)); -childmap[name_in].push_back(children.back()); + children.push_back(new DataNode(name_in)); + childmap[name_in].push_back(children.back()); -children.back()->setParentNode(*this); + children.back()->setParentNode(*this); -return *children.back(); + return *children.back(); } DataNode &DataNode::child(const char *name_in, int index) throw (DataInvalidChildException) { -DataNode *child_ret; + DataNode *child_ret; -child_ret = childmap[name_in][index]; + child_ret = childmap[name_in][index]; -if (!child_ret) { - stringstream error_str; - error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; - throw(DataInvalidChildException(error_str.str().c_str())); -} + if (!child_ret) { + stringstream error_str; + error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; + throw(DataInvalidChildException(error_str.str().c_str())); + } -return *child_ret; + return *child_ret; } DataNode &DataNode::child(int index) throw (DataInvalidChildException) { -DataNode *child_ret; + DataNode *child_ret; -child_ret = children[index]; + child_ret = children[index]; -if (!child_ret) { - stringstream error_str; - error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; - throw(DataInvalidChildException(error_str.str().c_str())); -} + if (!child_ret) { + stringstream error_str; + error_str << "no child '" << index << "' in DataNode '" << node_name << "'"; + throw(DataInvalidChildException(error_str.str().c_str())); + } -return *child_ret; + return *child_ret; } int DataNode::numChildren() { -return children.size(); + return children.size(); } int DataNode::numChildren(const char *name_in) { -return childmap[name_in].size(); + return childmap[name_in].size(); } bool DataNode::hasAnother() { -return children.size() != ptr; + return children.size() != ptr; } bool DataNode::hasAnother(const char *name_in) { -return childmap[name_in].size() != childmap_ptr[name_in]; + return childmap[name_in].size() != childmap_ptr[name_in]; } DataNode & DataNode::getNext() throw (DataInvalidChildException) { -return child(ptr++); + return child(ptr++); } DataNode &DataNode::getNext(const char *name_in) throw (DataInvalidChildException) { -return child(name_in, childmap_ptr[name_in]++); + return child(name_in, childmap_ptr[name_in]++); } void DataNode::rewind() { -ptr = 0; + ptr = 0; } void DataNode::rewind(const char *name_in) { -childmap_ptr[name_in] = 0; + childmap_ptr[name_in] = 0; } /* DataTree class */ DataTree::DataTree(const char *name_in) { -dn_root.setName(name_in); + dn_root.setName(name_in); } DataTree::DataTree() { @@ -882,941 +446,941 @@ DataTree::~DataTree() { ; DataNode & DataTree::rootNode() { -return dn_root; + return dn_root; } std::string trim(std::string& s, const std::string& drop = " ") { -std::string r = s.erase(s.find_last_not_of(drop) + 1); -return r.erase(0, r.find_first_not_of(drop)); + std::string r = s.erase(s.find_last_not_of(drop) + 1); + return r.erase(0, r.find_first_not_of(drop)); } void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPointPolicy fpp) { -int tmp_char; -int tmp_int; -long tmp_long; -long long tmp_llong; -double tmp_double; -float tmp_float; -string tmp_str; -string tmp_str2; -std::stringstream tmp_stream; -std::stringstream tmp_stream2; + int tmp_char; + int tmp_int; + long tmp_long; + long long tmp_llong; + double tmp_double; + float tmp_float; + string tmp_str; + string tmp_str2; + std::stringstream tmp_stream; + std::stringstream tmp_stream2; -vector<char> tmp_charvect; -vector<int> tmp_intvect; -vector<long> tmp_longvect; -vector<long> tmp_llongvect; -vector<long>::iterator tmp_llongvect_i; -vector<double> tmp_doublevect; -vector<double>::iterator tmp_doublevect_i; -vector<float> tmp_floatvect; + vector<char> tmp_charvect; + vector<int> tmp_intvect; + vector<long> tmp_longvect; + vector<long> tmp_llongvect; + vector<long>::iterator tmp_llongvect_i; + vector<double> tmp_doublevect; + vector<double>::iterator tmp_doublevect_i; + vector<float> tmp_floatvect; -bool vChars = false; -bool vInts = false; -bool vLongs = false; + bool vChars = false; + bool vInts = false; + bool vLongs = false; -string in_text = src_text; + string in_text = src_text; -trim(in_text); -trim(in_text, "\r\n"); -tmp_stream.str(""); -tmp_stream2.str(""); + trim(in_text); + trim(in_text, "\r\n"); + tmp_stream.str(""); + tmp_stream2.str(""); -if (in_text.find_first_not_of("0123456789-") == string::npos) { - tmp_stream << in_text; - tmp_stream >> tmp_llong; - - tmp_int = tmp_llong; - tmp_long = tmp_llong; - - if (tmp_int == tmp_llong) { - elem->element().set((int) tmp_int); - } else if (tmp_long == tmp_llong) { - elem->element().set((long) tmp_int); - } else { - elem->element().set((long long) tmp_long); - } -} else if (in_text.find_first_not_of("0123456789.e+-") == string::npos) { - tmp_stream << in_text; - - if (fpp == USE_FLOAT) { - tmp_stream >> tmp_float; - - elem->element().set((float) tmp_float); - } else { - tmp_stream >> tmp_double; - - elem->element().set((double) tmp_double); - } -} else if (in_text.find_first_not_of("0123456789- ") == string::npos) { - tmp_stream << in_text; - - vChars = true; - vInts = true; - vLongs = true; - - while (!tmp_stream.eof()) { + if (in_text.find_first_not_of("0123456789-") == string::npos) { + tmp_stream << in_text; tmp_stream >> tmp_llong; - tmp_char = tmp_llong; + tmp_int = tmp_llong; tmp_long = tmp_llong; - if (tmp_char != tmp_llong) { - vChars = false; - } - if (tmp_int != tmp_llong) { - vInts = false; - } - if (tmp_long != tmp_llong) { - vLongs = false; - } - tmp_llongvect.push_back((long) tmp_long); - } - if (vChars) { - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_charvect.push_back(*tmp_llongvect_i); + if (tmp_int == tmp_llong) { + elem->element().set((int) tmp_int); + } else if (tmp_long == tmp_llong) { + elem->element().set((long) tmp_int); + } else { + elem->element().set((long long) tmp_long); } - tmp_llongvect.clear(); - elem->element().set(tmp_charvect); - tmp_charvect.clear(); - - } else if (vInts) { - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_intvect.push_back(*tmp_llongvect_i); - } - tmp_llongvect.clear(); - elem->element().set(tmp_intvect); - tmp_intvect.clear(); - } else if (vLongs) { - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_longvect.push_back(*tmp_llongvect_i); - } - tmp_llongvect.clear(); - elem->element().set(tmp_longvect); - tmp_longvect.clear(); - } else { - elem->element().set(tmp_llongvect); - } -} else if (in_text.find_first_not_of("0123456789.e-+ ") == string::npos) { - tmp_stream << in_text; - - if (fpp == USE_FLOAT) { - tmp_floatvect.clear(); - } else { - tmp_doublevect.clear(); - } - - while (!tmp_stream.eof()) { + } else if (in_text.find_first_not_of("0123456789.e+-") == string::npos) { + tmp_stream << in_text; if (fpp == USE_FLOAT) { tmp_stream >> tmp_float; - tmp_floatvect.push_back(tmp_float); + + elem->element().set((float) tmp_float); } else { tmp_stream >> tmp_double; - tmp_doublevect.push_back(tmp_double); - } - } - if (fpp == USE_FLOAT) { - elem->element().set(tmp_floatvect); + elem->element().set((double) tmp_double); + } + } else if (in_text.find_first_not_of("0123456789- ") == string::npos) { + tmp_stream << in_text; + + vChars = true; + vInts = true; + vLongs = true; + + while (!tmp_stream.eof()) { + tmp_stream >> tmp_llong; + tmp_char = tmp_llong; + tmp_int = tmp_llong; + tmp_long = tmp_llong; + if (tmp_char != tmp_llong) { + vChars = false; + } + if (tmp_int != tmp_llong) { + vInts = false; + } + if (tmp_long != tmp_llong) { + vLongs = false; + } + tmp_llongvect.push_back((long) tmp_long); + } + + if (vChars) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_charvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_charvect); + tmp_charvect.clear(); + + } else if (vInts) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_intvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_intvect); + tmp_intvect.clear(); + } else if (vLongs) { + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_longvect.push_back(*tmp_llongvect_i); + } + tmp_llongvect.clear(); + elem->element().set(tmp_longvect); + tmp_longvect.clear(); + } else { + elem->element().set(tmp_llongvect); + } + } else if (in_text.find_first_not_of("0123456789.e-+ ") == string::npos) { + tmp_stream << in_text; + + if (fpp == USE_FLOAT) { + tmp_floatvect.clear(); + } else { + tmp_doublevect.clear(); + } + + while (!tmp_stream.eof()) { + + if (fpp == USE_FLOAT) { + tmp_stream >> tmp_float; + tmp_floatvect.push_back(tmp_float); + } else { + tmp_stream >> tmp_double; + tmp_doublevect.push_back(tmp_double); + } + } + + if (fpp == USE_FLOAT) { + elem->element().set(tmp_floatvect); + } else { + elem->element().set(tmp_doublevect); + } } else { - elem->element().set(tmp_doublevect); + elem->element().set(src_text); + // printf( "Unhandled DataTree XML Field: [%s]", tmp_str.c_str() ); } -} else { - elem->element().set(src_text); - // printf( "Unhandled DataTree XML Field: [%s]", tmp_str.c_str() ); -} } void DataTree::setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node, DT_FloatingPointPolicy fpp) { -TiXmlText *pText; -int t = elxml->Type(); -string tmp_str; + TiXmlText *pText; + int t = elxml->Type(); + string tmp_str; -switch (t) { -case TiXmlNode::DOCUMENT: - // printf( "Document" ); - break; + switch (t) { + case TiXmlNode::DOCUMENT: + // printf( "Document" ); + break; -case TiXmlNode::ELEMENT: - if (!root_node) - elem = &elem->newChild(elxml->Value()); + case TiXmlNode::ELEMENT: + if (!root_node) + elem = &elem->newChild(elxml->Value()); - const TiXmlAttribute *attribs; - attribs = elxml->ToElement()->FirstAttribute(); + const TiXmlAttribute *attribs; + attribs = elxml->ToElement()->FirstAttribute(); - while (attribs) { + while (attribs) { - // following badgerfish xml->json and xml->ruby convention for attributes.. - string attrName("@"); - attrName.append(attribs->Name()); +// following badgerfish xml->json and xml->ruby convention for attributes.. + string attrName("@"); + attrName.append(attribs->Name()); - decodeXMLText(&elem->newChild(attrName.c_str()), attribs->Value(), fpp); + decodeXMLText(&elem->newChild(attrName.c_str()), attribs->Value(), fpp); - attribs = attribs->Next(); + attribs = attribs->Next(); + } + + // printf( "Element \"%s\"", elxml->Value()); + break; + + case TiXmlNode::COMMENT: +// printf( "Comment: \"%s\"", elxml->Value()); + break; + + case TiXmlNode::UNKNOWN: +// printf( "Unknown" ); + break; + + case TiXmlNode::TEXT: + pText = elxml->ToText(); + + decodeXMLText(elem, pText->Value(), fpp); + +// pText = elxml->ToText(); +// printf( "Text: [%s]", pText->Value() ); + break; + + case TiXmlNode::DECLARATION: +// printf( "Declaration" ); + break; + default: + break; } - // printf( "Element \"%s\"", elxml->Value()); - break; - -case TiXmlNode::COMMENT: - // printf( "Comment: \"%s\"", elxml->Value()); - break; - -case TiXmlNode::UNKNOWN: - // printf( "Unknown" ); - break; - -case TiXmlNode::TEXT: - pText = elxml->ToText(); - - decodeXMLText(elem, pText->Value(), fpp); - - // pText = elxml->ToText(); - // printf( "Text: [%s]", pText->Value() ); - break; - -case TiXmlNode::DECLARATION: - // printf( "Declaration" ); - break; -default: - break; -} - // printf( "\n" ); -TiXmlNode * pChild; + TiXmlNode * pChild; -if (!elxml->NoChildren()) { - if (elxml->FirstChild()->Type() == TiXmlNode::ELEMENT) { - if (elxml->FirstChild()->Value() == TIXML_STRING("str")) { - std::vector<std::string> tmp_strvect; + if (!elxml->NoChildren()) { + if (elxml->FirstChild()->Type() == TiXmlNode::ELEMENT) { + if (elxml->FirstChild()->Value() == TIXML_STRING("str")) { + std::vector<std::string> tmp_strvect; - for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { - if (pChild->Value() == TIXML_STRING("str")) { - if (!pChild->FirstChild()) { - tmp_strvect.push_back(""); - continue; - } + for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { + if (pChild->Value() == TIXML_STRING("str")) { + if (!pChild->FirstChild()) { + tmp_strvect.push_back(""); + continue; + } - pText = pChild->FirstChild()->ToText(); + pText = pChild->FirstChild()->ToText(); - if (pText) { - tmp_str = pText->Value(); - tmp_strvect.push_back(tmp_str); + if (pText) { + tmp_str = pText->Value(); + tmp_strvect.push_back(tmp_str); + } } } + + elem->element().set(tmp_strvect); + + return; } - - elem->element().set(tmp_strvect); - - return; } } -} -for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { - setFromXML(elem, pChild, false, fpp); -} + for (pChild = elxml->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { + setFromXML(elem, pChild, false, fpp); + } } void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { -DataNode *child; + DataNode *child; -elem->rewind(); + elem->rewind(); -while (elem->hasAnother()) { - child = &elem->getNext(); + while (elem->hasAnother()) { + child = &elem->getNext(); - std::string nodeName = child->getName(); + std::string nodeName = child->getName(); - TiXmlElement *element; + TiXmlElement *element; - element = new TiXmlElement(nodeName.length() ? nodeName.c_str() : "node"); - std::string tmp; - std::stringstream tmp_stream; - TiXmlText *text; - std::vector<float> tmp_floatvect; - std::vector<float>::iterator tmp_floatvect_i; - std::vector<double> tmp_doublevect; - std::vector<double>::iterator tmp_doublevect_i; - std::vector<int> tmp_intvect; - std::vector<int>::iterator tmp_intvect_i; - std::vector<char> tmp_charvect; - std::vector<char>::iterator tmp_charvect_i; - std::vector<unsigned char> tmp_ucharvect; - std::vector<unsigned char>::iterator tmp_ucharvect_i; - std::vector<unsigned int> tmp_uintvect; - std::vector<unsigned int>::iterator tmp_uintvect_i; - std::vector<long> tmp_longvect; - std::vector<long>::iterator tmp_longvect_i; - std::vector<unsigned long> tmp_ulongvect; - std::vector<unsigned long>::iterator tmp_ulongvect_i; - std::vector<long long> tmp_llongvect; - std::vector<long long>::iterator tmp_llongvect_i; - std::vector<unsigned long long> tmp_ullongvect; - std::vector<unsigned long long>::iterator tmp_ullongvect_i; - std::vector<string> tmp_stringvect; - std::vector<string>::iterator tmp_stringvect_i; - TiXmlElement *tmp_node; - char *tmp_pstr; - double tmp_double; - long double tmp_ldouble; - float tmp_float; - char tmp_char; - unsigned char tmp_uchar; - int tmp_int; - unsigned int tmp_uint; - long tmp_long; - unsigned long tmp_ulong; - long long tmp_llong; + element = new TiXmlElement(nodeName.length() ? nodeName.c_str() : "node"); + std::string tmp; + std::stringstream tmp_stream; + TiXmlText *text; + std::vector<float> tmp_floatvect; + std::vector<float>::iterator tmp_floatvect_i; + std::vector<double> tmp_doublevect; + std::vector<double>::iterator tmp_doublevect_i; + std::vector<int> tmp_intvect; + std::vector<int>::iterator tmp_intvect_i; + std::vector<char> tmp_charvect; + std::vector<char>::iterator tmp_charvect_i; + std::vector<unsigned char> tmp_ucharvect; + std::vector<unsigned char>::iterator tmp_ucharvect_i; + std::vector<unsigned int> tmp_uintvect; + std::vector<unsigned int>::iterator tmp_uintvect_i; + std::vector<long> tmp_longvect; + std::vector<long>::iterator tmp_longvect_i; + std::vector<unsigned long> tmp_ulongvect; + std::vector<unsigned long>::iterator tmp_ulongvect_i; + std::vector<long long> tmp_llongvect; + std::vector<long long>::iterator tmp_llongvect_i; + std::vector<unsigned long long> tmp_ullongvect; + std::vector<unsigned long long>::iterator tmp_ullongvect_i; + std::vector<string> tmp_stringvect; + std::vector<string>::iterator tmp_stringvect_i; + TiXmlElement *tmp_node; + char *tmp_pstr; + double tmp_double; + long double tmp_ldouble; + float tmp_float; + char tmp_char; + unsigned char tmp_uchar; + int tmp_int; + unsigned int tmp_uint; + long tmp_long; + unsigned long tmp_ulong; + long long tmp_llong; - switch (child->element().getDataType()) { - case DATA_NULL: - break; - case DATA_VOID: - child->element().get(&tmp_pstr); - // following badgerfish xml->json and xml->ruby convention for attributes.. - if (nodeName.substr(0, 1) == string("@")) { - elxml->SetAttribute(nodeName.substr(1).c_str(), tmp_pstr); - delete element; - element = NULL; - } else { - text = new TiXmlText(tmp_pstr); + switch (child->element().getDataType()) { + case DATA_NULL: + break; + case DATA_VOID: + child->element().get(&tmp_pstr); +// following badgerfish xml->json and xml->ruby convention for attributes.. + if (nodeName.substr(0, 1) == string("@")) { + elxml->SetAttribute(nodeName.substr(1).c_str(), tmp_pstr); + delete element; + element = NULL; + } else { + text = new TiXmlText(tmp_pstr); + element->LinkEndChild(text); + } + delete tmp_pstr; + break; + case DATA_CHAR: + child->element().get(tmp_char); + + tmp_stream.str(""); + + tmp_stream << tmp_char; + + text = new TiXmlText(tmp_stream.str().c_str()); element->LinkEndChild(text); - } - delete tmp_pstr; - break; - case DATA_CHAR: - child->element().get(tmp_char); + break; + case DATA_UCHAR: + child->element().get(tmp_uchar); - tmp_stream.str(""); + tmp_stream.str(""); - tmp_stream << tmp_char; + tmp_stream << tmp_uchar; - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_UCHAR: - child->element().get(tmp_uchar); - - tmp_stream.str(""); - - tmp_stream << tmp_uchar; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_INT: - child->element().get(tmp_int); - - tmp_stream.str(""); - - tmp_stream << tmp_int; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_UINT: - child->element().get(tmp_uint); - - tmp_stream.str(""); - - tmp_stream << tmp_uint; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_LONG: - child->element().get(tmp_long); - - tmp_stream.str(""); - - tmp_stream << tmp_long; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_ULONG: - child->element().get(tmp_ulong); - - tmp_stream.str(""); - - tmp_stream << tmp_ulong; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_LONGLONG: - child->element().get(tmp_llong); - - tmp_stream.str(""); - - tmp_stream << tmp_llong; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_FLOAT: - child->element().get(tmp_float); - - tmp_stream.str(""); - - tmp_stream << tmp_float; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_DOUBLE: - child->element().get(tmp_double); - - tmp_stream.str(""); - - tmp_stream << tmp_double; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_LONGDOUBLE: - child->element().get(tmp_ldouble); - - tmp_stream.str(""); - - tmp_stream << tmp_ldouble; - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - break; - case DATA_STRING: - child->element().get(tmp); - if (nodeName.substr(0, 1) == string("@")) { - elxml->SetAttribute(nodeName.substr(1).c_str(), tmp.c_str()); - delete element; - element = NULL; - } else { - text = new TiXmlText(tmp.c_str()); + text = new TiXmlText(tmp_stream.str().c_str()); element->LinkEndChild(text); - } - break; + break; + case DATA_INT: + child->element().get(tmp_int); - case DATA_STR_VECTOR: - child->element().get(tmp_stringvect); + tmp_stream.str(""); - tmp_stream.str(""); + tmp_stream << tmp_int; - for (tmp_stringvect_i = tmp_stringvect.begin(); tmp_stringvect_i != tmp_stringvect.end(); tmp_stringvect_i++) { - tmp_node = new TiXmlElement("str"); - text = new TiXmlText((*tmp_stringvect_i).c_str()); - tmp_node->LinkEndChild(text); - element->LinkEndChild(tmp_node); + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_UINT: + child->element().get(tmp_uint); + + tmp_stream.str(""); + + tmp_stream << tmp_uint; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONG: + child->element().get(tmp_long); + + tmp_stream.str(""); + + tmp_stream << tmp_long; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_ULONG: + child->element().get(tmp_ulong); + + tmp_stream.str(""); + + tmp_stream << tmp_ulong; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONGLONG: + child->element().get(tmp_llong); + + tmp_stream.str(""); + + tmp_stream << tmp_llong; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_FLOAT: + child->element().get(tmp_float); + + tmp_stream.str(""); + + tmp_stream << tmp_float; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_DOUBLE: + child->element().get(tmp_double); + + tmp_stream.str(""); + + tmp_stream << tmp_double; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_LONGDOUBLE: + child->element().get(tmp_ldouble); + + tmp_stream.str(""); + + tmp_stream << tmp_ldouble; + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + break; + case DATA_STRING: + child->element().get(tmp); + if (nodeName.substr(0, 1) == string("@")) { + elxml->SetAttribute(nodeName.substr(1).c_str(), tmp.c_str()); + delete element; + element = NULL; + } else { + text = new TiXmlText(tmp.c_str()); + element->LinkEndChild(text); + } + break; + + case DATA_STR_VECTOR: + child->element().get(tmp_stringvect); + + tmp_stream.str(""); + + for (tmp_stringvect_i = tmp_stringvect.begin(); tmp_stringvect_i != tmp_stringvect.end(); tmp_stringvect_i++) { + tmp_node = new TiXmlElement("str"); + text = new TiXmlText((*tmp_stringvect_i).c_str()); + tmp_node->LinkEndChild(text); + element->LinkEndChild(tmp_node); + } + + tmp_stringvect.clear(); + break; + case DATA_CHAR_VECTOR: + child->element().get(tmp_charvect); + + tmp_stream.str(""); + + for (tmp_charvect_i = tmp_charvect.begin(); tmp_charvect_i != tmp_charvect.end(); tmp_charvect_i++) { + tmp_stream << (*tmp_charvect_i); + if (tmp_charvect_i != tmp_charvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_charvect.clear(); + break; + case DATA_UCHAR_VECTOR: + child->element().get(tmp_ucharvect); + + tmp_stream.str(""); + + for (tmp_ucharvect_i = tmp_ucharvect.begin(); tmp_ucharvect_i != tmp_ucharvect.end(); tmp_ucharvect_i++) { + tmp_stream << (*tmp_ucharvect_i); + if (tmp_ucharvect_i != tmp_ucharvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_ucharvect.clear(); + break; + case DATA_INT_VECTOR: + child->element().get(tmp_intvect); + + tmp_stream.str(""); + + for (tmp_intvect_i = tmp_intvect.begin(); tmp_intvect_i != tmp_intvect.end(); tmp_intvect_i++) { + tmp_stream << (*tmp_intvect_i); + if (tmp_intvect_i != tmp_intvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_intvect.clear(); + break; + case DATA_UINT_VECTOR: + child->element().get(tmp_uintvect); + + tmp_stream.str(""); + + for (tmp_uintvect_i = tmp_uintvect.begin(); tmp_uintvect_i != tmp_uintvect.end(); tmp_uintvect_i++) { + tmp_stream << (*tmp_intvect_i); + if (tmp_uintvect_i != tmp_uintvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_uintvect.clear(); + break; + case DATA_LONG_VECTOR: + child->element().get(tmp_longvect); + + tmp_stream.str(""); + + for (tmp_longvect_i = tmp_longvect.begin(); tmp_longvect_i != tmp_longvect.end(); tmp_longvect_i++) { + tmp_stream << (*tmp_longvect_i); + if (tmp_longvect_i != tmp_longvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_longvect.clear(); + break; + case DATA_ULONG_VECTOR: + child->element().get(tmp_ulongvect); + + tmp_stream.str(""); + + for (tmp_ulongvect_i = tmp_ulongvect.begin(); tmp_ulongvect_i != tmp_ulongvect.end(); tmp_ulongvect_i++) { + tmp_stream << (*tmp_ulongvect_i); + if (tmp_ulongvect_i != tmp_ulongvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_ulongvect.clear(); + break; + case DATA_LONGLONG_VECTOR: + child->element().get(tmp_llongvect); + + tmp_stream.str(""); + + for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { + tmp_stream << (*tmp_llongvect_i); + if (tmp_llongvect_i != tmp_llongvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_llongvect.clear(); + break; + case DATA_FLOAT_VECTOR: + child->element().get(tmp_floatvect); + + tmp_stream.str(""); + + for (tmp_floatvect_i = tmp_floatvect.begin(); tmp_floatvect_i != tmp_floatvect.end(); tmp_floatvect_i++) { + tmp_stream << (*tmp_floatvect_i); + if (tmp_floatvect_i != tmp_floatvect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_floatvect.clear(); + break; + case DATA_DOUBLE_VECTOR: + child->element().get(tmp_doublevect); + + tmp_stream.str(""); + + for (tmp_doublevect_i = tmp_doublevect.begin(); tmp_doublevect_i != tmp_doublevect.end(); tmp_doublevect_i++) { + tmp_stream << (*tmp_doublevect_i); + if (tmp_doublevect_i != tmp_doublevect.end() - 1) + tmp_stream << " "; + } + + text = new TiXmlText(tmp_stream.str().c_str()); + element->LinkEndChild(text); + tmp_doublevect.clear(); + break; } - tmp_stringvect.clear(); - break; - case DATA_CHAR_VECTOR: - child->element().get(tmp_charvect); + if (element) { + elxml->LinkEndChild(element); - tmp_stream.str(""); - - for (tmp_charvect_i = tmp_charvect.begin(); tmp_charvect_i != tmp_charvect.end(); tmp_charvect_i++) { - tmp_stream << (*tmp_charvect_i); - if (tmp_charvect_i != tmp_charvect.end() - 1) - tmp_stream << " "; + if (child->numChildren()) { + nodeToXML(child, element); + } } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_charvect.clear(); - break; - case DATA_UCHAR_VECTOR: - child->element().get(tmp_ucharvect); - - tmp_stream.str(""); - - for (tmp_ucharvect_i = tmp_ucharvect.begin(); tmp_ucharvect_i != tmp_ucharvect.end(); tmp_ucharvect_i++) { - tmp_stream << (*tmp_ucharvect_i); - if (tmp_ucharvect_i != tmp_ucharvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_ucharvect.clear(); - break; - case DATA_INT_VECTOR: - child->element().get(tmp_intvect); - - tmp_stream.str(""); - - for (tmp_intvect_i = tmp_intvect.begin(); tmp_intvect_i != tmp_intvect.end(); tmp_intvect_i++) { - tmp_stream << (*tmp_intvect_i); - if (tmp_intvect_i != tmp_intvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_intvect.clear(); - break; - case DATA_UINT_VECTOR: - child->element().get(tmp_uintvect); - - tmp_stream.str(""); - - for (tmp_uintvect_i = tmp_uintvect.begin(); tmp_uintvect_i != tmp_uintvect.end(); tmp_uintvect_i++) { - tmp_stream << (*tmp_intvect_i); - if (tmp_uintvect_i != tmp_uintvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_uintvect.clear(); - break; - case DATA_LONG_VECTOR: - child->element().get(tmp_longvect); - - tmp_stream.str(""); - - for (tmp_longvect_i = tmp_longvect.begin(); tmp_longvect_i != tmp_longvect.end(); tmp_longvect_i++) { - tmp_stream << (*tmp_longvect_i); - if (tmp_longvect_i != tmp_longvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_longvect.clear(); - break; - case DATA_ULONG_VECTOR: - child->element().get(tmp_ulongvect); - - tmp_stream.str(""); - - for (tmp_ulongvect_i = tmp_ulongvect.begin(); tmp_ulongvect_i != tmp_ulongvect.end(); tmp_ulongvect_i++) { - tmp_stream << (*tmp_ulongvect_i); - if (tmp_ulongvect_i != tmp_ulongvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_ulongvect.clear(); - break; - case DATA_LONGLONG_VECTOR: - child->element().get(tmp_llongvect); - - tmp_stream.str(""); - - for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { - tmp_stream << (*tmp_llongvect_i); - if (tmp_llongvect_i != tmp_llongvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_llongvect.clear(); - break; - case DATA_FLOAT_VECTOR: - child->element().get(tmp_floatvect); - - tmp_stream.str(""); - - for (tmp_floatvect_i = tmp_floatvect.begin(); tmp_floatvect_i != tmp_floatvect.end(); tmp_floatvect_i++) { - tmp_stream << (*tmp_floatvect_i); - if (tmp_floatvect_i != tmp_floatvect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_floatvect.clear(); - break; - case DATA_DOUBLE_VECTOR: - child->element().get(tmp_doublevect); - - tmp_stream.str(""); - - for (tmp_doublevect_i = tmp_doublevect.begin(); tmp_doublevect_i != tmp_doublevect.end(); tmp_doublevect_i++) { - tmp_stream << (*tmp_doublevect_i); - if (tmp_doublevect_i != tmp_doublevect.end() - 1) - tmp_stream << " "; - } - - text = new TiXmlText(tmp_stream.str().c_str()); - element->LinkEndChild(text); - tmp_doublevect.clear(); - break; } - if (element) { - elxml->LinkEndChild(element); - - if (child->numChildren()) { - nodeToXML(child, element); - } - } -} - -elem->rewind(); + elem->rewind(); } void DataTree::printXML() /* get serialized size + return node names header */ { -TiXmlDocument doc; -TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); -doc.LinkEndChild(decl); + TiXmlDocument doc; + TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); + doc.LinkEndChild(decl); -DataNode *root = &rootNode(); + DataNode *root = &rootNode(); -string rootName = root->getName(); + string rootName = root->getName(); -TiXmlElement *element = new TiXmlElement(rootName.empty() ? "root" : rootName.c_str()); -doc.LinkEndChild(element); + TiXmlElement *element = new TiXmlElement(rootName.empty() ? "root" : rootName.c_str()); + doc.LinkEndChild(element); + + if (!root->numChildren()) + doc.Print(); + + nodeToXML(root, element); + + root->rewind(); -if (!root->numChildren()) doc.Print(); - -nodeToXML(root, element); - -root->rewind(); - -doc.Print(); } long DataTree::getSerializedSize(DataElement &de_node_names, bool debug) /* get serialized size + return node names header */ { -long total_size = 0; + long total_size = 0; -stack<DataNode *> dn_stack; -vector<string> node_names; -map<string, int, string_less> node_name_index_map; + stack<DataNode *> dn_stack; + vector<string> node_names; + map<string, int, string_less> node_name_index_map; -DataElement de_name_index; // just used for sizing purposes -DataElement de_num_children; + DataElement de_name_index; // just used for sizing purposes + DataElement de_num_children; -de_name_index.set((int) 0); -de_num_children.set((int) 0); + de_name_index.set((int) 0); + de_num_children.set((int) 0); -int de_name_index_size = de_name_index.getSerializedSize(); -int de_num_children_size = de_num_children.getSerializedSize(); + int de_name_index_size = de_name_index.getSerializedSize(); + int de_num_children_size = de_num_children.getSerializedSize(); -dn_stack.push(&dn_root); + dn_stack.push(&dn_root); -while (!dn_stack.empty()) { - int name_index; - // int num_children; + while (!dn_stack.empty()) { + int name_index; + // int num_children; - /* build the name list */ - if (dn_stack.top()->getName().empty()) { - name_index = 0; /* empty string */ - } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { - node_names.push_back(string(dn_stack.top()->getName())); - name_index = node_names.size(); - node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; - } else { - name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; - } - - /* add on the size of the name index and number of children */ - total_size += de_name_index_size; - total_size += de_num_children_size; - total_size += dn_stack.top()->element().getSerializedSize(); - - /* debug output */ - if (debug) { - for (unsigned int i = 0; i < dn_stack.size() - 1; i++) - cout << "--"; - cout << (dn_stack.top()->getName().empty() ? "NULL" : dn_stack.top()->getName()) << "(" << dn_stack.top()->element().getSerializedSize() - << ")"; - cout << " type: " << dn_stack.top()->element().getDataType() << endl; - //cout << " index: " << name_index << endl; - } - /* end debug output */ - - /* if it has children, traverse into them */ - if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } else { - /* no more children, back out until we have children, then add next child to the top */ - while (!dn_stack.empty()) { - if (!dn_stack.top()->hasAnother()) { - dn_stack.top()->rewind(); - dn_stack.pop(); - } else - break; + /* build the name list */ + if (dn_stack.top()->getName().empty()) { + name_index = 0; /* empty string */ + } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { + node_names.push_back(string(dn_stack.top()->getName())); + name_index = node_names.size(); + node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; + } else { + name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; } - if (!dn_stack.empty()) { + /* add on the size of the name index and number of children */ + total_size += de_name_index_size; + total_size += de_num_children_size; + total_size += dn_stack.top()->element().getSerializedSize(); + + /* debug output */ + if (debug) { + for (unsigned int i = 0; i < dn_stack.size() - 1; i++) + cout << "--"; + cout << (dn_stack.top()->getName().empty() ? "NULL" : dn_stack.top()->getName()) << "(" << dn_stack.top()->element().getSerializedSize() + << ")"; + cout << " type: " << dn_stack.top()->element().getDataType() << endl; +//cout << " index: " << name_index << endl; + } + /* end debug output */ + + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { dn_stack.push(&dn_stack.top()->getNext()); dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } } } -} -/* set the header for use in serialization */ -de_node_names.set(node_names); + /* set the header for use in serialization */ + de_node_names.set(node_names); -total_size += de_node_names.getSerializedSize(); + total_size += de_node_names.getSerializedSize(); -return total_size; + return total_size; } void DataNode::findAll(const char *name_in, vector<DataNode *> &node_list_out) { -stack<DataNode *> dn_stack; + stack<DataNode *> dn_stack; -/* start at the root */ -dn_stack.push(this); + /* start at the root */ + dn_stack.push(this); -if (string(getName()) == string(name_in)) - node_list_out.push_back(this); + if (string(getName()) == string(name_in)) + node_list_out.push_back(this); -while (!dn_stack.empty()) { - while (dn_stack.top()->hasAnother(name_in)) { - node_list_out.push_back(&dn_stack.top()->getNext(name_in)); - } - - /* if it has children, traverse into them */ - if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } else { - /* no more children, back out until we have children, then add next child to the top */ - while (!dn_stack.empty()) { - if (!dn_stack.top()->hasAnother()) { - dn_stack.top()->rewind(); - dn_stack.pop(); - } else - break; + while (!dn_stack.empty()) { + while (dn_stack.top()->hasAnother(name_in)) { + node_list_out.push_back(&dn_stack.top()->getNext(name_in)); } - if (!dn_stack.empty()) { + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { dn_stack.push(&dn_stack.top()->getNext()); dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } } } -} } long DataTree::getSerialized(char **ser_str, bool debug) { -long data_ptr = 0; -long data_size = 0; + long data_ptr = 0; + long data_size = 0; -stack<DataNode *> dn_stack; -vector<string> node_names; -map<string, int, string_less> node_name_index_map; + stack<DataNode *> dn_stack; + vector<string> node_names; + map<string, int, string_less> node_name_index_map; -/* header of node names, grabbed from getserializedsize to avoid having to memmove() or realloc() */ -DataElement de_node_names; + /* header of node names, grabbed from getserializedsize to avoid having to memmove() or realloc() */ + DataElement de_node_names; -data_size = getSerializedSize(de_node_names, debug); + data_size = getSerializedSize(de_node_names, debug); -*ser_str = (char *) malloc(data_size); + *ser_str = (char *) malloc(data_size); -char *data_out = *ser_str; + char *data_out = *ser_str; -/* name list header */ -char *de_node_names_serialized; -long de_node_names_serialized_size; + /* name list header */ + char *de_node_names_serialized; + long de_node_names_serialized_size; -de_node_names.getSerialized(&de_node_names_serialized); -de_node_names_serialized_size = de_node_names.getSerializedSize(); + de_node_names.getSerialized(&de_node_names_serialized); + de_node_names_serialized_size = de_node_names.getSerializedSize(); -/* copy the header and increase the pointer */ -memcpy(data_out, de_node_names_serialized, de_node_names_serialized_size); -data_ptr += de_node_names_serialized_size; + /* copy the header and increase the pointer */ + memcpy(data_out, de_node_names_serialized, de_node_names_serialized_size); + data_ptr += de_node_names_serialized_size; -/* start at the root */ -dn_stack.push(&dn_root); + /* start at the root */ + dn_stack.push(&dn_root); -while (!dn_stack.empty()) { - int name_index; - int num_children; + while (!dn_stack.empty()) { + int name_index; + int num_children; - DataElement de_name_index; - DataElement de_num_children; + DataElement de_name_index; + DataElement de_num_children; - char *de_name_index_serialized; - char *de_num_children_serialized; - char *element_serialized; + char *de_name_index_serialized; + char *de_num_children_serialized; + char *element_serialized; - long de_name_index_serialized_size; - long de_num_children_serialized_size; - long element_serialized_size; + long de_name_index_serialized_size; + long de_num_children_serialized_size; + long element_serialized_size; - /* build the name list */ - if (dn_stack.top()->getName().empty()) { - name_index = 0; /* empty string */ - } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { - node_names.push_back(string(dn_stack.top()->getName())); - name_index = node_names.size(); - node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; - } else { - name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; - } - - num_children = dn_stack.top()->numChildren(); - - de_name_index.set(name_index); - de_num_children.set(num_children); - - de_name_index_serialized_size = de_name_index.getSerializedSize(); - de_num_children_serialized_size = de_num_children.getSerializedSize(); - element_serialized_size = dn_stack.top()->element().getSerializedSize(); - - de_name_index.getSerialized(&de_name_index_serialized); - de_num_children.getSerialized(&de_num_children_serialized); - dn_stack.top()->element().getSerialized(&element_serialized); - - /* add on the name index and number of children */ - memcpy(data_out + data_ptr, de_name_index_serialized, de_name_index_serialized_size); - data_ptr += de_name_index_serialized_size; - - memcpy(data_out + data_ptr, de_num_children_serialized, de_num_children_serialized_size); - data_ptr += de_num_children_serialized_size; - - /* add on the data element */ - memcpy(data_out + data_ptr, element_serialized, element_serialized_size); - data_ptr += element_serialized_size; - - delete de_name_index_serialized; - delete de_num_children_serialized; - delete element_serialized; - - /* if it has children, traverse into them */ - if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); - dn_stack.top()->rewind(); - } else { - /* no more children, back out until we have children, then add next child to the top */ - while (!dn_stack.empty()) { - if (!dn_stack.top()->hasAnother()) { - dn_stack.top()->rewind(); - dn_stack.pop(); - } else - break; + /* build the name list */ + if (dn_stack.top()->getName().empty()) { + name_index = 0; /* empty string */ + } else if (node_name_index_map[dn_stack.top()->getName().c_str()] == 0) { + node_names.push_back(string(dn_stack.top()->getName())); + name_index = node_names.size(); + node_name_index_map[dn_stack.top()->getName().c_str()] = name_index; + } else { + name_index = node_name_index_map[dn_stack.top()->getName().c_str()]; } - if (!dn_stack.empty()) { + num_children = dn_stack.top()->numChildren(); + + de_name_index.set(name_index); + de_num_children.set(num_children); + + de_name_index_serialized_size = de_name_index.getSerializedSize(); + de_num_children_serialized_size = de_num_children.getSerializedSize(); + element_serialized_size = dn_stack.top()->element().getSerializedSize(); + + de_name_index.getSerialized(&de_name_index_serialized); + de_num_children.getSerialized(&de_num_children_serialized); + dn_stack.top()->element().getSerialized(&element_serialized); + + /* add on the name index and number of children */ + memcpy(data_out + data_ptr, de_name_index_serialized, de_name_index_serialized_size); + data_ptr += de_name_index_serialized_size; + + memcpy(data_out + data_ptr, de_num_children_serialized, de_num_children_serialized_size); + data_ptr += de_num_children_serialized_size; + + /* add on the data element */ + memcpy(data_out + data_ptr, element_serialized, element_serialized_size); + data_ptr += element_serialized_size; + + delete de_name_index_serialized; + delete de_num_children_serialized; + delete element_serialized; + + /* if it has children, traverse into them */ + if (dn_stack.top()->hasAnother()) { dn_stack.push(&dn_stack.top()->getNext()); dn_stack.top()->rewind(); + } else { + /* no more children, back out until we have children, then add next child to the top */ + while (!dn_stack.empty()) { + if (!dn_stack.top()->hasAnother()) { + dn_stack.top()->rewind(); + dn_stack.pop(); + } else + break; + } + + if (!dn_stack.empty()) { + dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.top()->rewind(); + } } } -} -return data_size; + return data_size; } void DataTree::setSerialized(char *ser_str, bool debug) { -long data_ptr = 0; + long data_ptr = 0; // long data_size = 0; -stack<DataNode *> dn_stack; -stack<int> dn_childcount_stack; -vector<string> node_names; + stack<DataNode *> dn_stack; + stack<int> dn_childcount_stack; + vector<string> node_names; -DataElement de_node_names; + DataElement de_node_names; -de_node_names.setSerialized(ser_str); -data_ptr += de_node_names.getSerializedSize(); -de_node_names.get(node_names); + de_node_names.setSerialized(ser_str); + data_ptr += de_node_names.getSerializedSize(); + de_node_names.get(node_names); -DataElement de_name_index; -DataElement de_num_children; -DataElement de_element; + DataElement de_name_index; + DataElement de_num_children; + DataElement de_element; -dn_stack.push(&dn_root); -dn_childcount_stack.push(0); /* root (parent null) has no siblings */ + dn_stack.push(&dn_root); + dn_childcount_stack.push(0); /* root (parent null) has no siblings */ -/* unserialization is a little less straightforward since we have to do a countdown of remaining children */ -while (!dn_stack.empty()) { - int name_index; - int num_children; + /* unserialization is a little less straightforward since we have to do a countdown of remaining children */ + while (!dn_stack.empty()) { + int name_index; + int num_children; - /* pull the index of the name of this node */ - de_name_index.setSerialized(ser_str + data_ptr); - data_ptr += de_name_index.getSerializedSize(); + /* pull the index of the name of this node */ + de_name_index.setSerialized(ser_str + data_ptr); + data_ptr += de_name_index.getSerializedSize(); - /* pull the number of children this node has */ - de_num_children.setSerialized(ser_str + data_ptr); - data_ptr += de_num_children.getSerializedSize(); + /* pull the number of children this node has */ + de_num_children.setSerialized(ser_str + data_ptr); + data_ptr += de_num_children.getSerializedSize(); - /* get values from the temp dataelements */ - de_name_index.get(name_index); - de_num_children.get(num_children); - - /* pull the node's element */ - dn_stack.top()->element().setSerialized(ser_str + data_ptr); - data_ptr += dn_stack.top()->element().getSerializedSize(); - - /* debug output */ - if (debug) { - for (unsigned int i = 0; i < dn_stack.size() - 1; i++) - cout << "--"; - cout << (name_index ? node_names[name_index - 1] : "NULL") << "(" << dn_stack.top()->element().getSerializedSize() << ")"; - cout << " index: " << name_index << endl; - } - /* end debug output */ - - /* name index >= 1 means it has a name */ - if (name_index) { - dn_stack.top()->setName(node_names[name_index - 1].c_str()); - - } else /* name is nil */ - { - dn_stack.top()->setName(""); - } - - if (num_children) /* Has children, create first child and push it to the top */ - { - dn_childcount_stack.push(num_children); /* push the child count onto the stack */ - - de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ + /* get values from the temp dataelements */ de_name_index.get(name_index); - /* add this child onto the top of the stack */ - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); - dn_childcount_stack.top()--; /* decrement to count the new child */ + de_num_children.get(num_children); + + /* pull the node's element */ + dn_stack.top()->element().setSerialized(ser_str + data_ptr); + data_ptr += dn_stack.top()->element().getSerializedSize(); + + /* debug output */ + if (debug) { + for (unsigned int i = 0; i < dn_stack.size() - 1; i++) + cout << "--"; + cout << (name_index ? node_names[name_index - 1] : "NULL") << "(" << dn_stack.top()->element().getSerializedSize() << ")"; + cout << " index: " << name_index << endl; } - else /* No children, move on to the next sibling */ - { - if (dn_childcount_stack.top()) /* any siblings remaining? */ + /* end debug output */ + + /* name index >= 1 means it has a name */ + if (name_index) { + dn_stack.top()->setName(node_names[name_index - 1].c_str()); + + } else /* name is nil */ { + dn_stack.top()->setName(""); + } + + if (num_children) /* Has children, create first child and push it to the top */ + { + dn_childcount_stack.push(num_children); /* push the child count onto the stack */ + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ de_name_index.get(name_index); - - dn_stack.pop(); - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* create the next sibling and throw it on the stack */ - dn_childcount_stack.top()--; /* decrement to count the new sibling */ + /* add this child onto the top of the stack */ + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); + dn_childcount_stack.top()--; /* decrement to count the new child */ } - else /* This is the last sibling, move up the stack and find the next */ + else /* No children, move on to the next sibling */ { - while (!dn_stack.empty()) /* move up the stack until we find the next sibling */ + if (dn_childcount_stack.top()) /* any siblings remaining? */ { - if (dn_childcount_stack.top()) { - de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ - de_name_index.get(name_index); + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ + de_name_index.get(name_index); - dn_stack.pop(); - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* throw it on the stack */ - dn_childcount_stack.top()--; /* count it */ - break -; } - else + dn_stack.pop(); + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* create the next sibling and throw it on the stack */ + dn_childcount_stack.top()--; /* decrement to count the new sibling */ + } + else /* This is the last sibling, move up the stack and find the next */ + { + while (!dn_stack.empty()) /* move up the stack until we find the next sibling */ { - dn_childcount_stack.pop(); - dn_stack.pop(); /* if no more siblings found the stack will empty naturally */ + if (dn_childcount_stack.top()) { + de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ + de_name_index.get(name_index); + + dn_stack.pop(); + dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* throw it on the stack */ + dn_childcount_stack.top()--; /* count it */ + break +; } + else + { + dn_childcount_stack.pop(); + dn_stack.pop(); /* if no more siblings found the stack will empty naturally */ + } } } } } } -} bool DataTree::LoadFromFileXML(const std::string& filename, DT_FloatingPointPolicy fpp) { TiXmlDocument doc(filename.c_str()); diff --git a/src/util/DataTree.h b/src/util/DataTree.h index ed1cb2d..fb4c8da 100755 --- a/src/util/DataTree.h +++ b/src/util/DataTree.h @@ -64,11 +64,10 @@ using namespace std; #define DATA_LONG_VECTOR 18 #define DATA_ULONG_VECTOR 19 #define DATA_LONGLONG_VECTOR 20 -#define DATA_ULONGLONG_VECTOR 21 -#define DATA_FLOAT_VECTOR 22 -#define DATA_DOUBLE_VECTOR 23 -#define DATA_LONGDOUBLE_VECTOR 24 -#define DATA_VOID 25 +#define DATA_FLOAT_VECTOR 21 +#define DATA_DOUBLE_VECTOR 22 +#define DATA_LONGDOUBLE_VECTOR 23 +#define DATA_VOID 24 /* map comparison function */ @@ -122,7 +121,8 @@ class DataElement private: unsigned char data_type; unsigned int data_size; - + unsigned int unit_size; + char *data_val; void data_init(long data_size_in); @@ -133,9 +133,9 @@ public: int getDataType(); long getDataSize(); + int getUnitSize(); /* set overloads */ - // void set(const bool &bool_in); void set(const char &char_in); void set(const unsigned char &uchar_in); void set(const int &int_in); From 95fcb307338e21d29e7410b8de7030c4f7d8c8b3 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Thu, 8 Jan 2015 21:12:49 -0500 Subject: [PATCH 05/11] Audio thread lock fix --- src/audio/AudioThread.cpp | 29 +++++++++++++++++++++++++++ src/audio/AudioThread.h | 1 + src/demod/DemodulatorInstance.cpp | 32 ++++++++++++++++++++++-------- src/demod/DemodulatorPreThread.cpp | 2 ++ src/demod/DemodulatorPreThread.h | 4 ++++ src/demod/DemodulatorThread.cpp | 2 ++ 6 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/audio/AudioThread.cpp b/src/audio/AudioThread.cpp index be9ed92..ce07cbd 100644 --- a/src/audio/AudioThread.cpp +++ b/src/audio/AudioThread.cpp @@ -72,6 +72,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu continue; } srcmix->inputQueue->pop(srcmix->currentInput); + if (srcmix->terminated) { + continue; + } srcmix->audioQueuePtr = 0; continue; } @@ -88,6 +91,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu continue; } srcmix->inputQueue->pop(srcmix->currentInput); + if (srcmix->terminated) { + continue; + } srcmix->audioQueuePtr = 0; } continue; @@ -104,6 +110,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu continue; } srcmix->inputQueue->pop(srcmix->currentInput); + if (srcmix->terminated) { + continue; + } srcmix->audioQueuePtr = 0; } if (srcmix->currentInput && srcmix->currentInput->data.size()) { @@ -124,6 +133,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu continue; } srcmix->inputQueue->pop(srcmix->currentInput); + if (srcmix->terminated) { + continue; + } srcmix->audioQueuePtr = 0; } if (srcmix->currentInput && srcmix->currentInput->data.size()) { @@ -151,6 +163,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu if (!src->currentInput) { src->inputQueue->pop(src->currentInput); + if (src->terminated) { + return 1; + } src->audioQueuePtr = 0; return 0; } @@ -167,6 +182,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu return 1; } src->inputQueue->pop(src->currentInput); + if (src->terminated) { + return 1; + } src->audioQueuePtr = 0; } return 0; @@ -183,6 +201,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu return 1; } src->inputQueue->pop(src->currentInput); + if (src->terminated) { + return 1; + } src->audioQueuePtr = 0; } if (src->currentInput && src->currentInput->data.size()) { @@ -201,6 +222,9 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu return 1; } src->inputQueue->pop(src->currentInput); + if (src->terminated) { + return 1; + } src->audioQueuePtr = 0; } if (src->currentInput && src->currentInput->data.size()) { @@ -348,6 +372,8 @@ void AudioThread::threadMain() { std::cout << "Audio thread started." << std::endl; + terminated = false; + while (!terminated) { AudioThreadCommand command; cmdQueue.pop(command); @@ -357,6 +383,9 @@ void AudioThread::threadMain() { } } + AudioThreadInput dummy; + inputQueue->push(&dummy); + #ifdef __APPLE__ if (deviceController[parameters.deviceId] != this) { deviceController[parameters.deviceId]->removeThread(this); diff --git a/src/audio/AudioThread.h b/src/audio/AudioThread.h index d18b1e4..f849af7 100644 --- a/src/audio/AudioThread.h +++ b/src/audio/AudioThread.h @@ -60,6 +60,7 @@ public: std::atomic<unsigned int> audioQueuePtr; std::atomic<unsigned int> underflowCount; std::atomic<bool> terminated; + std::atomic<bool> initialized; std::atomic<bool> active; std::atomic<int> outputDevice; float gain; diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 4b54ff9..72c1451 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -1,8 +1,8 @@ #include "DemodulatorInstance.h" DemodulatorInstance::DemodulatorInstance() : - t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(false), audioTerminated(false), demodTerminated( - false), preDemodTerminated(false), active(false), squelch(false), stereo(false), currentFrequency(0), currentBandwidth(0) { + t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(true), audioTerminated(true), demodTerminated( + true), preDemodTerminated(true), active(false), squelch(false), stereo(false), currentFrequency(0), currentBandwidth(0) { label = new std::string("Unnamed"); threadQueueDemod = new DemodulatorThreadInputQueue; @@ -26,9 +26,13 @@ DemodulatorInstance::DemodulatorInstance() : DemodulatorInstance::~DemodulatorInstance() { delete audioThread; delete demodulatorThread; - - delete audioInputQueue; + delete demodulatorPreThread; delete threadQueueDemod; + delete threadQueuePostDemod; + delete threadQueueCommand; + delete threadQueueNotify; + delete threadQueueControl; + delete audioInputQueue; } void DemodulatorInstance::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) { @@ -36,7 +40,16 @@ void DemodulatorInstance::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQu } void DemodulatorInstance::run() { + if (active) { + return; + } + +// while (!isTerminated()) { +// std::this_thread::sleep_for(std::chrono::milliseconds(1)); +// } + currentFrequency = demodulatorPreThread->getParams().frequency; + currentDemodType = demodulatorThread->getDemodulatorType(); t_Audio = new std::thread(&AudioThread::threadMain, audioThread); @@ -63,6 +76,8 @@ void DemodulatorInstance::run() { t_Demod = new std::thread(&DemodulatorThread::threadMain, demodulatorThread); #endif active = true; + audioTerminated = demodTerminated = preDemodTerminated = terminated = false; + } void DemodulatorInstance::updateLabel(long long freq) { @@ -109,12 +124,10 @@ bool DemodulatorInstance::isTerminated() { switch (cmd.cmd) { case DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED: - audioThread = NULL; t_Audio->join(); audioTerminated = true; break; case DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED: - demodulatorThread = NULL; #ifdef __APPLE__ pthread_join(t_Demod, NULL); #else @@ -123,7 +136,6 @@ bool DemodulatorInstance::isTerminated() { demodTerminated = true; break; case DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED: - demodulatorPreThread = NULL; #ifdef __APPLE__ pthread_join(t_PreDemod, NULL); #else @@ -146,8 +158,12 @@ bool DemodulatorInstance::isActive() { } void DemodulatorInstance::setActive(bool state) { + if (active && !state) { + audioThread->setActive(state); + } else if (!active && state) { + audioThread->setActive(state); + } active = state; - audioThread->setActive(state); } bool DemodulatorInstance::isStereo() { diff --git a/src/demod/DemodulatorPreThread.cpp b/src/demod/DemodulatorPreThread.cpp index 0b6d3d2..5dedd65 100644 --- a/src/demod/DemodulatorPreThread.cpp +++ b/src/demod/DemodulatorPreThread.cpp @@ -70,6 +70,8 @@ void DemodulatorPreThread::threadMain() { std::vector<liquid_float_complex> in_buf_data; std::vector<liquid_float_complex> out_buf_data; + terminated = false; + while (!terminated) { DemodulatorThreadIQData *inp; iqInputQueue->pop(inp); diff --git a/src/demod/DemodulatorPreThread.h b/src/demod/DemodulatorPreThread.h index 2785b2b..e5d8467 100644 --- a/src/demod/DemodulatorPreThread.h +++ b/src/demod/DemodulatorPreThread.h @@ -32,6 +32,10 @@ public: return params; } + void setParams(DemodulatorThreadParameters ¶ms_in) { + params = params_in; + } + void initialize(); void terminate(); diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index e67a7b8..bd13056 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -92,6 +92,8 @@ void DemodulatorThread::threadMain() { std::cout << "Demodulator thread started.." << std::endl; + terminated = false; + while (!terminated) { DemodulatorThreadPostIQData *inp; iqInputQueue->pop(inp); From 4633bfa36f0d120318550d8ccb68de8e96c78b7a Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Thu, 8 Jan 2015 23:10:54 -0500 Subject: [PATCH 06/11] Datatree fixes, 64-bit updates --- src/util/DataTree.cpp | 4 ++-- src/util/DataTree.h | 23 ++++++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/util/DataTree.cpp b/src/util/DataTree.cpp index be428fb..f6efbfc 100755 --- a/src/util/DataTree.cpp +++ b/src/util/DataTree.cpp @@ -66,7 +66,7 @@ int DataElement::getUnitSize() { #define DataElementSetNumericDef(enumtype, datatype) void DataElement::set(const datatype& val_in) { \ data_type = enumtype; \ - unit_size = sizeof(char); \ + unit_size = sizeof(datatype); \ data_init(unit_size); \ memcpy(data_val, &val_in, data_size); \ } @@ -140,7 +140,7 @@ void DataElement::set(std::set<string> &strset_in) { #define DataElementSetNumericVectorDef(enumtype, datatype) void DataElement::set(vector<datatype>& val_in) { \ data_type = enumtype; \ - unit_size = sizeof(char); \ + unit_size = sizeof(datatype); \ data_init(unit_size * val_in.size()); \ memcpy(data_val, &val_in[0], data_size); \ } diff --git a/src/util/DataTree.h b/src/util/DataTree.h index fb4c8da..316e8dc 100755 --- a/src/util/DataTree.h +++ b/src/util/DataTree.h @@ -261,28 +261,49 @@ public: void findAll(const char *name_in, vector<DataNode *> &node_list_out); operator string () { string s; element().get(s); return s; } + operator char () { char v; element().get(v); return v; } + operator unsigned char () { unsigned char v; element().get(v); return v; } operator int () { int v; element().get(v); return v; } + operator unsigned int () { unsigned int v; element().get(v); return v; } operator long () { long v; element().get(v); return v; } + operator unsigned long () { unsigned long v; element().get(v); return v; } + operator long long () { long long v; element().get(v); return v; } operator float () { float v; element().get(v); return v; } operator double () { double v; element().get(v); return v; } + operator long double () { long double v; element().get(v); return v; } + operator vector<char> () { vector<char> v; element().get(v); return v; } + operator vector<unsigned char> () { vector<unsigned char> v; element().get(v); return v; } operator vector<int> () { vector<int> v; element().get(v); return v; } + operator vector<unsigned int> () { vector<unsigned int> v; element().get(v); return v; } operator vector<long> () { vector<long> v; element().get(v); return v; } + operator vector<unsigned long> () { vector<unsigned long> v; element().get(v); return v; } operator vector<float> () { vector<float> v; element().get(v); return v; } operator vector<double> () { vector<double> v; element().get(v); return v; } + operator vector<long double> () { vector<long double> v; element().get(v); return v; } const string &operator= (const string &s) { element().set(s); return s; } + char operator= (char i) { element().set(i); return i; } + unsigned char operator= (unsigned char i) { element().set(i); return i; } int operator= (int i) { element().set(i); return i; } + unsigned int operator= (unsigned int i) { element().set(i); return i; } long operator= (long i) { element().set(i); return i; } + unsigned long operator= (unsigned long i) { element().set(i); return i; } + long long operator= (long long i) { element().set(i); return i; } float operator= (float i) { element().set(i); return i; } double operator= (double i) { element().set(i); return i; } - + long double operator= (long double i) { element().set(i); return i; } + vector<char> &operator= (vector<char> &v) { element().set(v); return v; } + vector<unsigned char> &operator= (vector<unsigned char> &v) { element().set(v); return v; } vector<int> &operator= (vector<int> &v) { element().set(v); return v; } + vector<unsigned int> &operator= (vector<unsigned int> &v) { element().set(v); return v; } vector<long> &operator= (vector<long> &v) { element().set(v); return v; } + vector<unsigned long> &operator= (vector<unsigned long> &v) { element().set(v); return v; } vector<float> &operator= (vector<float> &v) { element().set(v); return v; } vector<double> &operator= (vector<double> &v) { element().set(v); return v; } + vector<long double> &operator= (vector<long double> &v) { element().set(v); return v; } DataNode &operator[] (const char *name_in) { return getNext(name_in); } DataNode &operator[] (int idx) { return child(idx); } From c3b4271e31d3f29421d5e161abf26a4542c76932 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Thu, 8 Jan 2015 23:57:58 -0500 Subject: [PATCH 07/11] Load/Save dialogs and menus, OSX Cmd-Q fix --- src/AppFrame.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index d7bf65d..6df59a5 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -7,6 +7,7 @@ #endif #include "wx/numdlg.h" +#include "wx/filedlg.h" #if !wxUSE_GLCANVAS #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" @@ -26,13 +27,12 @@ wxBEGIN_EVENT_TABLE(AppFrame, wxFrame) //EVT_MENU(wxID_NEW, AppFrame::OnNewWindow) EVT_MENU(wxID_CLOSE, AppFrame::OnClose) EVT_MENU(wxID_ANY, AppFrame::OnMenu) - EVT_COMMAND(wxID_ANY, wxEVT_THREAD, AppFrame::OnThread) EVT_IDLE(AppFrame::OnIdle) wxEND_EVENT_TABLE() AppFrame::AppFrame() : - wxFrame(NULL, wxID_ANY, wxT("CubicSDR v0.1a by Charles J. Cliffe (@ccliffe)")), activeDemodulator(NULL) { +wxFrame(NULL, wxID_ANY, wxT("CubicSDR v0.1a by Charles J. Cliffe (@ccliffe)")), activeDemodulator(NULL) { wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); wxBoxSizer *demodOpts = new wxBoxSizer(wxVERTICAL); @@ -40,7 +40,6 @@ AppFrame::AppFrame() : wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *demodScopeTray = new wxBoxSizer(wxVERTICAL); - demodModeSelector = new ModeSelectorCanvas(this, NULL); demodModeSelector->addChoice(DEMOD_TYPE_FM,"FM"); demodModeSelector->addChoice(DEMOD_TYPE_AM,"AM"); @@ -111,6 +110,9 @@ AppFrame::AppFrame() : wxMenu *menu = new wxMenu; // menu->Append(wxID_NEW); menu->Append(wxID_SET_FREQ_OFFSET, "Set Frequency Offset"); + menu->Append(wxID_OPEN, "&Open Session"); + menu->Append(wxID_SAVE, "&Save Session"); + menu->Append(wxID_SAVEAS, "Save Session &As.."); menu->AppendSeparator(); menu->Append(wxID_CLOSE); @@ -172,15 +174,31 @@ void AppFrame::OnMenu(wxCommandEvent& event) { activeDemodulator = NULL; } } else if (event.GetId() == wxID_SET_FREQ_OFFSET) { - long ofs = wxGetNumberFromUser ("Shift the displayed frequency by this amount.\ni.e. -125000000 for -125 MHz", "Frequency (Hz)", "Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this); + long ofs = wxGetNumberFromUser("Shift the displayed frequency by this amount.\ni.e. -125000000 for -125 MHz", "Frequency (Hz)", + "Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this); if (ofs != -1) { wxGetApp().setOffset(ofs); } + } else if (event.GetId() == wxID_SAVE) { + wxFileDialog saveFileDialog(this, _("Save XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE|wxFD_OVERWRITE_PROMPT); + if (saveFileDialog.ShowModal() == wxID_CANCEL) { + return; + } + // saveFileDialog.GetPath(); + } else if (event.GetId() == wxID_OPEN) { + wxFileDialog openFileDialog(this, _("Open XML Session file"), "", "","XML files (*.xml)|*.xml", wxFD_OPEN|wxFD_FILE_MUST_EXIST); + if (openFileDialog.ShowModal() == wxID_CANCEL) { + return; + } + // openFileDialog.GetPath(); + } else if (event.GetId() == wxID_SAVEAS) { + } else if (event.GetId() == wxID_EXIT) { + Close(false); } } void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { - Close(true); + Close(false); } void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) { From 8ec6b75e54c03d5f104dd391d9471c1a7e49264f Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Fri, 9 Jan 2015 17:17:56 -0500 Subject: [PATCH 08/11] Session save handler --- src/AppFrame.cpp | 33 ++++++++++++++++++++++++++++++++- src/AppFrame.h | 5 +++++ src/CubicSDRDefs.h | 2 ++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index d7bf65d..1dc2877 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -17,6 +17,7 @@ #include "DemodulatorMgr.h" #include "AudioThread.h" #include "CubicSDR.h" +#include "DataTree.h" #include <thread> @@ -32,7 +33,7 @@ EVT_IDLE(AppFrame::OnIdle) wxEND_EVENT_TABLE() AppFrame::AppFrame() : - wxFrame(NULL, wxID_ANY, wxT("CubicSDR v0.1a by Charles J. Cliffe (@ccliffe)")), activeDemodulator(NULL) { + wxFrame(NULL, wxID_ANY, wxT("CubicSDR " CUBICSDR_VERSION " by Charles J. Cliffe (@ccliffe)")), activeDemodulator(NULL) { wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); wxBoxSizer *demodOpts = new wxBoxSizer(wxVERTICAL); @@ -282,3 +283,33 @@ void AppFrame::OnIdle(wxIdleEvent& event) { event.Skip(); } } + +void AppFrame::saveSession(std::string fileName) { + DataTree s("cubicsdr_session"); + DataNode &header = s.rootNode().newChild("header"); + header.newChild("version") = std::string(CUBICSDR_VERSION); + header.newChild("center_freq") = wxGetApp().getFrequency(); + header.newChild("offset") = wxGetApp().getOffset(); + + DataNode &demods = s.rootNode().newChild("demodulators"); + + std::vector<DemodulatorInstance *> &instances = wxGetApp().getDemodMgr().getDemodulators(); + std::vector<DemodulatorInstance *>::iterator instance_i; + for (instance_i = instances.begin(); instance_i != instances.end(); instance_i++) { + DataNode &demod = demods.newChild("demodulator"); + demod.newChild("bandwidth") = (long)(*instance_i)->getBandwidth(); + demod.newChild("frequency") = (long long)(*instance_i)->getFrequency(); + demod.newChild("type") = (int)(*instance_i)->getDemodulatorType(); + if ((*instance_i)->isSquelchEnabled()) { + demod.newChild("squelch") = (*instance_i)->getSquelchLevel(); + demod.newChild("squelch_enabled") = (char)1; + } + demod.newChild("stereo") = (char)(*instance_i)->isStereo(); + demod.newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name; + } + + s.SaveToFileXML(fileName); +} + +bool AppFrame::loadSession(std::string fileName) { +} diff --git a/src/AppFrame.h b/src/AppFrame.h index 4df734d..ca0df5b 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -23,6 +23,9 @@ public: void OnThread(wxCommandEvent& event); void OnEventInput(wxThreadEvent& event); + void saveSession(std::string fileName); + bool loadSession(std::string fileName); + private: void OnMenu(wxCommandEvent& event); void OnClose(wxCommandEvent& event); @@ -46,5 +49,7 @@ private: std::map<int,RtAudio::DeviceInfo> outputDevices; std::map<int,wxMenuItem *> outputDeviceMenuItems; + std::string currentSessionFile; + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 1a8fa98..1c0493b 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -1,5 +1,7 @@ #pragma once +#define CUBICSDR_VERSION "v0.01a" + #ifdef __APPLE__ #define BUF_SIZE (16384*2) #define SRATE 2000000 From faa87fcd10d433736eb6c5eb2f190da1e65c4593 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Fri, 9 Jan 2015 20:56:43 -0500 Subject: [PATCH 09/11] DataTree refactoring, load/save functions almost ready --- src/AppFrame.cpp | 85 +++++++++++++---- src/audio/AudioThread.cpp | 28 +++--- src/util/DataTree.cpp | 186 ++++++++++++++++++++------------------ src/util/DataTree.h | 139 ++++++++++++++-------------- 4 files changed, 248 insertions(+), 190 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index d397456..41e6e51 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -185,13 +185,13 @@ void AppFrame::OnMenu(wxCommandEvent& event) { if (saveFileDialog.ShowModal() == wxID_CANCEL) { return; } - // saveFileDialog.GetPath(); + saveSession(saveFileDialog.GetPath().ToStdString()); } else if (event.GetId() == wxID_OPEN) { wxFileDialog openFileDialog(this, _("Open XML Session file"), "", "","XML files (*.xml)|*.xml", wxFD_OPEN|wxFD_FILE_MUST_EXIST); if (openFileDialog.ShowModal() == wxID_CANCEL) { return; } - // openFileDialog.GetPath(); + loadSession(openFileDialog.GetPath().ToStdString()); } else if (event.GetId() == wxID_SAVEAS) { } else if (event.GetId() == wxID_EXIT) { Close(false); @@ -304,30 +304,81 @@ void AppFrame::OnIdle(wxIdleEvent& event) { void AppFrame::saveSession(std::string fileName) { DataTree s("cubicsdr_session"); - DataNode &header = s.rootNode().newChild("header"); - header.newChild("version") = std::string(CUBICSDR_VERSION); - header.newChild("center_freq") = wxGetApp().getFrequency(); - header.newChild("offset") = wxGetApp().getOffset(); + DataNode *header = s.rootNode()->newChild("header"); + *header->newChild("version") = std::string(CUBICSDR_VERSION); + *header->newChild("center_freq") = wxGetApp().getFrequency(); + *header->newChild("offset") = wxGetApp().getOffset(); - DataNode &demods = s.rootNode().newChild("demodulators"); + DataNode *demods = s.rootNode()->newChild("demodulators"); std::vector<DemodulatorInstance *> &instances = wxGetApp().getDemodMgr().getDemodulators(); std::vector<DemodulatorInstance *>::iterator instance_i; for (instance_i = instances.begin(); instance_i != instances.end(); instance_i++) { - DataNode &demod = demods.newChild("demodulator"); - demod.newChild("bandwidth") = (long)(*instance_i)->getBandwidth(); - demod.newChild("frequency") = (long long)(*instance_i)->getFrequency(); - demod.newChild("type") = (int)(*instance_i)->getDemodulatorType(); - if ((*instance_i)->isSquelchEnabled()) { - demod.newChild("squelch") = (*instance_i)->getSquelchLevel(); - demod.newChild("squelch_enabled") = (char)1; - } - demod.newChild("stereo") = (char)(*instance_i)->isStereo(); - demod.newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name; + DataNode *demod = demods->newChild("demodulator"); + *demod->newChild("bandwidth") = (*instance_i)->getBandwidth(); + *demod->newChild("frequency") = (*instance_i)->getFrequency(); + *demod->newChild("type") = (*instance_i)->getDemodulatorType(); + *demod->newChild("squelch_level") = (*instance_i)->getSquelchLevel(); + *demod->newChild("squelch_enabled") = (*instance_i)->isSquelchEnabled()?1:0; + *demod->newChild("stereo") = (*instance_i)->isStereo()?1:0; + *demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name; } s.SaveToFileXML(fileName); } bool AppFrame::loadSession(std::string fileName) { + DataTree l; + if (!l.LoadFromFileXML(fileName)) { + return false; + } + +// wxGetApp().getDemodMgr().terminateAll(); + + try { + DataNode *header = l.rootNode()->getNext("header"); + + std::string version = *header->getNext("version"); + long long center_freq = *header->getNext("center_freq"); + long long offset = *header->getNext("offset"); + + std::cout << "Loading " << version << " session file" << std::endl; + std::cout << "\tCenter Frequency: " << center_freq << std::endl; + std::cout << "\tOffset: " << offset << std::endl; + + + DataNode *demodulators = l.rootNode()->getNext("demodulators"); + + while (demodulators->hasAnother("demodulator")) { + DataNode *demod = demodulators->getNext("demodulator"); + + if (!demod->hasAnother("bandwidth") || !demod->hasAnother("frequency")) { + continue; + } + + long bandwidth = *demod->getNext("bandwidth"); + long long freq = *demod->getNext("frequency"); + int type = demod->hasAnother("type")?*demod->getNext("type"):DEMOD_TYPE_FM; + float squelch_level = demod->hasAnother("squelch_level")?(float)*demod->getNext("squelch_level"):0; + int squelch_enabled = demod->hasAnother("squelch_enabled")?(int)*demod->getNext("squelch_enabled"):0; + int stereo = demod->hasAnother("stereo")?(int)*demod->getNext("stereo"):0; + std::string output_device = demod->hasAnother("output_device")?*demod->getNext("output_device"):""; + + std::cout << "\tFound demodulator at frequency " << freq << " type " << type << std::endl; + std::cout << "\t\tBandwidth: " << bandwidth << std::endl; + std::cout << "\t\tSquelch Level: " << squelch_level << std::endl; + std::cout << "\t\tSquelch Enabled: " << (squelch_enabled?"true":"false") << std::endl; + std::cout << "\t\tStereo: " << (stereo?"true":"false") << std::endl; + std::cout << "\t\tOutput Device: " << output_device << std::endl; + + } + + } catch (DataInvalidChildException &e) { + std::cout << e.what() << std::endl; + return false; + } catch (DataTypeMismatchException &e) { + std::cout << e.what() << std::endl; + return false; + } + } diff --git a/src/audio/AudioThread.cpp b/src/audio/AudioThread.cpp index ce07cbd..139d641 100644 --- a/src/audio/AudioThread.cpp +++ b/src/audio/AudioThread.cpp @@ -10,8 +10,8 @@ std::map<int, std::thread *> AudioThread::deviceThread; #endif AudioThread::AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify) : - currentInput(NULL), inputQueue(inputQueue), audioQueuePtr(0), underflowCount(0), terminated(false), active(false), outputDevice(-1), gain(1.0), threadQueueNotify( - threadQueueNotify) { + currentInput(NULL), inputQueue(inputQueue), audioQueuePtr(0), underflowCount(0), terminated(false), active(false), outputDevice(-1), gain( + 1.0), threadQueueNotify(threadQueueNotify) { #ifdef __APPLE__ boundThreads = new std::vector<AudioThread *>; #endif @@ -368,7 +368,7 @@ void AudioThread::threadMain() { return; } - setupDevice((outputDevice.load() == -1)?(dac.getDefaultOutputDevice()):outputDevice.load()); + setupDevice((outputDevice.load() == -1) ? (dac.getDefaultOutputDevice()) : outputDevice.load()); std::cout << "Audio thread started." << std::endl; @@ -391,24 +391,27 @@ void AudioThread::threadMain() { deviceController[parameters.deviceId]->removeThread(this); } else { try { - dac.stopStream(); - dac.closeStream(); + if (dac.isStreamOpen()) { + if (dac.isStreamRunning()) { + dac.stopStream(); + } + dac.closeStream(); + } } catch (RtAudioError& e) { e.printMessage(); } } #else try { - // Stop the stream - dac.stopStream(); - dac.closeStream(); + if (dac.isStreamOpen()) { + if (dac.isStreamRunning()) { + dac.stopStream(); + } + dac.closeStream(); + } } catch (RtAudioError& e) { e.printMessage(); } - - if (dac.isStreamOpen()) { - dac.closeStream(); - } #endif std::cout << "Audio thread done." << std::endl; @@ -454,7 +457,6 @@ void AudioThread::setActive(bool state) { active = state; } - AudioThreadCommandQueue *AudioThread::getCommandQueue() { return &cmdQueue; } diff --git a/src/util/DataTree.cpp b/src/util/DataTree.cpp index f6efbfc..1f3cce6 100755 --- a/src/util/DataTree.cpp +++ b/src/util/DataTree.cpp @@ -89,7 +89,7 @@ void DataElement::set(const char *data_in, long size_in) { } void DataElement::set(const char *data_in) { - data_type = DATA_VOID; + data_type = DATA_STRING; data_init(strlen(data_in) + 1); memcpy(data_val, data_in, data_size); } @@ -176,7 +176,13 @@ return; \ std::cout << "Warning, data type mismatch requested size for '" << #datatype << "(" << sizeof(datatype) << ")' < data size '" << data_size << "'; possible loss of data."; \ } \ memset(&val_out, 0, sizeof(datatype)); \ - memcpy(&val_out, data_val, (sizeof(datatype) < data_size) ? sizeof(datatype) : data_size); \ + if (sizeof(datatype) > 4 && data_size <= 4) { \ + int v = 0; memcpy(&v,data_val,data_size); \ + val_out = (datatype)v; \ + return; \ + } else { \ + memcpy(&val_out, data_val, (sizeof(datatype) < data_size) ? sizeof(datatype) : data_size); \ + } \ return; \ } \ memcpy(&val_out, data_val, data_size); \ @@ -301,7 +307,7 @@ DataElementGetNumericVectorDef(DATA_LONGDOUBLE_VECTOR, long double, DATA_DOUBLE_ long DataElement::getSerializedSize() { - return sizeof(unsigned char) + sizeof(unsigned int) + data_size; + return sizeof(int) + sizeof(long) + data_size; } long DataElement::getSerialized(char **ser_str) { @@ -313,10 +319,10 @@ long DataElement::getSerialized(char **ser_str) { ser_pointer = *ser_str; - memcpy(ser_pointer, &data_type, sizeof(unsigned char)); - ser_pointer += sizeof(unsigned char); - memcpy(ser_pointer, &data_size, sizeof(unsigned int)); - ser_pointer += sizeof(unsigned int); + memcpy(ser_pointer, &data_type, sizeof(int)); + ser_pointer += sizeof(int); + memcpy(ser_pointer, &data_size, sizeof(long)); + ser_pointer += sizeof(long); memcpy(ser_pointer, data_val, data_size); return ser_size; @@ -357,20 +363,20 @@ void DataNode::setName(const char *name_in) { node_name = name_in; } -DataElement & DataNode::element() { - return data_elem; +DataElement *DataNode::element() { + return &data_elem; } -DataNode &DataNode::newChild(const char *name_in) { +DataNode *DataNode::newChild(const char *name_in) { children.push_back(new DataNode(name_in)); childmap[name_in].push_back(children.back()); children.back()->setParentNode(*this); - return *children.back(); + return children.back(); } -DataNode &DataNode::child(const char *name_in, int index) throw (DataInvalidChildException) { +DataNode *DataNode::child(const char *name_in, int index) throw (DataInvalidChildException) { DataNode *child_ret; child_ret = childmap[name_in][index]; @@ -381,10 +387,10 @@ DataNode &DataNode::child(const char *name_in, int index) throw (DataInvalidChil throw(DataInvalidChildException(error_str.str().c_str())); } - return *child_ret; + return child_ret; } -DataNode &DataNode::child(int index) throw (DataInvalidChildException) { +DataNode *DataNode::child(int index) throw (DataInvalidChildException) { DataNode *child_ret; @@ -396,7 +402,7 @@ DataNode &DataNode::child(int index) throw (DataInvalidChildException) { throw(DataInvalidChildException(error_str.str().c_str())); } - return *child_ret; + return child_ret; } int DataNode::numChildren() { @@ -415,11 +421,11 @@ bool DataNode::hasAnother(const char *name_in) { return childmap[name_in].size() != childmap_ptr[name_in]; } -DataNode & DataNode::getNext() throw (DataInvalidChildException) { +DataNode *DataNode::getNext() throw (DataInvalidChildException) { return child(ptr++); } -DataNode &DataNode::getNext(const char *name_in) throw (DataInvalidChildException) { +DataNode *DataNode::getNext(const char *name_in) throw (DataInvalidChildException) { return child(name_in, childmap_ptr[name_in]++); } @@ -445,8 +451,8 @@ DataTree::~DataTree() { } ; -DataNode & DataTree::rootNode() { - return dn_root; +DataNode *DataTree::rootNode() { + return &dn_root; } std::string trim(std::string& s, const std::string& drop = " ") { @@ -491,15 +497,15 @@ void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPo tmp_stream << in_text; tmp_stream >> tmp_llong; - tmp_int = tmp_llong; - tmp_long = tmp_llong; + tmp_int = (int)tmp_llong; + tmp_long = (long)tmp_llong; if (tmp_int == tmp_llong) { - elem->element().set((int) tmp_int); + elem->element()->set(tmp_int); } else if (tmp_long == tmp_llong) { - elem->element().set((long) tmp_int); + elem->element()->set(tmp_long); } else { - elem->element().set((long long) tmp_long); + elem->element()->set(tmp_llong); } } else if (in_text.find_first_not_of("0123456789.e+-") == string::npos) { tmp_stream << in_text; @@ -507,11 +513,11 @@ void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPo if (fpp == USE_FLOAT) { tmp_stream >> tmp_float; - elem->element().set((float) tmp_float); + elem->element()->set((float) tmp_float); } else { tmp_stream >> tmp_double; - elem->element().set((double) tmp_double); + elem->element()->set((double) tmp_double); } } else if (in_text.find_first_not_of("0123456789- ") == string::npos) { tmp_stream << in_text; @@ -542,7 +548,7 @@ void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPo tmp_charvect.push_back(*tmp_llongvect_i); } tmp_llongvect.clear(); - elem->element().set(tmp_charvect); + elem->element()->set(tmp_charvect); tmp_charvect.clear(); } else if (vInts) { @@ -550,17 +556,17 @@ void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPo tmp_intvect.push_back(*tmp_llongvect_i); } tmp_llongvect.clear(); - elem->element().set(tmp_intvect); + elem->element()->set(tmp_intvect); tmp_intvect.clear(); } else if (vLongs) { for (tmp_llongvect_i = tmp_llongvect.begin(); tmp_llongvect_i != tmp_llongvect.end(); tmp_llongvect_i++) { tmp_longvect.push_back(*tmp_llongvect_i); } tmp_llongvect.clear(); - elem->element().set(tmp_longvect); + elem->element()->set(tmp_longvect); tmp_longvect.clear(); } else { - elem->element().set(tmp_llongvect); + elem->element()->set(tmp_llongvect); } } else if (in_text.find_first_not_of("0123456789.e-+ ") == string::npos) { tmp_stream << in_text; @@ -583,12 +589,12 @@ void DataTree::decodeXMLText(DataNode *elem, const char *src_text, DT_FloatingPo } if (fpp == USE_FLOAT) { - elem->element().set(tmp_floatvect); + elem->element()->set(tmp_floatvect); } else { - elem->element().set(tmp_doublevect); + elem->element()->set(tmp_doublevect); } } else { - elem->element().set(src_text); + elem->element()->set(src_text); // printf( "Unhandled DataTree XML Field: [%s]", tmp_str.c_str() ); } @@ -606,7 +612,7 @@ void DataTree::setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node, DT_F case TiXmlNode::ELEMENT: if (!root_node) - elem = &elem->newChild(elxml->Value()); + elem = elem->newChild(elxml->Value()); const TiXmlAttribute *attribs; attribs = elxml->ToElement()->FirstAttribute(); @@ -617,7 +623,7 @@ void DataTree::setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node, DT_F string attrName("@"); attrName.append(attribs->Name()); - decodeXMLText(&elem->newChild(attrName.c_str()), attribs->Value(), fpp); + decodeXMLText(elem->newChild(attrName.c_str()), attribs->Value(), fpp); attribs = attribs->Next(); } @@ -674,7 +680,7 @@ void DataTree::setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node, DT_F } } - elem->element().set(tmp_strvect); + elem->element()->set(tmp_strvect); return; } @@ -693,7 +699,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { elem->rewind(); while (elem->hasAnother()) { - child = &elem->getNext(); + child = elem->getNext(); std::string nodeName = child->getName(); @@ -738,11 +744,11 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { unsigned long tmp_ulong; long long tmp_llong; - switch (child->element().getDataType()) { + switch (child->element()->getDataType()) { case DATA_NULL: break; case DATA_VOID: - child->element().get(&tmp_pstr); + child->element()->get(&tmp_pstr); // following badgerfish xml->json and xml->ruby convention for attributes.. if (nodeName.substr(0, 1) == string("@")) { elxml->SetAttribute(nodeName.substr(1).c_str(), tmp_pstr); @@ -755,7 +761,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { delete tmp_pstr; break; case DATA_CHAR: - child->element().get(tmp_char); + child->element()->get(tmp_char); tmp_stream.str(""); @@ -765,7 +771,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_UCHAR: - child->element().get(tmp_uchar); + child->element()->get(tmp_uchar); tmp_stream.str(""); @@ -775,7 +781,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_INT: - child->element().get(tmp_int); + child->element()->get(tmp_int); tmp_stream.str(""); @@ -785,7 +791,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_UINT: - child->element().get(tmp_uint); + child->element()->get(tmp_uint); tmp_stream.str(""); @@ -795,7 +801,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_LONG: - child->element().get(tmp_long); + child->element()->get(tmp_long); tmp_stream.str(""); @@ -805,7 +811,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_ULONG: - child->element().get(tmp_ulong); + child->element()->get(tmp_ulong); tmp_stream.str(""); @@ -815,7 +821,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_LONGLONG: - child->element().get(tmp_llong); + child->element()->get(tmp_llong); tmp_stream.str(""); @@ -825,7 +831,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_FLOAT: - child->element().get(tmp_float); + child->element()->get(tmp_float); tmp_stream.str(""); @@ -835,7 +841,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_DOUBLE: - child->element().get(tmp_double); + child->element()->get(tmp_double); tmp_stream.str(""); @@ -845,7 +851,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_LONGDOUBLE: - child->element().get(tmp_ldouble); + child->element()->get(tmp_ldouble); tmp_stream.str(""); @@ -855,7 +861,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { element->LinkEndChild(text); break; case DATA_STRING: - child->element().get(tmp); + child->element()->get(tmp); if (nodeName.substr(0, 1) == string("@")) { elxml->SetAttribute(nodeName.substr(1).c_str(), tmp.c_str()); delete element; @@ -867,7 +873,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { break; case DATA_STR_VECTOR: - child->element().get(tmp_stringvect); + child->element()->get(tmp_stringvect); tmp_stream.str(""); @@ -881,7 +887,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_stringvect.clear(); break; case DATA_CHAR_VECTOR: - child->element().get(tmp_charvect); + child->element()->get(tmp_charvect); tmp_stream.str(""); @@ -896,7 +902,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_charvect.clear(); break; case DATA_UCHAR_VECTOR: - child->element().get(tmp_ucharvect); + child->element()->get(tmp_ucharvect); tmp_stream.str(""); @@ -911,7 +917,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_ucharvect.clear(); break; case DATA_INT_VECTOR: - child->element().get(tmp_intvect); + child->element()->get(tmp_intvect); tmp_stream.str(""); @@ -926,7 +932,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_intvect.clear(); break; case DATA_UINT_VECTOR: - child->element().get(tmp_uintvect); + child->element()->get(tmp_uintvect); tmp_stream.str(""); @@ -941,7 +947,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_uintvect.clear(); break; case DATA_LONG_VECTOR: - child->element().get(tmp_longvect); + child->element()->get(tmp_longvect); tmp_stream.str(""); @@ -956,7 +962,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_longvect.clear(); break; case DATA_ULONG_VECTOR: - child->element().get(tmp_ulongvect); + child->element()->get(tmp_ulongvect); tmp_stream.str(""); @@ -971,7 +977,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_ulongvect.clear(); break; case DATA_LONGLONG_VECTOR: - child->element().get(tmp_llongvect); + child->element()->get(tmp_llongvect); tmp_stream.str(""); @@ -986,7 +992,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_llongvect.clear(); break; case DATA_FLOAT_VECTOR: - child->element().get(tmp_floatvect); + child->element()->get(tmp_floatvect); tmp_stream.str(""); @@ -1001,7 +1007,7 @@ void DataTree::nodeToXML(DataNode *elem, TiXmlElement *elxml) { tmp_floatvect.clear(); break; case DATA_DOUBLE_VECTOR: - child->element().get(tmp_doublevect); + child->element()->get(tmp_doublevect); tmp_stream.str(""); @@ -1035,7 +1041,7 @@ void DataTree::printXML() /* get serialized size + return node names header */ TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); doc.LinkEndChild(decl); - DataNode *root = &rootNode(); + DataNode *root = rootNode(); string rootName = root->getName(); @@ -1089,22 +1095,22 @@ long DataTree::getSerializedSize(DataElement &de_node_names, bool debug) /* get /* add on the size of the name index and number of children */ total_size += de_name_index_size; total_size += de_num_children_size; - total_size += dn_stack.top()->element().getSerializedSize(); + total_size += dn_stack.top()->element()->getSerializedSize(); /* debug output */ if (debug) { for (unsigned int i = 0; i < dn_stack.size() - 1; i++) cout << "--"; - cout << (dn_stack.top()->getName().empty() ? "NULL" : dn_stack.top()->getName()) << "(" << dn_stack.top()->element().getSerializedSize() + cout << (dn_stack.top()->getName().empty() ? "NULL" : dn_stack.top()->getName()) << "(" << dn_stack.top()->element()->getSerializedSize() << ")"; - cout << " type: " << dn_stack.top()->element().getDataType() << endl; + cout << " type: " << dn_stack.top()->element()->getDataType() << endl; //cout << " index: " << name_index << endl; } /* end debug output */ /* if it has children, traverse into them */ if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.push(dn_stack.top()->getNext()); dn_stack.top()->rewind(); } else { /* no more children, back out until we have children, then add next child to the top */ @@ -1117,7 +1123,7 @@ long DataTree::getSerializedSize(DataElement &de_node_names, bool debug) /* get } if (!dn_stack.empty()) { - dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.push(dn_stack.top()->getNext()); dn_stack.top()->rewind(); } } @@ -1142,12 +1148,12 @@ void DataNode::findAll(const char *name_in, vector<DataNode *> &node_list_out) { while (!dn_stack.empty()) { while (dn_stack.top()->hasAnother(name_in)) { - node_list_out.push_back(&dn_stack.top()->getNext(name_in)); + node_list_out.push_back(dn_stack.top()->getNext(name_in)); } /* if it has children, traverse into them */ if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.push(dn_stack.top()->getNext()); dn_stack.top()->rewind(); } else { /* no more children, back out until we have children, then add next child to the top */ @@ -1160,7 +1166,7 @@ void DataNode::findAll(const char *name_in, vector<DataNode *> &node_list_out) { } if (!dn_stack.empty()) { - dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.push(dn_stack.top()->getNext()); dn_stack.top()->rewind(); } } @@ -1232,11 +1238,11 @@ long DataTree::getSerialized(char **ser_str, bool debug) { de_name_index_serialized_size = de_name_index.getSerializedSize(); de_num_children_serialized_size = de_num_children.getSerializedSize(); - element_serialized_size = dn_stack.top()->element().getSerializedSize(); + element_serialized_size = dn_stack.top()->element()->getSerializedSize(); de_name_index.getSerialized(&de_name_index_serialized); de_num_children.getSerialized(&de_num_children_serialized); - dn_stack.top()->element().getSerialized(&element_serialized); + dn_stack.top()->element()->getSerialized(&element_serialized); /* add on the name index and number of children */ memcpy(data_out + data_ptr, de_name_index_serialized, de_name_index_serialized_size); @@ -1255,7 +1261,7 @@ long DataTree::getSerialized(char **ser_str, bool debug) { /* if it has children, traverse into them */ if (dn_stack.top()->hasAnother()) { - dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.push(dn_stack.top()->getNext()); dn_stack.top()->rewind(); } else { /* no more children, back out until we have children, then add next child to the top */ @@ -1268,7 +1274,7 @@ long DataTree::getSerialized(char **ser_str, bool debug) { } if (!dn_stack.empty()) { - dn_stack.push(&dn_stack.top()->getNext()); + dn_stack.push(dn_stack.top()->getNext()); dn_stack.top()->rewind(); } } @@ -1316,14 +1322,14 @@ void DataTree::setSerialized(char *ser_str, bool debug) { de_num_children.get(num_children); /* pull the node's element */ - dn_stack.top()->element().setSerialized(ser_str + data_ptr); - data_ptr += dn_stack.top()->element().getSerializedSize(); + dn_stack.top()->element()->setSerialized(ser_str + data_ptr); + data_ptr += dn_stack.top()->element()->getSerializedSize(); /* debug output */ if (debug) { for (unsigned int i = 0; i < dn_stack.size() - 1; i++) cout << "--"; - cout << (name_index ? node_names[name_index - 1] : "NULL") << "(" << dn_stack.top()->element().getSerializedSize() << ")"; + cout << (name_index ? node_names[name_index - 1] : "NULL") << "(" << dn_stack.top()->element()->getSerializedSize() << ")"; cout << " index: " << name_index << endl; } /* end debug output */ @@ -1344,7 +1350,7 @@ void DataTree::setSerialized(char *ser_str, bool debug) { de_name_index.setSerialized(ser_str + data_ptr); /* peek at the new child name but don't increment pointer */ de_name_index.get(name_index); /* add this child onto the top of the stack */ - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); + dn_stack.push(dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); dn_childcount_stack.top()--; /* decrement to count the new child */ } else /* No children, move on to the next sibling */ @@ -1355,7 +1361,7 @@ void DataTree::setSerialized(char *ser_str, bool debug) { de_name_index.get(name_index); dn_stack.pop(); - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* create the next sibling and throw it on the stack */ + dn_stack.push(dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* create the next sibling and throw it on the stack */ dn_childcount_stack.top()--; /* decrement to count the new sibling */ } else /* This is the last sibling, move up the stack and find the next */ @@ -1367,7 +1373,7 @@ void DataTree::setSerialized(char *ser_str, bool debug) { de_name_index.get(name_index); dn_stack.pop(); - dn_stack.push(&dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* throw it on the stack */ + dn_stack.push(dn_stack.top()->newChild((name_index ? node_names[name_index - 1] : string("")).c_str())); /* throw it on the stack */ dn_childcount_stack.top()--; /* count it */ break ; } @@ -1398,9 +1404,9 @@ bool DataTree::LoadFromFileXML(const std::string& filename, DT_FloatingPointPoli return false; } - rootNode().setName(xml_root_node->ToElement()->Value()); + rootNode()->setName(xml_root_node->ToElement()->Value()); - setFromXML(&rootNode(), xml_root_node, true, fpp); + setFromXML(rootNode(), xml_root_node, true, fpp); return true; } @@ -1410,13 +1416,13 @@ bool DataTree::SaveToFileXML(const std::string& filename) { TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", ""); doc.LinkEndChild(decl); - string rootName = rootNode().getName(); + string rootName = rootNode()->getName(); TiXmlElement *element = new TiXmlElement(rootName.empty() ? "root" : rootName.c_str()); doc.LinkEndChild(element); - nodeToXML(&rootNode(), element); + nodeToXML(rootNode(), element); doc.SaveFile(filename.c_str()); @@ -1489,11 +1495,11 @@ bool DataTree::SaveToFile(const std::string& filename, bool compress, int compre compress = false; } #endif - DataNode &header = dtHeader.rootNode(); + DataNode *header = dtHeader.rootNode(); - header ^ "version" = 1.0f; - header ^ "compression" = string(compress ? "FastLZ" : "none"); - header ^ "uncompressed_size" = dataSize; + *header->newChild("version") = 1.0f; + *header->newChild("compression") = string(compress ? "FastLZ" : "none"); + *header->newChild("uncompressed_size") = dataSize; headerSize = dtHeader.getSerialized(&hdr_serialized); @@ -1533,10 +1539,10 @@ bool DataTree::LoadFromFile(const std::string& filename) { DataTree dtHeader; dtHeader.setSerialized(hdr_serialized); - DataNode &header = dtHeader.rootNode(); + DataNode *header = dtHeader.rootNode(); - string compressionType = header["compression"]; - dataSize = header["uncompressed_size"]; + string compressionType = *header->getNext("compression"); + dataSize = *header->getNext("uncompressed_size"); bool uncompress = false; #if USE_FASTLZ diff --git a/src/util/DataTree.h b/src/util/DataTree.h index 316e8dc..49273a9 100755 --- a/src/util/DataTree.h +++ b/src/util/DataTree.h @@ -51,23 +51,22 @@ using namespace std; #define DATA_LONG 5 #define DATA_ULONG 6 #define DATA_LONGLONG 7 -#define DATA_ULONGLONG 8 -#define DATA_FLOAT 9 -#define DATA_DOUBLE 10 -#define DATA_LONGDOUBLE 11 -#define DATA_STRING 12 -#define DATA_STR_VECTOR 13 -#define DATA_CHAR_VECTOR 14 -#define DATA_UCHAR_VECTOR 15 -#define DATA_INT_VECTOR 16 -#define DATA_UINT_VECTOR 17 -#define DATA_LONG_VECTOR 18 -#define DATA_ULONG_VECTOR 19 -#define DATA_LONGLONG_VECTOR 20 -#define DATA_FLOAT_VECTOR 21 -#define DATA_DOUBLE_VECTOR 22 -#define DATA_LONGDOUBLE_VECTOR 23 -#define DATA_VOID 24 +#define DATA_FLOAT 8 +#define DATA_DOUBLE 9 +#define DATA_LONGDOUBLE 10 +#define DATA_STRING 11 +#define DATA_STR_VECTOR 12 +#define DATA_CHAR_VECTOR 13 +#define DATA_UCHAR_VECTOR 14 +#define DATA_INT_VECTOR 15 +#define DATA_UINT_VECTOR 16 +#define DATA_LONG_VECTOR 17 +#define DATA_ULONG_VECTOR 18 +#define DATA_LONGLONG_VECTOR 19 +#define DATA_FLOAT_VECTOR 20 +#define DATA_DOUBLE_VECTOR 21 +#define DATA_LONGDOUBLE_VECTOR 22 +#define DATA_VOID 23 /* map comparison function */ @@ -119,9 +118,9 @@ public: class DataElement { private: - unsigned char data_type; - unsigned int data_size; - unsigned int unit_size; + int data_type; + long data_size; + int unit_size; char *data_val; @@ -244,74 +243,74 @@ public: int numChildren(); /* Number of children */ int numChildren(const char *name_in); /* Number of children named 'name_in' */ - DataElement &element(); /* DataElement at this node */ + DataElement *element(); /* DataElement at this node */ - DataNode &newChild(const char *name_in); - DataNode &child(const char *name_in, int index = 0) throw (DataInvalidChildException); - DataNode &child(int index) throw (DataInvalidChildException); + DataNode *newChild(const char *name_in); + DataNode *child(const char *name_in, int index = 0) throw (DataInvalidChildException); + DataNode *child(int index) throw (DataInvalidChildException); bool hasAnother(const char *name_in); /* useful for while() loops in conjunction with getNext() */ bool hasAnother(); - DataNode &getNext(const char *name_in) throw (DataInvalidChildException); /* get next of specified name */ - DataNode &getNext() throw (DataInvalidChildException); /* get next child */ + DataNode *getNext(const char *name_in) throw (DataInvalidChildException); /* get next of specified name */ + DataNode *getNext() throw (DataInvalidChildException); /* get next child */ void rewind(const char *name_in); /* rewind specific */ void rewind(); /* rewind generic */ void findAll(const char *name_in, vector<DataNode *> &node_list_out); - operator string () { string s; element().get(s); return s; } - operator char () { char v; element().get(v); return v; } - operator unsigned char () { unsigned char v; element().get(v); return v; } - operator int () { int v; element().get(v); return v; } - operator unsigned int () { unsigned int v; element().get(v); return v; } - operator long () { long v; element().get(v); return v; } - operator unsigned long () { unsigned long v; element().get(v); return v; } - operator long long () { long long v; element().get(v); return v; } - operator float () { float v; element().get(v); return v; } - operator double () { double v; element().get(v); return v; } - operator long double () { long double v; element().get(v); return v; } + operator string () { string s; element()->get(s); return s; } + operator char () { char v; element()->get(v); return v; } + operator unsigned char () { unsigned char v; element()->get(v); return v; } + operator int () { int v; element()->get(v); return v; } + operator unsigned int () { unsigned int v; element()->get(v); return v; } + operator long () { long v; element()->get(v); return v; } + operator unsigned long () { unsigned long v; element()->get(v); return v; } + operator long long () { long long v; element()->get(v); return v; } + operator float () { float v; element()->get(v); return v; } + operator double () { double v; element()->get(v); return v; } + operator long double () { long double v; element()->get(v); return v; } - operator vector<char> () { vector<char> v; element().get(v); return v; } - operator vector<unsigned char> () { vector<unsigned char> v; element().get(v); return v; } - operator vector<int> () { vector<int> v; element().get(v); return v; } - operator vector<unsigned int> () { vector<unsigned int> v; element().get(v); return v; } - operator vector<long> () { vector<long> v; element().get(v); return v; } - operator vector<unsigned long> () { vector<unsigned long> v; element().get(v); return v; } - operator vector<float> () { vector<float> v; element().get(v); return v; } - operator vector<double> () { vector<double> v; element().get(v); return v; } - operator vector<long double> () { vector<long double> v; element().get(v); return v; } + operator vector<char> () { vector<char> v; element()->get(v); return v; } + operator vector<unsigned char> () { vector<unsigned char> v; element()->get(v); return v; } + operator vector<int> () { vector<int> v; element()->get(v); return v; } + operator vector<unsigned int> () { vector<unsigned int> v; element()->get(v); return v; } + operator vector<long> () { vector<long> v; element()->get(v); return v; } + operator vector<unsigned long> () { vector<unsigned long> v; element()->get(v); return v; } + operator vector<float> () { vector<float> v; element()->get(v); return v; } + operator vector<double> () { vector<double> v; element()->get(v); return v; } + operator vector<long double> () { vector<long double> v; element()->get(v); return v; } - const string &operator= (const string &s) { element().set(s); return s; } + const string &operator= (const string &s) { element()->set(s); return s; } - char operator= (char i) { element().set(i); return i; } - unsigned char operator= (unsigned char i) { element().set(i); return i; } - int operator= (int i) { element().set(i); return i; } - unsigned int operator= (unsigned int i) { element().set(i); return i; } - long operator= (long i) { element().set(i); return i; } - unsigned long operator= (unsigned long i) { element().set(i); return i; } - long long operator= (long long i) { element().set(i); return i; } - float operator= (float i) { element().set(i); return i; } - double operator= (double i) { element().set(i); return i; } - long double operator= (long double i) { element().set(i); return i; } + char operator= (char i) { element()->set(i); return i; } + unsigned char operator= (unsigned char i) { element()->set(i); return i; } + int operator= (int i) { element()->set(i); return i; } + unsigned int operator= (unsigned int i) { element()->set(i); return i; } + long operator= (long i) { element()->set(i); return i; } + unsigned long operator= (unsigned long i) { element()->set(i); return i; } + long long operator= (long long i) { element()->set(i); return i; } + float operator= (float i) { element()->set(i); return i; } + double operator= (double i) { element()->set(i); return i; } + long double operator= (long double i) { element()->set(i); return i; } - vector<char> &operator= (vector<char> &v) { element().set(v); return v; } - vector<unsigned char> &operator= (vector<unsigned char> &v) { element().set(v); return v; } - vector<int> &operator= (vector<int> &v) { element().set(v); return v; } - vector<unsigned int> &operator= (vector<unsigned int> &v) { element().set(v); return v; } - vector<long> &operator= (vector<long> &v) { element().set(v); return v; } - vector<unsigned long> &operator= (vector<unsigned long> &v) { element().set(v); return v; } - vector<float> &operator= (vector<float> &v) { element().set(v); return v; } - vector<double> &operator= (vector<double> &v) { element().set(v); return v; } - vector<long double> &operator= (vector<long double> &v) { element().set(v); return v; } + vector<char> &operator= (vector<char> &v) { element()->set(v); return v; } + vector<unsigned char> &operator= (vector<unsigned char> &v) { element()->set(v); return v; } + vector<int> &operator= (vector<int> &v) { element()->set(v); return v; } + vector<unsigned int> &operator= (vector<unsigned int> &v) { element()->set(v); return v; } + vector<long> &operator= (vector<long> &v) { element()->set(v); return v; } + vector<unsigned long> &operator= (vector<unsigned long> &v) { element()->set(v); return v; } + vector<float> &operator= (vector<float> &v) { element()->set(v); return v; } + vector<double> &operator= (vector<double> &v) { element()->set(v); return v; } + vector<long double> &operator= (vector<long double> &v) { element()->set(v); return v; } - DataNode &operator[] (const char *name_in) { return getNext(name_in); } - DataNode &operator[] (int idx) { return child(idx); } + DataNode *operator[] (const char *name_in) { return getNext(name_in); } + DataNode *operator[] (int idx) { return child(idx); } bool operator() (const char *name_in) { return hasAnother(name_in); } bool operator() () { return hasAnother(); } - DataNode &operator ^(const char *name_in) { return newChild(name_in); } + DataNode *operator ^(const char *name_in) { return newChild(name_in); } }; @@ -333,7 +332,7 @@ public: DataTree(); ~DataTree(); - DataNode &rootNode(); + DataNode *rootNode(); void nodeToXML(DataNode *elem, TiXmlElement *elxml); void setFromXML(DataNode *elem, TiXmlNode *elxml, bool root_node=true, DT_FloatingPointPolicy fpp=USE_FLOAT); From 2c5eb4f946ef8c436d53e5d717c65937da651593 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Sat, 10 Jan 2015 11:00:03 -0500 Subject: [PATCH 10/11] load / save almost functional --- src/AppFrame.cpp | 4 ++-- src/util/DataTree.cpp | 50 +++++++++++++++++++++++++++---------------- src/util/DataTree.h | 6 ++++-- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 41e6e51..84c1309 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -338,7 +338,7 @@ bool AppFrame::loadSession(std::string fileName) { try { DataNode *header = l.rootNode()->getNext("header"); - std::string version = *header->getNext("version"); + std::string version(*header->getNext("version")); long long center_freq = *header->getNext("center_freq"); long long offset = *header->getNext("offset"); @@ -362,7 +362,7 @@ bool AppFrame::loadSession(std::string fileName) { float squelch_level = demod->hasAnother("squelch_level")?(float)*demod->getNext("squelch_level"):0; int squelch_enabled = demod->hasAnother("squelch_enabled")?(int)*demod->getNext("squelch_enabled"):0; int stereo = demod->hasAnother("stereo")?(int)*demod->getNext("stereo"):0; - std::string output_device = demod->hasAnother("output_device")?*demod->getNext("output_device"):""; + std::string output_device = demod->hasAnother("output_device")?string(*(demod->getNext("output_device"))):""; std::cout << "\tFound demodulator at frequency " << freq << " type " << type << std::endl; std::cout << "\t\tBandwidth: " << bandwidth << std::endl; diff --git a/src/util/DataTree.cpp b/src/util/DataTree.cpp index 1f3cce6..cb91ac2 100755 --- a/src/util/DataTree.cpp +++ b/src/util/DataTree.cpp @@ -33,23 +33,29 @@ using namespace std; #define STRINGIFY(A) #A -DataElement::DataElement() { - data_type = DATA_NULL; - data_val = NULL; - data_size = 0; - unit_size = 0; +DataElement::DataElement() : data_type(DATA_NULL), data_val(NULL), data_size(0), unit_size(0) { } DataElement::~DataElement() { - if (data_val) + if (data_val) { delete data_val; + data_val = NULL; + } } void DataElement::data_init(long data_size_in) { - if (data_val) + if (data_val) { delete data_val; + data_val = NULL; + } data_size = data_size_in; - data_val = new char[data_size]; + if (data_size) { + data_val = new char[data_size]; + } +} + +char * DataElement::getDataPointer() { + return data_val; } int DataElement::getDataType() { @@ -84,6 +90,7 @@ DataElementSetNumericDef(DATA_LONGDOUBLE, long double) void DataElement::set(const char *data_in, long size_in) { data_type = DATA_VOID; + if (!data_size) { return; } data_init(size_in); memcpy(data_val, data_in, data_size); } @@ -220,7 +227,9 @@ void DataElement::get(string &str_in) throw (DataTypeMismatchException) { str_in.erase(str_in.begin(), str_in.end()); } - str_in.append(data_val); + if (data_val) { + str_in.append(data_val); + } } void DataElement::get(vector<string> &strvect_in) throw (DataTypeMismatchException) { @@ -342,20 +351,23 @@ void DataElement::setSerialized(char *ser_str) { /* DataNode class */ -DataNode::DataNode() { - ptr = 0; - parentNode = NULL; +DataNode::DataNode(): ptr(0), parentNode(NULL) { + data_elem = new DataElement(); } -DataNode::DataNode(const char *name_in) { - ptr = 0; +DataNode::DataNode(const char *name_in): ptr(0), parentNode(NULL) { node_name = name_in; - parentNode = NULL; + data_elem = new DataElement(); } DataNode::~DataNode() { - for (vector<DataNode *>::iterator i = children.begin(); i != children.end(); i++) { - delete *i; + while (children.size()) { + DataNode *del = children.back(); + children.pop_back(); + delete del; + } + if (data_elem) { + delete data_elem; } } @@ -364,7 +376,7 @@ void DataNode::setName(const char *name_in) { } DataElement *DataNode::element() { - return &data_elem; + return data_elem; } DataNode *DataNode::newChild(const char *name_in) { @@ -1541,7 +1553,7 @@ bool DataTree::LoadFromFile(const std::string& filename) { dtHeader.setSerialized(hdr_serialized); DataNode *header = dtHeader.rootNode(); - string compressionType = *header->getNext("compression"); + string compressionType(*header->getNext("compression")); dataSize = *header->getNext("uncompressed_size"); bool uncompress = false; diff --git a/src/util/DataTree.h b/src/util/DataTree.h index 49273a9..8220e11 100755 --- a/src/util/DataTree.h +++ b/src/util/DataTree.h @@ -131,6 +131,7 @@ public: ~DataElement(); int getDataType(); + char *getDataPointer(); long getDataSize(); int getUnitSize(); @@ -224,7 +225,7 @@ private: map<string, unsigned int, string_less> childmap_ptr; string node_name; - DataElement data_elem; + DataElement *data_elem; unsigned int ptr; @@ -259,7 +260,8 @@ public: void findAll(const char *name_in, vector<DataNode *> &node_list_out); - operator string () { string s; element()->get(s); return s; } +// operator string () { string s; element()->get(s); return s; } + operator const char * () { if (element()->getDataType() == DATA_STRING) return element()->getDataPointer(); else return NULL; } operator char () { char v; element()->get(v); return v; } operator unsigned char () { unsigned char v; element()->get(v); return v; } operator int () { int v; element()->get(v); return v; } From f454c3424588eba5e9ff299ef2e258572d5a9c84 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" <cj@cubicproductions.com> Date: Sat, 10 Jan 2015 12:27:03 -0500 Subject: [PATCH 11/11] Save / Load session working --- src/AppFrame.cpp | 109 ++++++++++++++++++++++-------- src/AppFrame.h | 1 + src/CubicSDRDefs.h | 3 +- src/demod/DemodulatorInstance.cpp | 41 +++++++---- src/demod/DemodulatorMgr.cpp | 3 +- src/sdr/SDRPostThread.cpp | 9 ++- 6 files changed, 117 insertions(+), 49 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 84c1309..2dc848c 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -33,7 +33,7 @@ EVT_IDLE(AppFrame::OnIdle) wxEND_EVENT_TABLE() AppFrame::AppFrame() : - wxFrame(NULL, wxID_ANY, wxT("CubicSDR " CUBICSDR_VERSION " by Charles J. Cliffe (@ccliffe)")), activeDemodulator(NULL) { + wxFrame(NULL, wxID_ANY, wxT("CubicSDR " CUBICSDR_VERSION " by Charles J. Cliffe (@ccliffe)")), activeDemodulator(NULL) { wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); wxBoxSizer *demodOpts = new wxBoxSizer(wxVERTICAL); @@ -42,11 +42,11 @@ AppFrame::AppFrame() : wxBoxSizer *demodScopeTray = new wxBoxSizer(wxVERTICAL); demodModeSelector = new ModeSelectorCanvas(this, NULL); - demodModeSelector->addChoice(DEMOD_TYPE_FM,"FM"); - demodModeSelector->addChoice(DEMOD_TYPE_AM,"AM"); - demodModeSelector->addChoice(DEMOD_TYPE_LSB,"LSB"); - demodModeSelector->addChoice(DEMOD_TYPE_USB,"USB"); - demodModeSelector->addChoice(DEMOD_TYPE_DSB,"DSB"); + demodModeSelector->addChoice(DEMOD_TYPE_FM, "FM"); + demodModeSelector->addChoice(DEMOD_TYPE_AM, "AM"); + demodModeSelector->addChoice(DEMOD_TYPE_LSB, "LSB"); + demodModeSelector->addChoice(DEMOD_TYPE_USB, "USB"); + demodModeSelector->addChoice(DEMOD_TYPE_DSB, "DSB"); demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0); // demodTray->AddSpacer(2); @@ -115,6 +115,7 @@ AppFrame::AppFrame() : menu->Append(wxID_SAVE, "&Save Session"); menu->Append(wxID_SAVEAS, "Save Session &As.."); menu->AppendSeparator(); + menu->Append(wxID_RESET, "&Reset Session"); menu->Append(wxID_CLOSE); menuBar->Append(menu, wxT("&File")); @@ -159,6 +160,14 @@ AppFrame::AppFrame() : GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), DEFAULT_FREQ)); + wxAcceleratorEntry entries[3]; + entries[0].Set(wxACCEL_CTRL, (int) 'O', wxID_OPEN); + entries[1].Set(wxACCEL_CTRL, (int) 'S', wxID_SAVE); + entries[2].Set(wxACCEL_CTRL, (int) 'A', wxID_SAVEAS); + + wxAcceleratorTable accel(3, entries); + SetAcceleratorTable(accel); + // static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; // wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not"); // ShowFullScreen(true); @@ -181,18 +190,31 @@ void AppFrame::OnMenu(wxCommandEvent& event) { wxGetApp().setOffset(ofs); } } else if (event.GetId() == wxID_SAVE) { - wxFileDialog saveFileDialog(this, _("Save XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE|wxFD_OVERWRITE_PROMPT); - if (saveFileDialog.ShowModal() == wxID_CANCEL) { - return; - } - saveSession(saveFileDialog.GetPath().ToStdString()); + if (!currentSessionFile.empty()) { + saveSession(currentSessionFile); + } else { + wxFileDialog saveFileDialog(this, _("Save XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (saveFileDialog.ShowModal() == wxID_CANCEL) { + return; + } + saveSession(saveFileDialog.GetPath().ToStdString()); + } } else if (event.GetId() == wxID_OPEN) { - wxFileDialog openFileDialog(this, _("Open XML Session file"), "", "","XML files (*.xml)|*.xml", wxFD_OPEN|wxFD_FILE_MUST_EXIST); - if (openFileDialog.ShowModal() == wxID_CANCEL) { - return; - } - loadSession(openFileDialog.GetPath().ToStdString()); + wxFileDialog openFileDialog(this, _("Open XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_OPEN | wxFD_FILE_MUST_EXIST); + if (openFileDialog.ShowModal() == wxID_CANCEL) { + return; + } + loadSession(openFileDialog.GetPath().ToStdString()); } else if (event.GetId() == wxID_SAVEAS) { + wxFileDialog saveFileDialog(this, _("Save XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (saveFileDialog.ShowModal() == wxID_CANCEL) { + return; + } + saveSession(saveFileDialog.GetPath().ToStdString()); + } else if (event.GetId() == wxID_RESET) { + wxGetApp().getDemodMgr().terminateAll(); + wxGetApp().setFrequency(DEFAULT_FREQ); + wxGetApp().setOffset(0); } else if (event.GetId() == wxID_EXIT) { Close(false); } @@ -319,8 +341,8 @@ void AppFrame::saveSession(std::string fileName) { *demod->newChild("frequency") = (*instance_i)->getFrequency(); *demod->newChild("type") = (*instance_i)->getDemodulatorType(); *demod->newChild("squelch_level") = (*instance_i)->getSquelchLevel(); - *demod->newChild("squelch_enabled") = (*instance_i)->isSquelchEnabled()?1:0; - *demod->newChild("stereo") = (*instance_i)->isStereo()?1:0; + *demod->newChild("squelch_enabled") = (*instance_i)->isSquelchEnabled() ? 1 : 0; + *demod->newChild("stereo") = (*instance_i)->isStereo() ? 1 : 0; *demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name; } @@ -333,7 +355,7 @@ bool AppFrame::loadSession(std::string fileName) { return false; } -// wxGetApp().getDemodMgr().terminateAll(); + wxGetApp().getDemodMgr().terminateAll(); try { DataNode *header = l.rootNode()->getNext("header"); @@ -346,6 +368,8 @@ bool AppFrame::loadSession(std::string fileName) { std::cout << "\tCenter Frequency: " << center_freq << std::endl; std::cout << "\tOffset: " << offset << std::endl; + wxGetApp().setOffset(offset); + wxGetApp().setFrequency(center_freq); DataNode *demodulators = l.rootNode()->getNext("demodulators"); @@ -358,17 +382,47 @@ bool AppFrame::loadSession(std::string fileName) { long bandwidth = *demod->getNext("bandwidth"); long long freq = *demod->getNext("frequency"); - int type = demod->hasAnother("type")?*demod->getNext("type"):DEMOD_TYPE_FM; - float squelch_level = demod->hasAnother("squelch_level")?(float)*demod->getNext("squelch_level"):0; - int squelch_enabled = demod->hasAnother("squelch_enabled")?(int)*demod->getNext("squelch_enabled"):0; - int stereo = demod->hasAnother("stereo")?(int)*demod->getNext("stereo"):0; - std::string output_device = demod->hasAnother("output_device")?string(*(demod->getNext("output_device"))):""; + int type = demod->hasAnother("type") ? *demod->getNext("type") : DEMOD_TYPE_FM; + float squelch_level = demod->hasAnother("squelch_level") ? (float) *demod->getNext("squelch_level") : 0; + int squelch_enabled = demod->hasAnother("squelch_enabled") ? (int) *demod->getNext("squelch_enabled") : 0; + int stereo = demod->hasAnother("stereo") ? (int) *demod->getNext("stereo") : 0; + std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : ""; - std::cout << "\tFound demodulator at frequency " << freq << " type " << type << std::endl; + DemodulatorInstance *newDemod = wxGetApp().getDemodMgr().newThread(); + newDemod->setDemodulatorType(type); + newDemod->setBandwidth(bandwidth); + newDemod->setFrequency(freq); + newDemod->updateLabel(freq); + if (squelch_enabled) { + newDemod->setSquelchEnabled(true); + newDemod->setSquelchLevel(squelch_level); + } + if (stereo) { + newDemod->setStereo(true); + } + + bool found_device = false; + std::map<int, RtAudio::DeviceInfo>::iterator i; + for (i = outputDevices.begin(); i != outputDevices.end(); i++) { + if (i->second.name == output_device) { + newDemod->setOutputDevice(i->first); + found_device = true; + } + } + + if (!found_device) { + std::cout << "\tWarning: named output device '" << output_device << "' was not found. Using default output."; + } + + newDemod->run(); + + wxGetApp().bindDemodulator(newDemod); + + std::cout << "\tAdded demodulator at frequency " << freq << " type " << type << std::endl; std::cout << "\t\tBandwidth: " << bandwidth << std::endl; std::cout << "\t\tSquelch Level: " << squelch_level << std::endl; - std::cout << "\t\tSquelch Enabled: " << (squelch_enabled?"true":"false") << std::endl; - std::cout << "\t\tStereo: " << (stereo?"true":"false") << std::endl; + std::cout << "\t\tSquelch Enabled: " << (squelch_enabled ? "true" : "false") << std::endl; + std::cout << "\t\tStereo: " << (stereo ? "true" : "false") << std::endl; std::cout << "\t\tOutput Device: " << output_device << std::endl; } @@ -381,4 +435,5 @@ bool AppFrame::loadSession(std::string fileName) { return false; } + currentSessionFile = fileName; } diff --git a/src/AppFrame.h b/src/AppFrame.h index ca0df5b..cb7d378 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -14,6 +14,7 @@ #define wxID_RT_AUDIO_DEVICE 1000 #define wxID_SET_FREQ_OFFSET 2001 +#define wxID_RESET 2002 // Define a new frame type class AppFrame: public wxFrame { diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 1c0493b..5c2338d 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -11,8 +11,7 @@ #endif #define DEFAULT_FFT_SIZE 2048 -//#define DEFAULT_FREQ 98900000 -#define DEFAULT_FREQ 132000000 +#define DEFAULT_FREQ 100000000 #define AUDIO_FREQUENCY 44100 #include <mutex> diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 72c1451..a203885 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -213,7 +213,9 @@ float DemodulatorInstance::getSquelchLevel() { } void DemodulatorInstance::setOutputDevice(int device_id) { - if (audioThread) { + if (!active) { + audioThread->setInitOutputDevice(device_id); + } else if (audioThread) { AudioThreadCommand command; command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE; command.int_value = device_id; @@ -232,7 +234,12 @@ void DemodulatorInstance::checkBandwidth() { } void DemodulatorInstance::setDemodulatorType(int demod_type_in) { - if (demodulatorThread && threadQueueControl) { + if (!active) { + currentDemodType = demod_type_in; + checkBandwidth(); + demodulatorPreThread->getParams().demodType = currentDemodType; + demodulatorThread->setDemodulatorType(currentDemodType); + } else if (demodulatorThread && threadQueueControl) { DemodulatorThreadControlCommand command; command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE; currentDemodType = demod_type_in; @@ -247,7 +254,11 @@ int DemodulatorInstance::getDemodulatorType() { } void DemodulatorInstance::setBandwidth(int bw) { - if (demodulatorPreThread && threadQueueCommand) { + if (!active) { + currentBandwidth = bw; + checkBandwidth(); + demodulatorPreThread->getParams().bandwidth = currentBandwidth; + } else if (demodulatorPreThread && threadQueueCommand) { DemodulatorThreadCommand command; command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH; currentBandwidth = bw; @@ -255,7 +266,6 @@ void DemodulatorInstance::setBandwidth(int bw) { command.llong_value = currentBandwidth; threadQueueCommand->push(command); } - demodulatorPreThread->getParams().bandwidth; } int DemodulatorInstance::getBandwidth() { @@ -266,17 +276,20 @@ int DemodulatorInstance::getBandwidth() { } void DemodulatorInstance::setFrequency(long long freq) { - if ((freq - getBandwidth()/2) <= 0) { - freq = getBandwidth()/2; + if ((freq - getBandwidth() / 2) <= 0) { + freq = getBandwidth() / 2; } - if (demodulatorPreThread && threadQueueCommand) { - DemodulatorThreadCommand command; - command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY; - currentFrequency = freq; - command.llong_value = freq; - threadQueueCommand->push(command); - } - demodulatorPreThread->getParams().bandwidth; + if (!active) { + currentFrequency = freq; + demodulatorPreThread->getParams().frequency = currentFrequency; + } else if (demodulatorPreThread && threadQueueCommand) { + DemodulatorThreadCommand command; + command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY; + currentFrequency = freq; + command.llong_value = freq; + threadQueueCommand->push(command); + } + demodulatorPreThread->getParams().bandwidth; } long long DemodulatorInstance::getFrequency() { diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index 7b32bab..91bcd7a 100644 --- a/src/demod/DemodulatorMgr.cpp +++ b/src/demod/DemodulatorMgr.cpp @@ -29,6 +29,7 @@ DemodulatorInstance *DemodulatorMgr::newThread() { void DemodulatorMgr::terminateAll() { while (demods.size()) { DemodulatorInstance *d = demods.back(); + wxGetApp().removeDemodulator(d); deleteThread(d); } } @@ -54,8 +55,8 @@ void DemodulatorMgr::deleteThread(DemodulatorInstance *demod) { if (i != demods.end()) { demods.erase(i); - demod->terminate(); } + demod->terminate(); demods_deleted.push_back(demod); diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 9be2080..7282bca 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -130,9 +130,8 @@ void SDRPostThread::threadMain() { std::vector<DemodulatorInstance *>::iterator i; for (i = demodulators.begin(); i != demodulators.end(); i++) { DemodulatorInstance *demod = *i; - - if (demod->getParams().frequency != data_in->frequency - && abs(data_in->frequency - demod->getParams().frequency) > (SRATE / 2)) { + if (demod->getFrequency() != data_in->frequency + && abs(data_in->frequency - demod->getFrequency()) > (SRATE / 2)) { continue; } activeDemods++; @@ -165,8 +164,8 @@ void SDRPostThread::threadMain() { DemodulatorInstance *demod = *i; DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod; - if (demod->getParams().frequency != data_in->frequency - && abs(data_in->frequency - demod->getParams().frequency) > (SRATE / 2)) { + if (demod->getFrequency() != data_in->frequency + && abs(data_in->frequency - demod->getFrequency()) > (SRATE / 2)) { if (demod->isActive()) { demod->setActive(false); DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;