Przeglądaj źródła

Merge branch 'master' of github.com:leethomason/tinyxml2

Lee Thomason 14 lat temu
rodzic
commit
975426752c
8 zmienionych plików z 413 dodań i 156 usunięć
  1. 48 0
      CMakeLists.txt
  2. 2 2
      dox
  3. 4 4
      readme.txt
  4. 25 21
      tinyxml2.cpp
  5. 167 111
      tinyxml2.h
  6. 29 12
      tinyxml2/tinyxml2.xcodeproj/project.pbxproj
  7. 44 6
      xmltest.cpp
  8. 94 0
      xmltest.h

+ 48 - 0
CMakeLists.txt

@@ -0,0 +1,48 @@
+cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
+cmake_policy(VERSION 2.6)
+
+project(tinyxml2)
+#enable_testing()
+
+#CMAKE_BUILD_TOOL
+
+################################
+# Add common source 
+
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/.")
+
+################################
+# Add custom target to copy all data
+
+set(TARGET_DATA_COPY DATA_COPY)
+if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
+	add_custom_target(
+		${TARGET_DATA_COPY}
+	 	COMMAND ${CMAKE_COMMAND} -E echo "In source build")
+else(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
+	add_custom_target(
+		${TARGET_DATA_COPY}
+		COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/dream.xml ${CMAKE_CURRENT_BINARY_DIR}
+		COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/utf8test.xml ${CMAKE_CURRENT_BINARY_DIR}
+		COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/utf8testverify.xml ${CMAKE_CURRENT_BINARY_DIR})
+endif(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
+
+set(OGL_DATA_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data)
+
+################################
+# Add definitions
+
+if(MSVC)
+	add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif(MSVC)
+
+################################
+# Add targets
+
+add_library(tinyxml2 STATIC tinyxml2.cpp tinyxml2.h)
+
+add_executable(test xmltest.cpp)
+add_dependencies(test tinyxml2)
+add_dependencies(test ${TARGET_DATA_COPY})
+target_link_libraries(test tinyxml2)
+#add_test(test ${SAMPLE_NAME} COMMAND $<TARGET_FILE:${SAMPLE_NAME}>)

+ 2 - 2
dox

@@ -32,7 +32,7 @@ PROJECT_NAME           = "TinyXML-2"
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER = 0.9.3
+PROJECT_NUMBER = 0.9.4
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer
@@ -661,7 +661,7 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = tinyxml2.h readme.txt
+INPUT                  = tinyxml2.h xmltest.h readme.txt
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is

+ 4 - 4
readme.txt

@@ -11,8 +11,7 @@ github.com/leethomason/tinyxml2
 The online HTML version of these docs:
 http://grinninglizard.com/tinyxml2docs/index.html
 
-Where examples are in the "related pages" tab:
-http://grinninglizard.com/tinyxml2docs/pages.html
+Examples are in the "related pages" tab of the HTML docs.
 
 <h2> What it does. </h2>
 	
@@ -243,8 +242,9 @@ And additionally a test file:
 	<li>xmltest.cpp</li>
 </ol>
 
-Simply compile and run. There is a visual studio 2010 project included.
-
+Simply compile and run. There is a visual studio 2010 project included, a simple Makefile, 
+an XCode project, and a cmake CMakeLists.txt included to help you. The top of tinyxml.h
+even has a simple g++ command line if you are are *nix and don't want to use a build system.
 
 <h2> Documentation </h2>
 

+ 25 - 21
tinyxml2.cpp

@@ -24,7 +24,6 @@ distribution.
 #include "tinyxml2.h"
 
 #if 1
-	#include <cstdarg>
 	#include <cstdio>
 	#include <cstdlib>
 	#include <new>
@@ -998,7 +997,7 @@ void XMLAttribute::SetAttribute( const char* v )
 void XMLAttribute::SetAttribute( int v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );	
 	value.SetStr( buf );
 }
 
@@ -1006,7 +1005,7 @@ void XMLAttribute::SetAttribute( int v )
 void XMLAttribute::SetAttribute( unsigned v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );	
 	value.SetStr( buf );
 }
 
