| /* |
| www.sourceforge.net/projects/tinyxml |
| Original code by 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 <ctype.h> |
| |
| #ifdef TIXML_USE_STL |
| #include <sstream> |
| #include <iostream> |
| #endif |
| |
| #include "tinyxml.h" |
| |
| FILE* TiXmlFOpen( const char* filename, const char* mode ); |
| |
| 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; |
| target->location = location; |
| } |
| |
| |
| 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::TINYXML_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::TINYXML_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::TINYXML_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::TINYXML_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 ) |
| return 0; |
| |
| if ( replaceThis->parent != this ) |
| return 0; |
| |
| if ( withThis.ToDocument() ) { |
| // A document can never be a child. Thanks to Noam. |
| TiXmlDocument* document = GetDocument(); |
| if ( document ) |
| document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
| 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 ) { |
| return false; |
| } |
| |
| 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::TINYXML_ELEMENT ) |
| { |
| firstChild = lastChild = 0; |
| value = _value; |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| TiXmlElement::TiXmlElement( const std::string& _value ) |
| : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) |
| { |
| firstChild = lastChild = 0; |
| value = _value; |
| } |
| #endif |
| |
| |
| TiXmlElement::TiXmlElement( const TiXmlElement& copy) |
| : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) |
| { |
| firstChild = lastChild = 0; |
| copy.CopyTo( this ); |
| } |
| |
| |
| TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) |
| { |
| ClearThis(); |
| base.CopyTo( this ); |
| return *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* attrib = attributeSet.Find( name ); |
| if ( attrib ) |
| return &attrib->ValueStr(); |
| return 0; |
| } |
| #endif |
| |
| |
| const char* TiXmlElement::Attribute( const char* name, int* i ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| const char* result = 0; |
| |
| if ( attrib ) { |
| result = attrib->Value(); |
| if ( i ) { |
| attrib->QueryIntValue( i ); |
| } |
| } |
| return result; |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| const std::string* result = 0; |
| |
| if ( attrib ) { |
| result = &attrib->ValueStr(); |
| if ( i ) { |
| attrib->QueryIntValue( i ); |
| } |
| } |
| return result; |
| } |
| #endif |
| |
| |
| const char* TiXmlElement::Attribute( const char* name, double* d ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| const char* result = 0; |
| |
| if ( attrib ) { |
| result = attrib->Value(); |
| if ( d ) { |
| attrib->QueryDoubleValue( d ); |
| } |
| } |
| return result; |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| const std::string* result = 0; |
| |
| if ( attrib ) { |
| result = &attrib->ValueStr(); |
| if ( d ) { |
| attrib->QueryDoubleValue( d ); |
| } |
| } |
| return result; |
| } |
| #endif |
| |
| |
| int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| if ( !attrib ) |
| return TIXML_NO_ATTRIBUTE; |
| return attrib->QueryIntValue( ival ); |
| } |
| |
| |
| int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const |
| { |
| const TiXmlAttribute* node = attributeSet.Find( name ); |
| if ( !node ) |
| return TIXML_NO_ATTRIBUTE; |
| |
| int ival = 0; |
| int result = node->QueryIntValue( &ival ); |
| *value = (unsigned)ival; |
| return result; |
| } |
| |
| |
| int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const |
| { |
| const TiXmlAttribute* node = attributeSet.Find( name ); |
| if ( !node ) |
| return TIXML_NO_ATTRIBUTE; |
| |
| int result = TIXML_WRONG_TYPE; |
| if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) |
| || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) |
| || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) |
| { |
| *bval = true; |
| result = TIXML_SUCCESS; |
| } |
| else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) |
| || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) |
| || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) |
| { |
| *bval = false; |
| result = TIXML_SUCCESS; |
| } |
| return result; |
| } |
| |
| |
| |
| #ifdef TIXML_USE_STL |
| int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| if ( !attrib ) |
| return TIXML_NO_ATTRIBUTE; |
| return attrib->QueryIntValue( ival ); |
| } |
| #endif |
| |
| |
| int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| if ( !attrib ) |
| return TIXML_NO_ATTRIBUTE; |
| return attrib->QueryDoubleValue( dval ); |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const |
| { |
| const TiXmlAttribute* attrib = attributeSet.Find( name ); |
| if ( !attrib ) |
| return TIXML_NO_ATTRIBUTE; |
| return attrib->QueryDoubleValue( dval ); |
| } |
| #endif |
| |
| |
| void TiXmlElement::SetAttribute( const char * name, int val ) |
| { |
| TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); |
| if ( attrib ) { |
| attrib->SetIntValue( val ); |
| } |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| void TiXmlElement::SetAttribute( const std::string& name, int val ) |
| { |
| TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); |
| if ( attrib ) { |
| attrib->SetIntValue( val ); |
| } |
| } |
| #endif |
| |
| |
| void TiXmlElement::SetDoubleAttribute( const char * name, double val ) |
| { |
| TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); |
| if ( attrib ) { |
| attrib->SetDoubleValue( val ); |
| } |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) |
| { |
| TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); |
| if ( attrib ) { |
| attrib->SetDoubleValue( val ); |
| } |
| } |
| #endif |
| |
| |
| void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) |
| { |
| TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); |
| if ( attrib ) { |
| attrib->SetValue( cvalue ); |
| } |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) |
| { |
| TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); |
| if ( attrib ) { |
| attrib->SetValue( _value ); |
| } |
| } |
| #endif |
| |
| |
| void TiXmlElement::Print( FILE* cfile, int depth ) const |
| { |
| int i; |
| assert( cfile ); |
| for ( i=0; i<depth; i++ ) { |
| fprintf( cfile, " " ); |
| } |
| |
| fprintf( cfile, "<%s", value.c_str() ); |
| |
| const TiXmlAttribute* attrib; |
| for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) |
| { |
| fprintf( cfile, " " ); |
| attrib->Print( cfile, depth ); |
| } |
| |
| // There are 3 different formatting approaches: |
| // 1) An element without children is printed as a <foo /> node |
| // 2) An element with only a text child is printed as <foo> text </foo> |
| // 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, "</%s>", 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<depth; ++i ) { |
| fprintf( cfile, " " ); |
| } |
| fprintf( cfile, "</%s>", 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::TINYXML_DOCUMENT ) |
| { |
| tabsize = 4; |
| useMicrosoftBOM = false; |
| ClearError(); |
| } |
| |
| TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) |
| { |
| tabsize = 4; |
| useMicrosoftBOM = false; |
| value = documentName; |
| ClearError(); |
| } |
| |
| |
| #ifdef TIXML_USE_STL |
| TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) |
| { |
| tabsize = 4; |
| useMicrosoftBOM = false; |
| value = documentName; |
| ClearError(); |
| } |
| #endif |
| |
| |
| TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) |
| { |
| copy.CopyTo( this ); |
| } |
| |
| |
| TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) |
| { |
| Clear(); |
| copy.CopyTo( this ); |
| return *this; |
| } |
| |
| |
| bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) |
| { |
| return LoadFile( Value(), encoding ); |
| } |
| |
| |
| bool TiXmlDocument::SaveFile() const |
| { |
| return SaveFile( Value() ); |
| } |
| |
| bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) |
| { |
| 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; |
| } |
| |
| // Subtle bug here. TinyXml did use fgets. But from the XML spec: |
| // 2.11 End-of-Line Handling |
| // <snip> |
| // <quote> |
| // ...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. |
| // </quote> |
| // |
| // 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; |
| } |
| |
| // Process the buffer in place to normalize new lines. (See comment above.) |
| // Copies from the 'p' to 'q' pointer, where p can advance faster if |
| // a newline-carriage return is hit. |
| // |
| // Wikipedia: |
| // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or |
| // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... |
| // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others |
| // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS |
| // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 |
| |
| const char* p = buf; // the read head |
| char* q = buf; // the write head |
| const char CR = 0x0d; |
| const char LF = 0x0a; |
| |
| buf[length] = 0; |
| while( *p ) { |
| assert( p < (buf+length) ); |
| assert( q <= (buf+length) ); |
| assert( q <= p ); |
| |
| if ( *p == CR ) { |
| *q++ = LF; |
| p++; |
| if ( *p == LF ) { // check for CR+LF (and skip LF) |
| p++; |
| } |
| } |
| else { |
| *q++ = *p++; |
| } |
| } |
| assert( q <= (buf+length) ); |
| *q = 0; |
| |
| Parse( buf, 0, encoding ); |
| |
| delete [] buf; |
| return !Error(); |
| } |
| |
| |
| 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), "%g", _value); |
| #else |
| sprintf (buf, "%g", _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::TINYXML_COMMENT ) |
| { |
| copy.CopyTo( this ); |
| } |
| |
| |
| TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) |
| { |
| Clear(); |
| base.CopyTo( this ); |
| return *this; |
| } |
| |
| |
| void TiXmlComment::Print( FILE* cfile, int depth ) const |
| { |
| assert( cfile ); |
| for ( int i=0; i<depth; i++ ) |
| { |
| fprintf( cfile, " " ); |
| } |
| fprintf( cfile, "<!--%s-->", 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<depth; i++ ) { |
| fprintf( cfile, " " ); |
| } |
| fprintf( cfile, "<![CDATA[%s]]>\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::TINYXML_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::TINYXML_DECLARATION ) |
| { |
| version = _version; |
| encoding = _encoding; |
| standalone = _standalone; |
| } |
| #endif |
| |
| |
| TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) |
| : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) |
| { |
| copy.CopyTo( this ); |
| } |
| |
| |
| TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) |
| { |
| Clear(); |
| copy.CopyTo( this ); |
| return *this; |
| } |
| |
| |
| void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const |
| { |
| if ( cfile ) fprintf( cfile, "<?xml " ); |
| if ( str ) (*str) += "<?xml "; |
| |
| if ( !version.empty() ) { |
| if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ()); |
| if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; } |
| } |
| if ( !encoding.empty() ) { |
| if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); |
| if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; } |
| } |
| if ( !standalone.empty() ) { |
| if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); |
| if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; } |
| } |
| 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<depth; i++ ) |
| fprintf( cfile, " " ); |
| fprintf( cfile, "<%s>", 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 |
| TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const |
| { |
| for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) |
| { |
| if ( node->name == name ) |
| return node; |
| } |
| return 0; |
| } |
| |
| TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) |
| { |
| TiXmlAttribute* attrib = Find( _name ); |
| if ( !attrib ) { |
| attrib = new TiXmlAttribute(); |
| Add( attrib ); |
| attrib->SetName( _name ); |
| } |
| return attrib; |
| } |
| #endif |
| |
| |
| TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const |
| { |
| for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) |
| { |
| if ( strcmp( node->name.c_str(), name ) == 0 ) |
| return node; |
| } |
| return 0; |
| } |
| |
| |
| TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) |
| { |
| TiXmlAttribute* attrib = Find( _name ); |
| if ( !attrib ) { |
| attrib = new TiXmlAttribute(); |
| Add( attrib ); |
| attrib->SetName( _name ); |
| } |
| return attrib; |
| } |
| |
| |
| #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 && i<count; |
| child = child->NextSibling(), ++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 && i<count; |
| child = child->NextSibling( 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 && i<count; |
| child = child->NextSiblingElement(), ++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 && i<count; |
| child = child->NextSiblingElement( 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 += "</"; |
| buffer += element.Value(); |
| buffer += ">"; |
| DoLineBreak(); |
| } |
| return true; |
| } |
| |
| |
| bool TiXmlPrinter::Visit( const TiXmlText& text ) |
| { |
| if ( text.CDATA() ) |
| { |
| DoIndent(); |
| buffer += "<![CDATA["; |
| buffer += text.Value(); |
| 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 += "<!--"; |
| buffer += comment.Value(); |
| buffer += "-->"; |
| DoLineBreak(); |
| return true; |
| } |
| |
| |
| bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) |
| { |
| DoIndent(); |
| buffer += "<"; |
| buffer += unknown.Value(); |
| buffer += ">"; |
| DoLineBreak(); |
| return true; |
| } |
| |