[gunzemulator] r349 committed - Added the TinyXML parser. We're lucky - it's MIT licensed just like us...

1 view
Skip to first unread message

gunzem...@googlecode.com

unread,
Jun 27, 2010, 10:25:45 PM6/27/10
to gogo-dev...@googlegroups.com
Revision: 349
Author: cg.wowus.cg
Date: Sun Jun 27 19:25:07 2010
Log: Added the TinyXML parser. We're lucky - it's MIT licensed just like us.
I still need to pull the tests out into seperate files, and hopefully
clean up the implementation a bit. Oh well.
http://code.google.com/p/gunzemulator/source/detail?r=349

Added:
/trunk/include/tinyxml
/trunk/include/tinyxml/tinystr.h
/trunk/include/tinyxml/tinyxml.h
/trunk/tinyxml
/trunk/tinyxml/src
/trunk/tinyxml/src/CMakeLists.txt
/trunk/tinyxml/src/tinystr.cpp
/trunk/tinyxml/src/tinyxml.cpp
/trunk/tinyxml/src/tinyxmlerror.cpp
/trunk/tinyxml/src/tinyxmlparser.cpp
/trunk/tinyxml/test
/trunk/tinyxml/test/CMakeLists.txt
/trunk/tinyxml/test/utf8test.xml
/trunk/tinyxml/test/utf8testverify.xml
/trunk/tinyxml/test/xmltest.cpp
Modified:
/trunk/CMakeLists.txt