@@ -1014,21 +1013,21 @@ void XMLAttribute::SetAttribute( unsigned v )
 void XMLAttribute::SetAttribute( bool v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );	
 	value.SetStr( buf );
 }
 
 void XMLAttribute::SetAttribute( double v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	
 	value.SetStr( buf );
 }
 
 void XMLAttribute::SetAttribute( float v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	
 	value.SetStr( buf );
 }
 
@@ -1408,7 +1407,7 @@ int XMLDocument::LoadFile( FILE* fp )
 }
 
 
-void XMLDocument::SaveFile( const char* filename )
+int XMLDocument::SaveFile( const char* filename )
 {
 #if defined(_MSC_VER)
 #pragma warning ( push )
@@ -1418,14 +1417,21 @@ void XMLDocument::SaveFile( const char* filename )
 #if defined(_MSC_VER)
 #pragma warning ( pop )
 #endif
-	if ( fp ) {
-		XMLPrinter stream( fp );
-		Print( &stream );
-		fclose( fp );
-	}
-	else {
+	if ( !fp ) {
 		SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
+		return errorID;
 	}
+	SaveFile(fp);
+	fclose( fp );
+	return errorID;
+}
+
+
+int XMLDocument::SaveFile( FILE* fp )
+{
+	XMLPrinter stream( fp );
+	Print( &stream );
+	return errorID;
 }
 
 
@@ -1481,11 +1487,9 @@ void XMLDocument::PrintError() const
 		
 		if ( errorStr1 ) {
 			TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
-			buf1[LEN-1] = 0;
 		}
 		if ( errorStr2 ) {
 			TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
-			buf2[LEN-1] = 0;
 		}
 
 		printf( "XMLDocument error id=%d str1=%s str2=%s\n",
@@ -1534,10 +1538,10 @@ void XMLPrinter::Print( const char* format, ... )
 			int len = -1;
 			int expand = 1000;
 			while ( len < 0 ) {
-				len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), accumulator.Capacity()-1, format, va );
+				len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
 				if ( len < 0 ) {
-					accumulator.PushArr( expand );
 					expand *= 3/2;
+					accumulator.PushArr( expand );
 				}
 			}
 			char* p = buffer.PushArr( len ) - 1;
@@ -1644,7 +1648,7 @@ void XMLPrinter::PushAttribute( const char* name, const char* value )
 void XMLPrinter::PushAttribute( const char* name, int v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );	
 	PushAttribute( name, buf );
 }
 
@@ -1652,7 +1656,7 @@ void XMLPrinter::PushAttribute( const char* name, int v )
 void XMLPrinter::PushAttribute( const char* name, unsigned v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );	
 	PushAttribute( name, buf );
 }
 
@@ -1660,7 +1664,7 @@ void XMLPrinter::PushAttribute( const char* name, unsigned v )
 void XMLPrinter::PushAttribute( const char* name, bool v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );	
 	PushAttribute( name, buf );
 }
 
@@ -1668,7 +1672,7 @@ void XMLPrinter::PushAttribute( const char* name, bool v )
 void XMLPrinter::PushAttribute( const char* name, double v )
 {
 	char buf[BUF_SIZE];
-	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );	
+	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	
 	PushAttribute( name, buf );
 }
 

+ 167 - 111
tinyxml2.h

@@ -29,6 +29,7 @@ distribution.
 	#include <climits>
 	#include <cstdio>
 	#include <cstring>
+	#include <cstdarg>
 #else
 	// Not completely sure all the interesting systems
 	// can handle the new headers; can switch this if
@@ -70,33 +71,33 @@ distribution.
 #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
-
 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
 	// Microsoft visual studio, version 2005 and higher.
-	#define TIXML_SNPRINTF _snprintf_s
+	/*int _snprintf_s(
+	   char *buffer,
+	   size_t sizeOfBuffer,
+	   size_t count,	
+	   const char *format [,
+		  argument] ... 
+	);*/
+	inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) {
+	    va_list va;
+		va_start( va, format );
+		int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
+	    va_end( va );
+		return result;
+	}
 	#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 )
+#else
 	// GCC version 3 and higher
 	//#warning( "Using sn* functions." )
 	#define TIXML_SNPRINTF snprintf
 	#define TIXML_SSCANF   sscanf
-#else
-	#define TIXML_SNPRINTF snprintf
-	#define TIXML_SSCANF   sscanf
 #endif
 
 static const int TIXML2_MAJOR_VERSION = 0;
 static const int TIXML2_MINOR_VERSION = 9;
-static const int TIXML2_PATCH_VERSION = 3;
+static const int TIXML2_PATCH_VERSION = 4;
 
 namespace tinyxml2
 {
@@ -1007,24 +1008,38 @@ public:
 		an errorID.
 	*/
 	int Parse( const char* xml );
+	
 	/**
 		Load an XML file from disk.
 		Returns XML_NO_ERROR (0) on success, or
 		an errorID.
-	*/
+	*/	
 	int LoadFile( const char* filename );
+	
 	/**
 		Load an XML file from disk. You are responsible
 		for providing and closing the FILE*.
 
 		Returns XML_NO_ERROR (0) on success, or
 		an errorID.
-	*/
+	*/	
 	int LoadFile( FILE* );
+	
 	/**
 		Save the XML file to disk.
+		Returns XML_NO_ERROR (0) on success, or
+		an errorID.
 	*/
-	void SaveFile( const char* filename );
+	int SaveFile( const char* filename );
+
+	/**
+		Save the XML file to disk.  You are responsible
+		for providing and closing the FILE*.
+
+		Returns XML_NO_ERROR (0) on success, or
+		an errorID.
+	*/
+	int SaveFile( FILE* );
 
 	bool ProcessEntities() const						{ return processEntities; }
 
@@ -1131,6 +1146,139 @@ private:
 };
 
 