=======================================
--- /dev/null
+++ /trunk/include/tinyxml/tinystr.h Sun Jun 27 19:25:07 2010
@@ -0,0 +1,323 @@
+/*
+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
+ #define TIXML_USE_STL
+#endif
+
+#ifndef TIXML_USE_STL
+
+#ifndef TIXML_STRING_INCLUDED
+#define TIXML_STRING_INCLUDED
+
+#include <assert.h>
+#include <string.h>
+
+/* 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<size_type>( 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<size_type>( 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<Rep*>(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<Rep*>( 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<int*>( 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
=======================================
--- /dev/null
+++ /trunk/include/tinyxml/tinyxml.h Sun Jun 27 19:25:07 2010
@@ -0,0 +1,1801 @@
+/*
+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 TIXML_USE_STL
+ #define TIXML_USE_STL
+#endif
+
+#ifndef TINYXML_INCLUDED
+#define TINYXML_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4530 )
+#pragma warning( disable : 4786 )
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+// Help out windows:
+#if defined( _DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+
+#ifdef TIXML_USE_STL
+ #include <string>
+ #include <iostream>
+ #include <sstream>
+ #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_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_SSCANF sscanf
+ #elif defined(__GNUC__) && (__GNUC__ >= 3 )
+ // GCC version 3 and higher.s
+ //#warning( "Using sn* functions." )
+ #define TIXML_SNPRINTF snprintf
+ #define TIXML_SSCANF sscanf
+ #else
+ #define TIXML_SNPRINTF snprintf
+ #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 = 6;
+const int TIXML_PATCH_VERSION = 1;
+
+/* 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.
+};
+
+
+/**
+ Implements the interface to the "Visitor pattern" (see the Accept()
method.)
+ 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 simply called with Visit().
+
+ If you return 'true' from a Visit method, recursive parsing will
continue. If you return
+ false, <b>no children of this node or its sibilings</b> 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_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
+ {
+ TINYXML_DOCUMENT,
+ TINYXML_ELEMENT,
+ TINYXML_COMMENT,
+ TINYXML_UNKNOWN,
+ TINYXML_TEXT,
+ TINYXML_DECLARATION,
+ TINYXML_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; }
+
+ TiXmlAttribute* Find( const char* _name ) const;
+ TiXmlAttribute* FindOrCreate( const char* _name );
+
+# ifdef TIXML_USE_STL
+ TiXmlAttribute* Find( const std::string& _name ) const;
+ TiXmlAttribute* FindOrCreate( const std::string& _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;
***The diff for this file has been truncated for email.***
=======================================
--- /dev/null
+++ /trunk/tinyxml/src/CMakeLists.txt Sun Jun 27 19:25:07 2010
@@ -0,0 +1,8 @@
+set(TINYXML_SRC
+ tinystr.cpp
+ tinyxml.cpp
+ tinyxmlerror.cpp
+ tinyxmlparser.cpp
+)
+
+add_library(tinyxml ${TINYXML_SRC})
=======================================
--- /dev/null
+++ /trunk/tinyxml/src/tinystr.cpp Sun Jun 27 19:25:07 2010
@@ -0,0 +1,115 @@
+/*
+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.
+ */
+
+#include <tinyxml/tinystr.h>
+
+#ifndef TIXML_USE_STL
+
+// 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<TiXmlString::size_type>(
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<TiXmlString::size_type>(
strlen(a) );
+ tmp.reserve(a_len + b.length());
+ tmp.append(a, a_len);
+ tmp += b;
+ return tmp;
+}
+
+
+#endif // TIXML_USE_STL
=======================================
--- /dev/null
+++ /trunk/tinyxml/src/tinyxml.cpp Sun Jun 27 19:25:07 2010
@@ -0,0 +1,1838 @@
+/*
+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 <ctype.h>
+
+#include <tinyxml/tinyxml.h>
+
+#ifdef TIXML_USE_STL
+#include <sstream>
+#include <iostream>
+#endif
+
+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.
+ // &#xA9; -- 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 );
+}
+
+
+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* 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 );
+}
+
+
+#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 );
+}
+
+
+void TiXmlDocument::operator=( const TiXmlDocument& copy )
+{
+ Clear();
+ copy.CopyTo( 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.
***The diff for this file has been truncated for email.***
=======================================
--- /dev/null
+++ /trunk/tinyxml/src/tinyxmlerror.cpp Sun Jun 27 19:25:07 2010
@@ -0,0 +1,52 @@
+/*
+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 <tinyxml/tinyxml.h>
+
+// The goal of the seperate error file is to make the first
+// step towards localization. tinyxml (currently) only supports
+// english error messages, but the could now be translated.
+//
+// It also cleans up the code a bit.
+//
+
+const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
+{
+ "No error",
+ "Error",
+ "Failed to open file",
+ "Error parsing Element.",
+ "Failed to read Element name",
+ "Error reading Element value.",
+ "Error reading Attributes.",
+ "Error: empty tag.",
+ "Error reading end tag.",
+ "Error parsing Unknown.",
+ "Error parsing Comment.",
+ "Error parsing Declaration.",
+ "Error document empty.",
+ "Error null (0) or unexpected EOF found in input stream.",
+ "Error parsing CDATA.",
+ "Error when TiXmlDocument added to document, because TiXmlDocument can
only be at the root.",
+};
=======================================
--- /dev/null
+++ /trunk/tinyxml/src/tinyxmlparser.cpp Sun Jun 27 19:25:07 2010
@@ -0,0 +1,1634 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2002 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>
+#include <stddef.h>
+
+#include <tinyxml/tinyxml.h>
+
+//#define DEBUG_PARSER
+#if defined( DEBUG_PARSER )
+# if defined( DEBUG ) && defined( _MSC_VER )
+# include <windows.h>
+# 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 ] =
+{
+ { "&amp;", 5, '&' },
+ { "&lt;", 4, '<' },
+ { "&gt;", 4, '>' },
+ { "&quot;", 6, '\"' },
+ { "&apos;", 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 ) ) // Still using old rules for white space.
+ ++p;
+ else
+ break;
+ }
+ }
+ else
+ {
+ while ( *p && IsWhiteSpace( *p ) )
+ ++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; i<NUM_ENTITY; ++i )
+ {
+ if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
+ {
+ assert( strlen( entity[i].str ) == entity[i].strLength );
+ *value = entity[i].chr;
+ *length = 1;
+ return ( p + entity[i].strLength );
+ }
+ }
+
+ // So it wasn't an entity, its unrecognized, or something like that.
+ *value = *p; // Don't put back the last one, since we return it!
+ //*length = 1; // Leave unrecognized entities - this doesn't really work.
+ // Just writes strange XML.
+ return p+1;
+}
+
+
+bool TiXmlBase::StringEqual( const char* p,
+ const char* tag,
+ bool ignoreCase,
+ TiXmlEncoding encoding )
+{
+ assert( p );
+ assert( tag );
+ if ( !p || !*p )
+ {
+ assert( 0 );
+ return false;
+ }
+
+ const char* q = p;
+
+ if ( ignoreCase )
+ {
+ while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding
) )
+ {
+ ++q;
+ ++tag;
+ }
+
+ if ( *tag == 0 )
+ return true;
+ }
+ else
+ {
+ while ( *q && *tag && *q == *tag )
+ {
+ ++q;
+ ++tag;
+ }
+
+ if ( *tag == 0 ) // Have we found the end of the tag, and everything
equal?
+ return true;
+ }
+ return false;
+}
+
+const char* TiXmlBase::ReadText( const char* p,
+ TIXML_STRING * text,
+ bool trimWhiteSpace,
+ const char* endTag,
+ bool caseInsensitive,
+ TiXmlEncoding encoding )
+{
+ *text = "";
+ if ( !trimWhiteSpace // certain tags always keep whitespace
+ || !condenseWhiteSpace ) // if true, whitespace is always kept
+ {
+ // Keep all the white space.
+ while ( p && *p
+ && !StringEqual( p, endTag, caseInsensitive, encoding )
+ )
+ {
+ int len;
+ char cArr[4] = { 0, 0, 0, 0 };
+ p = GetChar( p, cArr, &len, encoding );
+ text->append( 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 )
+ 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;
+ }
+
+ 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: <!--
+ // - Decleration: <?xml
+ // - Everthing else is unknown to tinyxml.
+ //
+
+ const char* xmlHeader = { "<?xml" };
+ const char* commentHeader = { "<!--" };
+ const char* dtdHeader = { "<!" };
+ const char* cdataHeader = { "<![CDATA[" };
+
+ if ( StringEqual( p, xmlHeader, true, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Declaration\n" );
+ #endif
+ returnNode = new TiXmlDeclaration();
+ }
+ else if ( StringEqual( p, commentHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Comment\n" );
+ #endif
+ returnNode = new TiXmlComment();
+ }
+ else if ( StringEqual( p, cdataHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing CDATA\n" );
+ #endif
+ TiXmlText* text = new TiXmlText( "" );
+ text->SetCDATA( true );
+ returnNode = text;
+ }
+ else if ( StringEqual( p, dtdHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Unknown(1)\n" );
+ #endif
+ returnNode = new TiXmlUnknown();
+ }
+ else if ( IsAlpha( *(p+1), encoding )
+ || *(p+1) == '_' )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Element\n" );
+ #endif
+ returnNode = new TiXmlElement( "" );
+ }
+ else
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Unknown(2)\n" );
+ #endif
+ returnNode = new TiXmlUnknown();
+ }
+
+ if ( returnNode )
+ {
+ // Set the parent, so it can report errors
+ returnNode->parent = this;
+ }
+ return returnNode;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
+{
+ // We're called with some amount of pre-parsing. That is, some of "this"
+ // element is in "tag". Go ahead and stream to the closing ">"
+ 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 == '>' )
+ break;
+ }
+
+ if ( tag->length() < 3 ) return;
+
+ // Okay...if we are a "/>" tag, then we're done. We've read a complete
tag.
+ // If not, identify and stream.
+
+ if ( tag->at( tag->length() - 1 ) == '>'
+ && tag->at( tag->length() - 2 ) == '/' )
+ {
+ // All good!
+ return;
+ }
+ else if ( tag->at( tag->length() - 1 ) == '>' )
+ {
+ // There is more. Could be:
+ // text
+ // cdata text (which looks like another node)
+ // closing tag
+ // another node.
+ for ( ;; )
+ {
+ StreamWhiteSpace( in, tag );
+
+ // Do we have text?
+ if ( in->good() && in->peek() != '<' )
+ {
+ // Yep, text.
+ TiXmlText text( "" );
+ text.StreamIn( in, tag );
+
+ // What follows text is a closing tag or another node.
+ // Go around again and figure it out.
+ continue;
+ }
+
+ // We now have either a closing tag...or another node.
+ // We should be at a "<", regardless.
+ if ( !in->good() ) return;
+ assert( in->peek() == '<' );
+ int tagIndex = (int) tag->length();
+
+ bool closingTag = false;
+ bool firstCharFound = false;
+
+ for( ;; )
+ {
+ if ( !in->good() )
+ return;
+
+ int c = in->peek();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0,
TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ if ( c == '>' )
+ break;
+
+ *tag += (char) c;
+ in->get();
+
+ // Early out if we find the CDATA id.
+ if ( c == '[' && tag->size() >= 9 )
+ {
+ size_t len = tag->size();
+ const char* start = tag->c_str() + len - 9;
+ if ( strcmp( start, "<![CDATA[" ) == 0 ) {
+ assert( !closingTag );
+ break;
+ }
+ }
+
+ if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
+ {
***The diff for this file has been truncated for email.***
=======================================
--- /dev/null
+++ /trunk/tinyxml/test/CMakeLists.txt Sun Jun 27 19:25:07 2010
@@ -0,0 +1,15 @@
+set(TINYXML_TESTS
+ xmltest.cpp
+ # More tests here!
+)
+
+foreach(test ${TINYXML_TESTS})
+ add_executable(${test} ${test})
+ target_link_libraries(${test}
+ tinyxml
+ )
+ add_test(${test} ${test})
+endforeach()
+
+configure_file(utf8test.xml utf8test.xml COPYONLY)
+configure_file(utf8testverify.xml utf8testverify.xml COPYONLY)
=======================================
--- /dev/null
+++ /trunk/tinyxml/test/utf8test.xml Sun Jun 27 19:25:07 2010
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document>
+ <English name="name" value="value">The world has many
languages</English>
+ <Russian name="название(имя)" value="ценность">Мир имеет много
языков</Russian>
+ <Spanish name="el nombre" value="el valor">el mundo tiene muchos
idiomas</Spanish>
+ <SimplifiedChinese name="名字" value="价值">世界有很多语言
</SimplifiedChinese>
+ <Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
+ <汉语 名字="name" 价值="value">世界有很多语言</汉语>
+ <Heavy>"M&#x0eB;t&#230;l!"</Heavy>
+ <ä>Umlaut Element</ä>
+</document>
=======================================
--- /dev/null
+++ /trunk/tinyxml/test/utf8testverify.xml Sun Jun 27 19:25:07 2010
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<document>
+ <English name="name" value="value">The world has many
languages</English>
+ <Russian name="название(имя)" value="ценность">Мир имеет много
языков</Russian>
+ <Spanish name="el nombre" value="el valor">el mundo tiene muchos
idiomas</Spanish>
+ <SimplifiedChinese name="名字" value="价值">世界有很多语言
</SimplifiedChinese>
+ <Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
+ <汉语 名字="name" 价值="value">世界有很多语言</汉语>
+ <Heavy>&quot;Mëtæl!&quot;</Heavy>
+ <ä>Umlaut Element</ä>
+</document>
=======================================
--- /dev/null
+++ /trunk/tinyxml/test/xmltest.cpp Sun Jun 27 19:25:07 2010
@@ -0,0 +1,1365 @@
+/*
+ Test program for TinyXML.
+*/
+
+#include <tinyxml/tinyxml.h>
+
+#include <cstdio>
+
+#ifdef TIXML_USE_STL
+ #include <iostream>
+ #include <sstream>
+ using namespace std;
+#else
+ #include <stdio.h>
+#endif
+
+#if defined( WIN32 ) && defined( TUNE )
+ #include <crtdbg.h>
+ _CrtMemState startMemState;
+ _CrtMemState endMemState;
+#endif
+
+bool XmlTest (const char* testString, const char* expected, const char*
found, bool noEcho = false);
+bool XmlTest( const char* testString, int expected, int found, bool noEcho
= false );
+
+static int gPass = 0;
+static int gFail = 0;
+
+
+
+bool XmlTest (const char* testString, const char* expected, const char*
found, bool noEcho )
+{
+ 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
)
+{
+ 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 =
+ "<?xml version=\"1.0\" standalone='no' >\n"
+ "<!-- Our to do list data -->"
+ "<ToDo>\n"
+ "<!-- Do I need a secure PDA? -->\n"
+ "<Item priority=\"1\" distance='close'> Go to the <bold>Toy
store!</bold></Item>"
+ "<Item priority=\"2\" distance='none'> Do bills </Item>"
+ "<Item priority=\"2\" distance='far &amp; back'> Look for Evil
Dinosaurs! </Item>"
+ "</ToDo>";
+
+ {
+
+ #ifdef TIXML_USE_STL
+ // What the todo list should look like after processing.
+ // In stream (no formatting) representation.
+ const char* demoEnd =
+ "<?xml version=\"1.0\" standalone=\"no\" ?>"
+ "<!-- Our to do list data -->"
+ "<ToDo>"
+ "<!-- Do I need a secure PDA? -->"
+ "<Item priority=\"2\" distance=\"close\">Go to the"
+ "<bold>Toy store!"
+ "</bold>"
+ "</Item>"
+ "<Item priority=\"1\" distance=\"far\">Talk to:"
+ "<Meeting where=\"School\">"
+ "<Attendee name=\"Marple\" position=\"teacher\" />"
+ "<Attendee name=\"Voel\" position=\"counselor\" />"
+ "</Meeting>"
+ "<Meeting where=\"Lunch\" />"
+ "</Item>"
+ "<Item priority=\"2\" distance=\"here\">Do bills"
+ "</Item>"
+ "</ToDo>";
+ #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( "<Element0 attribute0='foo0' attribute1= noquotes
attribute2 = '&gt;' />" );
+ 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 = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
+ "<passages count=\"006\" formatversion=\"20020620\">\n"
+ " <wrong error>\n"
+ "</passages>";
+
+ 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 = "<doc attr0='1' attr1='2.0' attr2='foo' />";
+
+ 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 = "<doc/>";
+
+ TiXmlDocument doc;
+ doc.Parse( str );
+
+ TiXmlElement* ele = doc.FirstChildElement();
+
+ int iVal;
+ double dVal;
+
+ ele->SetAttribute( "str", "strValue" );
+ ele->SetAttribute( "int", 1 );
+ ele->SetDoubleAttribute( "double", -1.0 );
+
+ const char* cStr = ele->Attribute( "str" );
+ ele->QueryIntAttribute( "int", &iVal );
+ ele->QueryDoubleAttribute( "double", &dVal );
+
+ XmlTest( "Attribute round trip. c-string.", "strValue", cStr );
+ XmlTest( "Attribute round trip. int.", 1, iVal );
+ XmlTest( "Attribute round trip. double.", -1, (int)dVal );
+ }
+
+ {
+ const char* str = "\t<?xml version=\"1.0\" standalone=\"no\" ?>\t<room
doors='2'>\n"
+ "</room>";
+
+ 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<?xml version=\"1.0\" standalone=\"no\" ?>\t<room
doors='2'>\n"
+ " <!-- Silly example -->\n"
+ " <door wall='north'>A great door!</door>\n"
+ "\t<door wall='east'/>"
+ "</room>";
+
+ 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[] = "<element>r\x82sum\x82</element>";
+
+ 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( "<element name='value' />", 0, TIXML_ENCODING_UNKNOWN );
+
+ TiXmlElement elementCopy( element );
+ TiXmlElement elementAssign( "foo" );
+ elementAssign.Parse( "<incorrect foo='bar'/>", 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( "<!--comment-->", 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( "<?xml version='1.0' encoding='UTF-8'?>", 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( "<start>This is \ntext</start>" );
+ 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 = "<foo>This is text</foo>";
+ TiXmlDocument doc;
+ doc.Parse( str );
+ const TiXmlElement* element = doc.RootElement();
+
+ XmlTest( "GetText() normal use.", "This is text", element->GetText() );
+
+ str = "<foo><b>This is text</b></foo>";
+ doc.Clear();
+ doc.Parse( str );
+ element = doc.RootElement();
+
+ XmlTest( "GetText() contained element.", element->GetText() == 0, true );
+
+ str = "<foo>This is <b>text</b></foo>";
+ 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 = "<xmlElement>"
+ "<![CDATA["
+ "I am > the rules!\n"
+ "...since I make symbolic puns"
+ "]]>"
+ "</xmlElement>";
+ 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( "<xmlElement><![CDATA[" );
+ str += buf;
+ str += "]]></xmlElement>";
+
+ 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 = "<xmlElement>"
+ "<![CDATA["
+ "<b>I am > the rules!</b>\n"
+ "...since I make symbolic puns"
+ "]]>"
+ "</xmlElement>";
+ TiXmlDocument doc;
+ doc.Parse( str );
+ doc.Print();
+
+ XmlTest( "CDATA parse. [ 1480107 ]",
doc.FirstChildElement()->FirstChild()->Value(),
+ "<b>I am > the rules!</b>\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(),
+ "<b>I am > the rules!</b>\n...since I make symbolic puns",
+ true );
+ #endif
+
+ TiXmlDocument doc1 = doc;
+ //doc.Print();
+
+ XmlTest( "CDATA copy. [ 1480107 ]",
doc1.FirstChildElement()->FirstChild()->Value(),
+ "<b>I am > the rules!</b>\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<FUZZ_ITERATION; ++i )
+ {
+ char* demoCopy = new char[ len+1 ];
+ strcpy( demoCopy, demoStart );
+
+ demoCopy[ i%len ] = (char)((i+1)*3);
+ demoCopy[ (i*7)%len ] = '>';
+ demoCopy[ (i*11)%len ] = '<';
+
+ TiXmlDocument xml;
+ xml.Parse( demoCopy );
+
+ delete [] demoCopy;
+ }
+ printf( "** Fuzzing Complete. **\n" );
+
+ //////////////////////////////////////////////////////
+ printf ("\n** Bug regression tests **\n");
+
+ // InsertBeforeChild and InsertAfterChild causes crash.
+ {
+ TiXmlElement parent( "Parent" );
+ TiXmlElement childText0( "childText0" );
+ TiXmlElement childText1( "childText1" );
+ TiXmlNode* childNode0 = parent.InsertEndChild( childText0 );
+ TiXmlNode* childNode1 = parent.InsertBeforeChild( childNode0, childText1
);
+
+ XmlTest( "Test InsertBeforeChild on empty node.", ( childNode1 ==
parent.FirstChild() ), true );
+ }
+
+ {
+ // InsertBeforeChild and InsertAfterChild causes crash.
+ TiXmlElement parent( "Parent" );
+ TiXmlElement childText0( "childText0" );
+ TiXmlElement childText1( "childText1" );
+ TiXmlNode* childNode0 = parent.InsertEndChild( childText0 );
+ TiXmlNode* childNode1 = parent.InsertAfterChild( childNode0, childText1
);
+
+ XmlTest( "Test InsertAfterChild on empty node. ", ( childNode1 ==
parent.LastChild() ), true );
+ }
+
+ // Reports of missing constructors, irregular string problems.
+ {
+ // Missing constructor implementation. No test -- just compiles.
+ TiXmlText text( "Missing" );
+
+ #ifdef TIXML_USE_STL
+ // Missing implementation:
+ TiXmlDocument doc;
+ string name = "missing";
+ doc.LoadFile( name );
+
+ TiXmlText textSTL( name );
+ #else
+ // verifying some basic string functions:
+ TiXmlString a;
+ TiXmlString b( "Hello" );
+ TiXmlString c( "ooga" );
+
+ c = " World!";
+ a = b;
+ a += c;
+ a = a;
+
+ XmlTest( "Basic TiXmlString test. ", "Hello World!", a.c_str() );
+ #endif
+ }
+
+ // Long filenames crashing STL version
+ {
+ TiXmlDocument
doc( "midsummerNightsDreamWithAVeryLongFilenameToConfuseTheStringHandlingRoutines.xml"
);
+ bool loadOkay = doc.LoadFile();
+ loadOkay = true; // get rid of compiler warning.
+ // Won't pass on non-dev systems. Just a "no crash" check.
+ //XmlTest( "Long filename. ", true, loadOkay );
+ }
+
+ {
+ // Entities not being written correctly.
+ // From Lynn Allen
+
+ const char* passages =
+ "<?xml version=\"1.0\" standalone=\"no\" ?>"
+ "<passages count=\"006\" formatversion=\"20020620\">"
+ "<psg context=\"Line 5 has &quot;quotation marks&quot; and
&apos;apostrophe marks&apos;."
+ " It also has &lt;, &gt;, and &amp;, as well as a fake copyright
&#xA9;.\"> </psg>"
+ "</passages>";
+
+ 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. ",
+ "<psg context=\'Line 5 has &quot;quotation marks&quot; and
&apos;apostrophe marks&apos;."
+ " It also has &lt;, &gt;, and &amp;, as well as a fake copyright
\xC2\xA9.' />",
+ buf,
+ true );
+ }
+ fclose( textfile );
+ }
+
+ {
+ FILE* textfile = fopen( "test5.xml", "w" );
+ if ( textfile )
+ {
+ fputs("<?xml version='1.0'?><a.elem xmi.version='2.0'/>",
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("<element><Name>1.1 Start easy ignore fin
thickness&#xA;</Name></element>", 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" );
+ }
+ }
***The diff for this file has been truncated for email.***
=======================================
--- /trunk/CMakeLists.txt Sat Jun 26 13:54:08 2010
+++ /trunk/CMakeLists.txt Sun Jun 27 19:25:07 2010
@@ -104,3 +104,6 @@

add_subdirectory(cockpit/src)
add_subdirectory(cockpit/test)
+
+add_subdirectory(tinyxml/src)
+add_subdirectory(tinyxml/test)
Reply all
Reply to author
Forward
0 new messages