+/**
+	A XMLHandle is a class that wraps a node pointer with null checks; this is
+	an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
+	DOM structure. It is a separate utility class.
+
+	Take an example:
+	@verbatim
+	<Document>
+		<Element attributeA = "valueA">
+			<Child attributeB = "value1" />
+			<Child attributeB = "value2" />
+		</Element>
+	<Document>
+	@endverbatim
+
+	Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very 
+	easy to write a *lot* of code that looks like:
+
+	@verbatim
+	XMLElement* root = document.FirstChildElement( "Document" );
+	if ( root )
+	{
+		XMLElement* element = root->FirstChildElement( "Element" );
+		if ( element )
+		{
+			XMLElement* child = element->FirstChildElement( "Child" );
+			if ( child )
+			{
+				XMLElement* child2 = child->NextSiblingElement( "Child" );
+				if ( child2 )
+				{
+					// Finally do something useful.
+	@endverbatim
+
+	And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
+	of such code. A XMLHandle checks for null pointers so it is perfectly safe 
+	and correct to use:
+
+	@verbatim
+	XMLHandle docHandle( &document );
+	XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
+	if ( child2 )
+	{
+		// do something useful
+	@endverbatim
+
+	Which is MUCH more concise and useful.
+
+	It is also safe to copy handles - internally they are nothing more than node pointers.
+	@verbatim
+	XMLHandle handleCopy = handle;
+	@endverbatim
+
+	See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
+*/
+class XMLHandle
+{
+public:
+	/// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+	XMLHandle( XMLNode* _node )												{ node = _node; }
+	/// Create a handle from a node.
+	XMLHandle( XMLNode& _node )												{ node = &_node; }
+	/// Copy constructor
+	XMLHandle( const XMLHandle& ref )										{ node = ref.node; }
+	/// Assignment
+	XMLHandle operator=( const XMLHandle& ref )								{ node = ref.node; return *this; }
+
+	/// Get the first child of this handle.
+	XMLHandle FirstChild() 													{ return XMLHandle( node ? node->FirstChild() : 0 ); }
+	/// Get the first child element of this handle.
+	XMLHandle FirstChildElement( const char* value=0 )						{ return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); }
+	/// Get the last child of this handle.
+	XMLHandle LastChild()													{ return XMLHandle( node ? node->LastChild() : 0 ); }
+	/// Get the last child element of this handle.
+	XMLHandle LastChildElement( const char* _value=0 )						{ return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); }
+	/// Get the previous sibling of this handle.
+	XMLHandle PreviousSibling()												{ return XMLHandle( node ? node->PreviousSibling() : 0 ); }
+	/// Get the previous sibling element of this handle.
+	XMLHandle PreviousSiblingElement( const char* _value=0 )				{ return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
+	/// Get the next sibling of this handle.
+	XMLHandle NextSibling()													{ return XMLHandle( node ? node->NextSibling() : 0 ); }		
+	/// Get the next sibling element of this handle.
+	XMLHandle NextSiblingElement( const char* _value=0 )					{ return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
+
+	/// Safe cast to XMLNode. This can return null.
+	XMLNode* ToNode()							{ return node; } 
+	/// Safe cast to XMLElement. This can return null.
+	XMLElement* ToElement() 					{ return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+	/// Safe cast to XMLText. This can return null.
+	XMLText* ToText() 							{ return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+	/// Safe cast to XMLUnknown. This can return null.
+	XMLUnknown* ToUnknown() 					{ return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+	/// Safe cast to XMLDeclaration. This can return null.
+	XMLDeclaration* ToDeclaration() 			{ return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
+
+private:
+	XMLNode* node;
+};
+
+
+/**
+	A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
+	same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
+*/
+class XMLConstHandle
+{
+public:
+	XMLConstHandle( const XMLNode* _node )											{ node = _node; }
+	XMLConstHandle( const XMLNode& _node )											{ node = &_node; }
+	XMLConstHandle( const XMLConstHandle& ref )										{ node = ref.node; }
+
+	XMLConstHandle operator=( const XMLConstHandle& ref )							{ node = ref.node; return *this; }
+
+	const XMLConstHandle FirstChild() const											{ return XMLConstHandle( node ? node->FirstChild() : 0 ); }
+	const XMLConstHandle FirstChildElement( const char* value=0 ) const				{ return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); }
+	const XMLConstHandle LastChild()	const										{ return XMLConstHandle( node ? node->LastChild() : 0 ); }
+	const XMLConstHandle LastChildElement( const char* _value=0 ) const				{ return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); }
+	const XMLConstHandle PreviousSibling() const									{ return XMLConstHandle( node ? node->PreviousSibling() : 0 ); }
+	const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const		{ return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
+	const XMLConstHandle NextSibling() const										{ return XMLConstHandle( node ? node->NextSibling() : 0 ); }
+	const XMLConstHandle NextSiblingElement( const char* _value=0 ) const			{ return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
+
+
+	const XMLNode* ToNode() const				{ return node; } 
+	const XMLElement* ToElement() const			{ return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+	const XMLText* ToText() const				{ return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+	const XMLUnknown* ToUnknown() const			{ return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+	const XMLDeclaration* ToDeclaration() const	{ return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
+
+private:
+	const XMLNode* node;
+};
+
 
 /**
 	Printing functionality. The XMLPrinter gives you more
@@ -1252,96 +1400,4 @@ private:
 }	// tinyxml2
 
 
-// What follows is the docs for the examples.
-// I'd like the docs to be just before the
-// actual examples in xmltest.cpp, but I 
-// can't seem to get doxygen to do that. It
-// would be a wonderful patch if anyone figures
-// it out.
-
-/** @page Example-1 Load an XML File
- *  @dontinclude ./xmltest.cpp
- *  Basic XML file loading.
- *  The basic syntax to load an XML file from
- *	disk and check for an error. (ErrorID()
- *	will return 0 for no error.)
- *	@skip example_1()
- *  @until }
- */
-
-
-/** @page Example-2 Parse an XML from char buffer
- *  @dontinclude ./xmltest.cpp
- *  Basic XML string parsing.
- *  The basic syntax to parse an XML for
- *  a char* and check for an error. (ErrorID()
- *	will return 0 for no error.)
- *	@skip example_2()
- *  @until }
- */
-
-/** @page Example-3 Get information out of XML
-	@dontinclude ./xmltest.cpp
-	In this example, we navigate a simple XML
-	file, and read some interesting text. Note
-	that this is examlpe doesn't use error
-	checking; working code should check for null
-	pointers when walking an XML tree, or use
-	XMLHandle.
-	
-	(The XML is an excerpt from "dream.xml"). 
-
-	@skip example_3
-	@until </PLAY>";
-
-	The structure of the XML file is:
-
-	<ul>
-		<li>(declaration)</li>
-		<li>(dtd stuff)</li>
-		<li>Element "PLAY"</li>
-		<ul>
-			<li>Element "TITLE"</li>
-			<ul>
-			    <li>Text "A Midsummer Night's Dream"</li>
-			</ul>
-		</ul>
-	</ul>
-
-	For this example, we want to print out the 
-	title of the play. The text of the title (what
-	we want) is child of the "TITLE" element which
-	is a child of the "PLAY" element.
-
-	We want to skip the declaration and dtd, so the
-	method FirstChildElement() is a good choice. The
-	FirstChildElement() of the Document is the "PLAY"
-	Element, the FirstChildElement() of the "PLAY" Element
-	is the "TITLE" Element.
-
-	@until ( "TITLE" );
-
-	We can then use the convenience function GetText()
-	to get the title of the play.
-
-	@until title );
-
-	Text is just another Node in the XML DOM. And in
-	fact you should be a little cautious with it, as
-	text nodes can contain elements. 
-	
-	@verbatim
-	Consider: A Midsummer Night's <b>Dream</b>
-	@endverbatim
-
-	It is more correct to actually query the Text Node
-	if in doubt:
-
-	@until title );
-
-	Noting that here we use FirstChild() since we are
-	looking for XMLText, not an element, and ToText()
-	is a cast from a Node to a XMLText. 
-*/
-
 #endif // TINYXML2_INCLUDED

+ 29 - 12
tinyxml2/tinyxml2.xcodeproj/project.pbxproj

@@ -7,11 +7,11 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		037AE8A4151E692700E0F29F /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 037AE8A1151E692700E0F29F /* tinyxml2.cpp */; };
 		037AE8A5151E692700E0F29F /* xmltest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 037AE8A3151E692700E0F29F /* xmltest.cpp */; };
 		037AE9BE151E694400E0F29F /* dream.xml in CopyFiles */ = {isa = PBXBuildFile; fileRef = 037AE062151CCC6D00E0F29F /* dream.xml */; };
 		037AE9BF151E694400E0F29F /* utf8test.xml in CopyFiles */ = {isa = PBXBuildFile; fileRef = 037AE065151CCC6D00E0F29F /* utf8test.xml */; };
 		037AE9C0151E694400E0F29F /* utf8testverify.xml in CopyFiles */ = {isa = PBXBuildFile; fileRef = 037AE066151CCC6D00E0F29F /* utf8testverify.xml */; };
+		03F28B53152E9B1B00D4CD90 /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F28B4A152E9B1B00D4CD90 /* tinyxml2.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -34,9 +34,9 @@
 		037AE065151CCC6D00E0F29F /* utf8test.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = utf8test.xml; sourceTree = "<group>"; };
 		037AE066151CCC6D00E0F29F /* utf8testverify.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = utf8testverify.xml; sourceTree = "<group>"; };
 		037AE86D151E685F00E0F29F /* tinyxml2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tinyxml2; sourceTree = BUILT_PRODUCTS_DIR; };
-		037AE8A1151E692700E0F29F /* tinyxml2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tinyxml2.cpp; path = ../tinyxml2.cpp; sourceTree = "<group>"; };
-		037AE8A2151E692700E0F29F /* tinyxml2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tinyxml2.h; path = ../tinyxml2.h; sourceTree = "<group>"; };
 		037AE8A3151E692700E0F29F /* xmltest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = xmltest.cpp; path = ../xmltest.cpp; sourceTree = SOURCE_ROOT; };
+		03F28B4A152E9B1B00D4CD90 /* tinyxml2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxml2.cpp; sourceTree = "<group>"; };
+		03F28B4B152E9B1B00D4CD90 /* tinyxml2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyxml2.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -53,30 +53,29 @@
 		037AE056151CCC5200E0F29F = {
 			isa = PBXGroup;
 			children = (
-				037AE06A151CCC7C00E0F29F /* resources */,
-				037AE069151CCC7000E0F29F /* src */,
+				037AE069151CCC7000E0F29F /* Classes */,
+				037AE06A151CCC7C00E0F29F /* Resources */,
+				03F28B60152E9B4C00D4CD90 /* Libraries */,
 				037AE06F151CCCB900E0F29F /* Products */,
 			);
 			sourceTree = "<group>";
 		};
-		037AE069151CCC7000E0F29F /* src */ = {
+		037AE069151CCC7000E0F29F /* Classes */ = {
 			isa = PBXGroup;
 			children = (
-				037AE8A1151E692700E0F29F /* tinyxml2.cpp */,
-				037AE8A2151E692700E0F29F /* tinyxml2.h */,
 				037AE8A3151E692700E0F29F /* xmltest.cpp */,
 			);
-			name = src;
+			name = Classes;
 			sourceTree = "<group>";
 		};
-		037AE06A151CCC7C00E0F29F /* resources */ = {
+		037AE06A151CCC7C00E0F29F /* Resources */ = {
 			isa = PBXGroup;
 			children = (
 				037AE062151CCC6D00E0F29F /* dream.xml */,
 				037AE065151CCC6D00E0F29F /* utf8test.xml */,
 				037AE066151CCC6D00E0F29F /* utf8testverify.xml */,
 			);
-			name = resources;
+			name = Resources;
 			path = ..;
 			sourceTree = "<group>";
 		};
@@ -88,6 +87,24 @@
 			name = Products;
 			sourceTree = "<group>";
 		};
+		03F28AD7152E9B1B00D4CD90 /* tinyxml2 */ = {
+			isa = PBXGroup;
+			children = (
+				03F28B4A152E9B1B00D4CD90 /* tinyxml2.cpp */,
+				03F28B4B152E9B1B00D4CD90 /* tinyxml2.h */,
+			);
+			name = tinyxml2;
+			path = ..;
+			sourceTree = SOURCE_ROOT;
+		};
+		03F28B60152E9B4C00D4CD90 /* Libraries */ = {
+			isa = PBXGroup;
+			children = (
+				03F28AD7152E9B1B00D4CD90 /* tinyxml2 */,
+			);
+			name = Libraries;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -138,8 +155,8 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				037AE8A4151E692700E0F29F /* tinyxml2.cpp in Sources */,
 				037AE8A5151E692700E0F29F /* xmltest.cpp in Sources */,
+				03F28B53152E9B1B00D4CD90 /* tinyxml2.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 44 - 6
xmltest.cpp

@@ -94,12 +94,12 @@ int example_2()
 
 int example_3()
 {
-	static const char* xml = 
-		"<?xml version=\"1.0\"?>"
-		"<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
-		"<PLAY>"
-		"<TITLE>A Midsummer Night's Dream</TITLE>"
-		"</PLAY>";
+	static const char* xml = 
+		"<?xml version=\"1.0\"?>"
+		"<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
+		"<PLAY>"
+		"<TITLE>A Midsummer Night's Dream</TITLE>"
+		"</PLAY>";
 
 	XMLDocument doc;
 	doc.Parse( xml );
@@ -751,6 +751,44 @@ int main( int /*argc*/, const char ** /*argv*/ )
 		XMLTest( "Clone and Equal", 4, count );
 	}
 
+	{
+		// This shouldn't crash.
+		XMLDocument doc;
+		if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
+		{
+			doc.PrintError();
+		}
+		XMLTest( "Error in snprinf handling.", true, doc.Error() );
+	}
+
+	// -------- Handles ------------
+	{
+		static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
+		XMLDocument doc;
+		doc.Parse( xml );
+
+		XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
+		XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
+
+		XMLHandle docH( doc );
+		ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
+		XMLTest( "Handle, dne, mutable", false, ele != 0 );
+	}
+	
+	{
+		static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
+		XMLDocument doc;
+		doc.Parse( xml );
+		XMLConstHandle docH( doc );
+
+		const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
+		XMLTest( "Handle, success, const", ele->Value(), "sub" );
+
+		ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
+		XMLTest( "Handle, dne, const", false, ele != 0 );
+	}
+
+	
 	// ----------- Performance tracking --------------
 	{
 #if defined( _MSC_VER )

+ 94 - 0
xmltest.h

@@ -0,0 +1,94 @@
+// Purely doxygen documentation
+
+
+// What follows is the docs for the examples.
+// I'd like the docs to be just before the
+// actual examples in xmltest.cpp, but I 
+// can't seem to get doxygen to do that. It
+// would be a wonderful patch if anyone figures
+// it out.
+
+/** @page Example-1 Load an XML File
+ *  @dontinclude ./xmltest.cpp
+ *  Basic XML file loading.
+ *  The basic syntax to load an XML file from
+ *	disk and check for an error. (ErrorID()
+ *	will return 0 for no error.)
+ *	@skip example_1()
+ *  @until }
+ */
+
+
+/** @page Example-2 Parse an XML from char buffer
+ *  @dontinclude ./xmltest.cpp
+ *  Basic XML string parsing.
+ *  The basic syntax to parse an XML for
+ *  a char* and check for an error. (ErrorID()
+ *	will return 0 for no error.)
+ *	@skip example_2()
+ *  @until }
+ */
+
+/** @page Example-3 Get information out of XML
+	@dontinclude ./xmltest.cpp
+	In this example, we navigate a simple XML
+	file, and read some interesting text. Note
+	that this is examlpe doesn't use error
+	checking; working code should check for null
+	pointers when walking an XML tree, or use
+	XMLHandle.
+	
+	(The XML is an excerpt from "dream.xml"). 
+
+	@skip example_3
+	@until </PLAY>";
+
+	The structure of the XML file is:
+
+	<ul>
+		<li>(declaration)</li>
+		<li>(dtd stuff)</li>
+		<li>Element "PLAY"</li>
+		<ul>
+			<li>Element "TITLE"</li>
+			<ul>
+			    <li>Text "A Midsummer Night's Dream"</li>
+			</ul>
+		</ul>
+	</ul>
+
+	For this example, we want to print out the 
+	title of the play. The text of the title (what
+	we want) is child of the "TITLE" element which
+	is a child of the "PLAY" element.
+
+	We want to skip the declaration and dtd, so the
+	method FirstChildElement() is a good choice. The
+	FirstChildElement() of the Document is the "PLAY"
+	Element, the FirstChildElement() of the "PLAY" Element
+	is the "TITLE" Element.
+
+	@until ( "TITLE" );
+
+	We can then use the convenience function GetText()
+	to get the title of the play.
+
+	@until title );
+
+	Text is just another Node in the XML DOM. And in
+	fact you should be a little cautious with it, as
+	text nodes can contain elements. 
+	
+	@verbatim
+	Consider: A Midsummer Night's <b>Dream</b>
+	@endverbatim
+
+	It is more correct to actually query the Text Node
+	if in doubt:
+
+	@until title );
+
+	Noting that here we use FirstChild() since we are
+	looking for XMLText, not an element, and ToText()
+	is a cast from a Node to a XMLText. 
+*/