Imported Upstream version 5.0.0 upstream/5.0.0
authorJinWang An <jinwang.an@samsung.com>
Fri, 30 Oct 2020 05:29:58 +0000 (14:29 +0900)
committerJinWang An <jinwang.an@samsung.com>
Fri, 30 Oct 2020 05:29:58 +0000 (14:29 +0900)
.gitignore
CMakeLists.txt
appveyor.yml
dox
readme.md
tinyxml2.cpp
tinyxml2.h
tinyxml2/test.vcxproj
tinyxml2/tinyxml2.vcxproj
xmltest.cpp

index f5b7e9960c3caaef10383dff5b9419d81067a83a..ca322427f571f994008dc4515e789a5090b8b4b1 100644 (file)
@@ -5,6 +5,8 @@ ipch/
 resources/out/
 tinyxml2/tinyxml2-cbp/bin/
 tinyxml2/tinyxml2-cbp/obj/
+tinyxml2/bin/
+tinyxml2/temp/
 *.sdf
 *.suo
 *.opensdf
@@ -12,3 +14,5 @@ tinyxml2/tinyxml2-cbp/obj/
 *.depend
 *.layout
 *.o
+*.vc.db
+*.vc.opendb
\ No newline at end of file
index e1d3ca00161cedb4bdb341d76c11ceb5df228ab9..bb6a7cef9c9a004637f8a920341eb76b722e35be 100644 (file)
@@ -7,6 +7,9 @@ IF(BIICODE)
 ENDIF(BIICODE)\r
 cmake_minimum_required(VERSION 2.6 FATAL_ERROR)\r
 cmake_policy(VERSION 2.6)\r
+if(POLICY CMP0063)\r
+       cmake_policy(SET CMP0063 OLD)\r
+endif()\r
 \r
 project(tinyxml2)\r
 include(GNUInstallDirs)\r
@@ -17,52 +20,32 @@ include(GNUInstallDirs)
 ################################\r
 # set lib version here\r
 \r
-set(GENERIC_LIB_VERSION "4.0.1")\r
-set(GENERIC_LIB_SOVERSION "4")\r
-\r
-\r
-################################\r
-# Add common source\r
-\r
-include_directories("${CMAKE_CURRENT_SOURCE_DIR}/.")\r
-\r
-################################\r
-# Add custom target to copy all data\r
-\r
-set(TARGET_DATA_COPY DATA_COPY)\r
-set(DATA_COPY_FILES)\r
-if(NOT ${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})\r
-       foreach(data dream.xml empty.xml utf8test.xml utf8testverify.xml)\r
-               set(DATA_COPY_SRC  ${CMAKE_CURRENT_SOURCE_DIR}/resources/${data})\r
-               set(DATA_COPY_DEST ${CMAKE_CURRENT_BINARY_DIR}/resources/${data})\r
-               add_custom_command(\r
-                       OUTPUT ${DATA_COPY_DEST}\r
-                       COMMAND ${CMAKE_COMMAND}\r
-                       ARGS -E copy ${DATA_COPY_SRC} ${DATA_COPY_DEST}\r
-                       DEPENDS ${DATA_COPY_SRC})\r
-               list(APPEND DATA_COPY_FILES ${DATA_COPY_DEST})\r
-       endforeach(data)\r
-endif(NOT ${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})\r
-add_custom_target(${TARGET_DATA_COPY} DEPENDS ${DATA_COPY_FILES})\r
+set(GENERIC_LIB_VERSION "5.0.0")\r
+set(GENERIC_LIB_SOVERSION "5")\r
 \r
 ################################\r
 # Add definitions\r
 \r
-if(MSVC)\r
-       add_definitions(-D_CRT_SECURE_NO_WARNINGS)\r
-endif(MSVC)\r
-\r
 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")\r
 \r
 ################################\r
 # Add targets\r
 # By Default shared libray is being built\r
 # To build static libs also - Do cmake . -DBUILD_STATIC_LIBS:BOOL=ON\r
-# User can choose not to build shared library by using cmake -BUILD_SHARED_LIBS:BOOL:OFF\r
+# User can choose not to build shared library by using cmake -DBUILD_SHARED_LIBS:BOOL=OFF\r
 # To build only static libs use cmake . -DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_STATIC_LIBS:BOOL=ON\r
+# To build the tests, use cmake . -DBUILD_TESTS:BOOL=ON\r
+# To disable the building of the tests, use cmake . -DBUILD_TESTS:BOOL=OFF\r
 \r
 option(BUILD_SHARED_LIBS "build as shared library" ON)\r
 option(BUILD_STATIC_LIBS "build as static library" OFF)\r
+option(BUILD_TESTS "build xmltest" ON)\r
+\r
+set(CMAKE_CXX_VISIBILITY_PRESET hidden)\r
+set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)\r
+\r
+# to distinguish between debug and release lib\r
+set(CMAKE_DEBUG_POSTFIX "d")\r
 \r
 if(BUILD_SHARED_LIBS)\r
 add_library(tinyxml2 SHARED tinyxml2.cpp tinyxml2.h)\r
@@ -72,11 +55,29 @@ set_target_properties(tinyxml2 PROPERTIES
        VERSION "${GENERIC_LIB_VERSION}"\r
        SOVERSION "${GENERIC_LIB_SOVERSION}")\r
 \r
+\r
 if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")\r
-    target_include_directories(tinyxml2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/.")\r
+    target_include_directories(tinyxml2 PUBLIC \r
+                          $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>\r
+                          $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)\r
+\r
+    if(MSVC)\r
+      target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS)\r
+    endif(MSVC)\r
+else()\r
+    include_directories(${PROJECT_SOURCE_DIR})\r
+\r
+    if(MSVC)\r
+      add_definitions(-D_CRT_SECURE_NO_WARNINGS)\r
+    endif(MSVC)\r
 endif()\r
 \r
+# export targets for find_package config mode\r
+export(TARGETS tinyxml2\r
+      FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\r
+\r
 install(TARGETS tinyxml2\r
+        EXPORT ${CMAKE_PROJECT_NAME}Targets\r
         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\r
         LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\r
         ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})\r
@@ -90,27 +91,52 @@ set_target_properties(tinyxml2_static PROPERTIES
         SOVERSION "${GENERIC_LIB_SOVERSION}")\r
 set_target_properties( tinyxml2_static PROPERTIES OUTPUT_NAME tinyxml2 )\r
 \r
+target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS)\r
+\r
 if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")\r
-    target_include_directories(tinyxml2_static INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/.")\r
+    target_include_directories(tinyxml2_static PUBLIC \r
+                          $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>\r
+                          $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)\r
+\r
+    if(MSVC)\r
+      target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS)\r
+    endif(MSVC)\r
+else()\r
+    include_directories(${PROJECT_SOURCE_DIR})\r
+\r
+    if(MSVC)\r
+      add_definitions(-D_CRT_SECURE_NO_WARNINGS)\r
+    endif(MSVC)\r
 endif()\r
 \r
+# export targets for find_package config mode\r
+export(TARGETS tinyxml2_static\r
+      FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\r
+\r
 install(TARGETS tinyxml2_static\r
+        EXPORT ${CMAKE_PROJECT_NAME}Targets\r
         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\r
         LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\r
         ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})\r
 endif()\r
 \r
-add_executable(xmltest xmltest.cpp)\r
-if(BUILD_SHARED_LIBS)\r
-   add_dependencies(xmltest tinyxml2)\r
-   add_dependencies(xmltest ${TARGET_DATA_COPY})\r
-   target_link_libraries(xmltest tinyxml2)\r
-else(BUILD_STATIC_LIBS)\r
-   add_dependencies(xmltest tinyxml2_static)\r
-   add_dependencies(xmltest ${TARGET_DATA_COPY})\r
-   target_link_libraries(xmltest tinyxml2_static)\r
+if(BUILD_TESTS)\r
+  add_executable(xmltest xmltest.cpp)\r
+  if(BUILD_SHARED_LIBS)\r
+    add_dependencies(xmltest tinyxml2)\r
+    target_link_libraries(xmltest tinyxml2)\r
+  else(BUILD_STATIC_LIBS)\r
+    add_dependencies(xmltest tinyxml2_static)\r
+    target_link_libraries(xmltest tinyxml2_static)\r
+  endif()\r
+\r
+  # Copy test resources and create test output directory\r
+  add_custom_command(TARGET xmltest POST_BUILD\r
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources $<TARGET_FILE_DIR:xmltest>/resources\r
+    COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:xmltest>/resources/out\r
+    COMMENT "Configuring xmltest resources directory: ${CMAKE_BINARY_DIR}/resources"\r
+  )\r
 endif()\r
-install(TARGETS DESTINATION ${CMAKE_INSTALL_BINDIR})\r
 \r
 install(FILES tinyxml2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\r
 \r
@@ -124,8 +150,6 @@ endforeach()
 configure_file(tinyxml2.pc.in tinyxml2.pc @ONLY)\r
 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)\r
 \r
-#add_test(xmltest ${SAMPLE_NAME} COMMAND $<TARGET_FILE:${SAMPLE_NAME}>)\r
-\r
 # uninstall target\r
 configure_file(\r
     "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"\r
@@ -134,3 +158,14 @@ configure_file(
 \r
 add_custom_target(uninstall\r
     COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)\r
+\r
+file(WRITE\r
+    ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake\r
+    "include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n")\r
+\r
+install(FILES\r
+        ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake\r
+        DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})\r
+\r
+install(EXPORT ${CMAKE_PROJECT_NAME}Targets\r
+        DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
\ No newline at end of file
index aac8867562459f2668752e356f7058b7560c9e57..0c60b672eca19b03ac03e8bca96924c215107aba 100644 (file)
@@ -3,5 +3,5 @@ before_build:
 
 build_script:
   - msbuild tinyxml2.sln /m /p:Configuration=Release /t:ALL_BUILD
-  - copy Release\xmltest.exe .\ && copy Release\tinyxml2.dll .\
+  - cd Release
   - xmltest.exe
diff --git a/dox b/dox
index 394b1821d670f0b5de5d7ab68f4fb8b8d55d145f..9e271360f90a0423709448cd43f7b9bef3bef0f4 100644 (file)
--- a/dox
+++ b/dox
@@ -38,7 +38,7 @@ PROJECT_NAME           = "TinyXML-2"
 # could be handy for archiving the generated documentation or if some version\r
 # control system is used.\r
 \r
-PROJECT_NUMBER = 4.0.1\r
+PROJECT_NUMBER = 5.0.0\r
 \r
 # Using the PROJECT_BRIEF tag one can provide an optional one line description\r
 # for a project that appears at the top of each page and should give viewer a\r
index 82c6ce927580da2896e73e61ef867b6ec7de17e6..54f752a9bb61ea3d23dd3b86cf852f07ad6bf6ae 100644 (file)
--- a/readme.md
+++ b/readme.md
@@ -88,9 +88,8 @@ Advantages of TinyXML-2
 
 Advantages of TinyXML-1
 
-1.  Can report the location of parsing errors.
-2.  Support for some C++ STL conventions: streams and strings
-3.  Very mature and well debugged code base.
+1.  Support for some C++ STL conventions: streams and strings
+2.  Very mature and well debugged code base.
 
 Features
 --------
@@ -111,7 +110,7 @@ by the Document. When the Document is deleted, so are all the nodes it contains.
 
 Microsoft has an excellent article on white space: http://msdn.microsoft.com/en-us/library/ms256097.aspx
 
-By default, TinyXML-2 preserves white space in a (hopefully) sane way that is almost complient with the
+By default, TinyXML-2 preserves white space in a (hopefully) sane way that is almost compliant with the
 spec. (TinyXML-1 used a completely different model, much more similar to 'collapse', below.)
 
 As a first step, all newlines / carriage-returns / line-feeds are normalized to a
@@ -157,6 +156,15 @@ However, you may also use COLLAPSE_WHITESPACE, which will:
 Note that (currently) there is a performance impact for using COLLAPSE_WHITESPACE.
 It essentially causes the XML to be parsed twice.
 
+#### Error Reporting
+
+TinyXML-2 reports the line number of any errors in an XML document that
+cannot be parsed correctly. In addition, all nodes (elements, declarations,
+text, comments etc.) and attributes have a line number recorded as they are parsed.
+This allows an application that performs additional validation of the parsed
+XML document (e.g. application-implemented DTD validation) to report
+line number information in it's errors.
+
 ### Entities
 
 TinyXML-2 recognizes the pre-defined "character entities", meaning special
index 9d6be5c3ac87922e133a089facc2804e988473a5..b8c45e62e9ffd8381d63801bf003fb619af9743e 100755 (executable)
@@ -149,6 +149,7 @@ void StrPair::TransferTo( StrPair* other )
     // This in effect implements the assignment operator by "moving"\r
     // ownership (as in auto_ptr).\r
 \r
+    TIXMLASSERT( other != 0 );\r
     TIXMLASSERT( other->_flags == 0 );\r
     TIXMLASSERT( other->_start == 0 );\r
     TIXMLASSERT( other->_end == 0 );\r
@@ -188,9 +189,11 @@ void StrPair::SetStr( const char* str, int flags )
 }\r
 \r
 \r
-char* StrPair::ParseText( char* p, const char* endTag, int strFlags )\r
+char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )\r
 {\r
+    TIXMLASSERT( p );\r
     TIXMLASSERT( endTag && *endTag );\r
+       TIXMLASSERT(curLineNumPtr);\r
 \r
     char* start = p;\r
     char  endChar = *endTag;\r
@@ -201,8 +204,11 @@ char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {\r
             Set( start, p, strFlags );\r
             return p + length;\r
+        } else if (*p == '\n') {\r
+            ++(*curLineNumPtr);\r
         }\r
         ++p;\r
+        TIXMLASSERT( p );\r
     }\r
     return 0;\r
 }\r
@@ -233,15 +239,15 @@ void StrPair::CollapseWhitespace()
     // Adjusting _start would cause undefined behavior on delete[]\r
     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );\r
     // Trim leading space.\r
-    _start = XMLUtil::SkipWhiteSpace( _start );\r
+    _start = XMLUtil::SkipWhiteSpace( _start, 0 );\r
 \r
     if ( *_start ) {\r
-        char* p = _start;      // the read pointer\r
+        const char* p = _start;        // the read pointer\r
         char* q = _start;      // the write pointer\r
 \r
         while( *p ) {\r
             if ( XMLUtil::IsWhiteSpace( *p )) {\r
-                p = XMLUtil::SkipWhiteSpace( p );\r
+                p = XMLUtil::SkipWhiteSpace( p, 0 );\r
                 if ( *p == 0 ) {\r
                     break;    // don't write to q; this trims the trailing space.\r
                 }\r
@@ -266,7 +272,7 @@ const char* StrPair::GetStr()
         _flags ^= NEEDS_FLUSH;\r
 \r
         if ( _flags ) {\r
-            char* p = _start;  // the read pointer\r
+            const char* p = _start;    // the read pointer\r
             char* q = _start;  // the write pointer\r
 \r
             while( p < _end ) {\r
@@ -280,7 +286,8 @@ const char* StrPair::GetStr()
                     else {\r
                         ++p;\r
                     }\r
-                    *q++ = LF;\r
+                    *q = LF;\r
+                    ++q;\r
                 }\r
                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {\r
                     if ( *(p+1) == CR ) {\r
@@ -289,7 +296,8 @@ const char* StrPair::GetStr()
                     else {\r
                         ++p;\r
                     }\r
-                    *q++ = LF;\r
+                    *q = LF;\r
+                    ++q;\r
                 }\r
                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {\r
                     // Entities handled by tinyXML2:\r
@@ -360,6 +368,19 @@ const char* StrPair::GetStr()
 \r
 // --------- XMLUtil ----------- //\r
 \r
+const char* XMLUtil::writeBoolTrue  = "true";\r
+const char* XMLUtil::writeBoolFalse = "false";\r
+\r
+void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)\r
+{\r
+       static const char* defTrue  = "true";\r
+       static const char* defFalse = "false";\r
+\r
+       writeBoolTrue = (writeTrue) ? writeTrue : defTrue;\r
+       writeBoolFalse = (writeFalse) ? writeFalse : defFalse;\r
+}\r
+\r
+\r
 const char* XMLUtil::ReadBOM( const char* p, bool* bom )\r
 {\r
     TIXMLASSERT( p );\r
@@ -537,7 +558,7 @@ void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
 \r
 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )\r
 {\r
-    TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );\r
+    TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);\r
 }\r
 \r
 /*\r
@@ -632,7 +653,8 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
     TIXMLASSERT( node );\r
     TIXMLASSERT( p );\r
     char* const start = p;\r
-    p = XMLUtil::SkipWhiteSpace( p );\r
+    int const startLine = _parseCurLineNum;\r
+    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );\r
     if( !*p ) {\r
         *node = 0;\r
         TIXMLASSERT( p );\r
@@ -656,42 +678,37 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );   // use same memory pool\r
     XMLNode* returnNode = 0;\r
     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {\r
-        TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );\r
-        returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );\r
-        returnNode->_memPool = &_commentPool;\r
+        returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );\r
+        returnNode->_parseLineNum = _parseCurLineNum;\r
         p += xmlHeaderLen;\r
     }\r
     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {\r
-        TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );\r
-        returnNode = new (_commentPool.Alloc()) XMLComment( this );\r
-        returnNode->_memPool = &_commentPool;\r
+        returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );\r
+        returnNode->_parseLineNum = _parseCurLineNum;\r
         p += commentHeaderLen;\r
     }\r
     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {\r
-        TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );\r
-        XMLText* text = new (_textPool.Alloc()) XMLText( this );\r
+        XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );\r
         returnNode = text;\r
-        returnNode->_memPool = &_textPool;\r
+        returnNode->_parseLineNum = _parseCurLineNum;\r
         p += cdataHeaderLen;\r
         text->SetCData( true );\r
     }\r
     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {\r
-        TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );\r
-        returnNode = new (_commentPool.Alloc()) XMLUnknown( this );\r
-        returnNode->_memPool = &_commentPool;\r
+        returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );\r
+        returnNode->_parseLineNum = _parseCurLineNum;\r
         p += dtdHeaderLen;\r
     }\r
     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {\r
-        TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );\r
-        returnNode = new (_elementPool.Alloc()) XMLElement( this );\r
-        returnNode->_memPool = &_elementPool;\r
+        returnNode =  CreateUnlinkedNode<XMLElement>( _elementPool );\r
+        returnNode->_parseLineNum = _parseCurLineNum;\r
         p += elementHeaderLen;\r
     }\r
     else {\r
-        TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );\r
-        returnNode = new (_textPool.Alloc()) XMLText( this );\r
-        returnNode->_memPool = &_textPool;\r
+        returnNode = CreateUnlinkedNode<XMLText>( _textPool );\r
+        returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character\r
         p = start;     // Back it up, all the text counts.\r
+        _parseCurLineNum = startLine;\r
     }\r
 \r
     TIXMLASSERT( returnNode );\r
@@ -720,6 +737,7 @@ bool XMLDocument::Accept( XMLVisitor* visitor ) const
 XMLNode::XMLNode( XMLDocument* doc ) :\r
     _document( doc ),\r
     _parent( 0 ),\r
+    _parseLineNum( 0 ),\r
     _firstChild( 0 ), _lastChild( 0 ),\r
     _prev( 0 ), _next( 0 ),\r
        _userData( 0 ),\r
@@ -738,7 +756,7 @@ XMLNode::~XMLNode()
 \r
 const char* XMLNode::Value() const \r
 {\r
-    // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.\r
+    // Edge case: XMLDocuments don't have a Value. Return null.\r
     if ( this->ToDocument() )\r
         return 0;\r
     return _value.GetStr();\r
@@ -754,16 +772,24 @@ void XMLNode::SetValue( const char* str, bool staticMem )
     }\r
 }\r
 \r
+XMLNode* XMLNode::DeepClone(XMLDocument* target) const\r
+{\r
+       XMLNode* clone = this->ShallowClone(target);\r
+       if (!clone) return 0;\r
+\r
+       for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {\r
+               XMLNode* childClone = child->DeepClone(target);\r
+               TIXMLASSERT(childClone);\r
+               clone->InsertEndChild(childClone);\r
+       }\r
+       return clone;\r
+}\r
 \r
 void XMLNode::DeleteChildren()\r
 {\r
     while( _firstChild ) {\r
         TIXMLASSERT( _lastChild );\r
-        TIXMLASSERT( _firstChild->_document == _document );\r
-        XMLNode* node = _firstChild;\r
-        Unlink( node );\r
-\r
-        DeleteNode( node );\r
+        DeleteChild( _firstChild );\r
     }\r
     _firstChild = _lastChild = 0;\r
 }\r
@@ -787,6 +813,8 @@ void XMLNode::Unlink( XMLNode* child )
     if ( child->_next ) {\r
         child->_next->_prev = child->_prev;\r
     }\r
+       child->_next = 0;\r
+       child->_prev = 0;\r
        child->_parent = 0;\r
 }\r
 \r
@@ -797,6 +825,9 @@ void XMLNode::DeleteChild( XMLNode* node )
     TIXMLASSERT( node->_document == _document );\r
     TIXMLASSERT( node->_parent == this );\r
     Unlink( node );\r
+       TIXMLASSERT(node->_prev == 0);\r
+       TIXMLASSERT(node->_next == 0);\r
+       TIXMLASSERT(node->_parent == 0);\r
     DeleteNode( node );\r
 }\r
 \r
@@ -896,11 +927,9 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
 const XMLElement* XMLNode::FirstChildElement( const char* name ) const\r
 {\r
     for( const XMLNode* node = _firstChild; node; node = node->_next ) {\r
-        const XMLElement* element = node->ToElement();\r
+        const XMLElement* element = node->ToElementWithName( name );\r
         if ( element ) {\r
-            if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {\r
-                return element;\r
-            }\r
+            return element;\r
         }\r
     }\r
     return 0;\r
@@ -910,11 +939,9 @@ const XMLElement* XMLNode::FirstChildElement( const char* name ) const
 const XMLElement* XMLNode::LastChildElement( const char* name ) const\r
 {\r
     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {\r
-        const XMLElement* element = node->ToElement();\r
+        const XMLElement* element = node->ToElementWithName( name );\r
         if ( element ) {\r
-            if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {\r
-                return element;\r
-            }\r
+            return element;\r
         }\r
     }\r
     return 0;\r
@@ -924,9 +951,8 @@ const XMLElement* XMLNode::LastChildElement( const char* name ) const
 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const\r
 {\r
     for( const XMLNode* node = _next; node; node = node->_next ) {\r
-        const XMLElement* element = node->ToElement();\r
-        if ( element\r
-                && (!name || XMLUtil::StringEqual( name, element->Name() ))) {\r
+        const XMLElement* element = node->ToElementWithName( name );\r
+        if ( element ) {\r
             return element;\r
         }\r
     }\r
@@ -937,9 +963,8 @@ const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const\r
 {\r
     for( const XMLNode* node = _prev; node; node = node->_prev ) {\r
-        const XMLElement* element = node->ToElement();\r
-        if ( element\r
-                && (!name || XMLUtil::StringEqual( name, element->Name() ))) {\r
+        const XMLElement* element = node->ToElementWithName( name );\r
+        if ( element ) {\r
             return element;\r
         }\r
     }\r
@@ -947,7 +972,7 @@ const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
 }\r
 \r
 \r
-char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )\r
+char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )\r
 {\r
     // This is a recursive method, but thinking about it "at the current level"\r
     // it is a pretty simple flat list:\r
@@ -970,37 +995,50 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
         XMLNode* node = 0;\r
 \r
         p = _document->Identify( p, &node );\r
+        TIXMLASSERT( p );\r
         if ( node == 0 ) {\r
             break;\r
         }\r
 \r
+        int initialLineNum = node->_parseLineNum;\r
+\r
         StrPair endTag;\r
-        p = node->ParseDeep( p, &endTag );\r
+        p = node->ParseDeep( p, &endTag, curLineNumPtr );\r
         if ( !p ) {\r
             DeleteNode( node );\r
             if ( !_document->Error() ) {\r
-                _document->SetError( XML_ERROR_PARSING, 0, 0 );\r
+                _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);\r
             }\r
             break;\r
         }\r
 \r
         XMLDeclaration* decl = node->ToDeclaration();\r
         if ( decl ) {\r
-                // A declaration can only be the first child of a document.\r
-                // Set error, if document already has children.\r
-                if ( !_document->NoChildren() ) {\r
-                        _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);\r
-                        DeleteNode( decl );\r
+            // Declarations are only allowed at document level\r
+            bool wellLocated = ( ToDocument() != 0 );\r
+            if ( wellLocated ) {\r
+                // Multiple declarations are allowed but all declarations\r
+                // must occur before anything else\r
+                for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {\r
+                    if ( !existingNode->ToDeclaration() ) {\r
+                        wellLocated = false;\r
                         break;\r
+                    }\r
                 }\r
+            }\r
+            if ( !wellLocated ) {\r
+                _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);\r
+                DeleteNode( node );\r
+                break;\r
+            }\r
         }\r
 \r
         XMLElement* ele = node->ToElement();\r
         if ( ele ) {\r
             // We read the end tag. Return it to the parent.\r
             if ( ele->ClosingType() == XMLElement::CLOSING ) {\r
-                if ( parentEnd ) {\r
-                    ele->_value.TransferTo( parentEnd );\r
+                if ( parentEndTag ) {\r
+                    ele->_value.TransferTo( parentEndTag );\r
                 }\r
                 node->_memPool->SetTracked();   // created and then immediately deleted.\r
                 DeleteNode( node );\r
@@ -1024,7 +1062,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
                 }\r
             }\r
             if ( mismatch ) {\r
-                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );\r
+                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);\r
                 DeleteNode( node );\r
                 break;\r
             }\r
@@ -1034,11 +1072,16 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
     return 0;\r
 }\r
 \r
-void XMLNode::DeleteNode( XMLNode* node )\r
+/*static*/ void XMLNode::DeleteNode( XMLNode* node )\r
 {\r
     if ( node == 0 ) {\r
         return;\r
     }\r
+       TIXMLASSERT(node->_document);\r
+       if (!node->ToDocument()) {\r
+               node->_document->MarkInUse(node);\r
+       }\r
+\r
     MemPool* pool = node->_memPool;\r
     node->~XMLNode();\r
     pool->Free( node );\r
@@ -1049,20 +1092,38 @@ void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
     TIXMLASSERT( insertThis );\r
     TIXMLASSERT( insertThis->_document == _document );\r
 \r
-    if ( insertThis->_parent )\r
+       if (insertThis->_parent) {\r
         insertThis->_parent->Unlink( insertThis );\r
-    else\r
+       }\r
+       else {\r
+               insertThis->_document->MarkInUse(insertThis);\r
         insertThis->_memPool->SetTracked();\r
+       }\r
+}\r
+\r
+const XMLElement* XMLNode::ToElementWithName( const char* name ) const\r
+{\r
+    const XMLElement* element = this->ToElement();\r
+    if ( element == 0 ) {\r
+        return 0;\r
+    }\r
+    if ( name == 0 ) {\r
+        return element;\r
+    }\r
+    if ( XMLUtil::StringEqual( element->Name(), name ) ) {\r
+       return element;\r
+    }\r
+    return 0;\r
 }\r
 \r
 // --------- XMLText ---------- //\r
-char* XMLText::ParseDeep( char* p, StrPair* )\r
+char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\r
 {\r
     const char* start = p;\r
     if ( this->CData() ) {\r
-        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );\r
+        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );\r
         if ( !p ) {\r
-            _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );\r
+            _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );\r
         }\r
         return p;\r
     }\r
@@ -1072,12 +1133,12 @@ char* XMLText::ParseDeep( char* p, StrPair* )
             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;\r
         }\r
 \r
-        p = _value.ParseText( p, "<", flags );\r
+        p = _value.ParseText( p, "<", flags, curLineNumPtr );\r
         if ( p && *p ) {\r
             return p-1;\r
         }\r
         if ( !p ) {\r
-            _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );\r
+            _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );\r
         }\r
     }\r
     return 0;\r
@@ -1097,6 +1158,7 @@ XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
 \r
 bool XMLText::ShallowEqual( const XMLNode* compare ) const\r
 {\r
+    TIXMLASSERT( compare );\r
     const XMLText* text = compare->ToText();\r
     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );\r
 }\r
@@ -1121,13 +1183,13 @@ XMLComment::~XMLComment()
 }\r
 \r
 \r
-char* XMLComment::ParseDeep( char* p, StrPair* )\r
+char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\r
 {\r
     // Comment parses as text.\r
     const char* start = p;\r
-    p = _value.ParseText( p, "-->", StrPair::COMMENT );\r
+    p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );\r
     if ( p == 0 ) {\r
-        _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );\r
+        _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );\r
     }\r
     return p;\r
 }\r
@@ -1171,13 +1233,13 @@ XMLDeclaration::~XMLDeclaration()
 }\r
 \r
 \r
-char* XMLDeclaration::ParseDeep( char* p, StrPair* )\r
+char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\r
 {\r
     // Declaration parses as text.\r
     const char* start = p;\r
-    p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );\r
+    p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );\r
     if ( p == 0 ) {\r
-        _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );\r
+        _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );\r
     }\r
     return p;\r
 }\r
@@ -1220,14 +1282,14 @@ XMLUnknown::~XMLUnknown()
 }\r
 \r
 \r
-char* XMLUnknown::ParseDeep( char* p, StrPair* )\r
+char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\r
 {\r
     // Unknown parses as text.\r
     const char* start = p;\r
 \r
-    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );\r
+    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );\r
     if ( !p ) {\r
-        _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );\r
+        _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );\r
     }\r
     return p;\r
 }\r
@@ -1269,7 +1331,7 @@ const char* XMLAttribute::Value() const
     return _value.GetStr();\r
 }\r
 \r
-char* XMLAttribute::ParseDeep( char* p, bool processEntities )\r
+char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )\r
 {\r
     // Parse using the name rules: bug fix, was using ParseText before\r
     p = _name.ParseName( p );\r
@@ -1278,13 +1340,13 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities )
     }\r
 \r
     // Skip white space before =\r
-    p = XMLUtil::SkipWhiteSpace( p );\r
+    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\r
     if ( *p != '=' ) {\r
         return 0;\r
     }\r
 \r
     ++p;       // move up to opening quote\r
-    p = XMLUtil::SkipWhiteSpace( p );\r
+    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\r
     if ( *p != '\"' && *p != '\'' ) {\r
         return 0;\r
     }\r
@@ -1292,7 +1354,7 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities )
     char endTag[2] = { *p, 0 };\r
     ++p;       // move past opening quote\r
 \r
-    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );\r
+    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );\r
     return p;\r
 }\r
 \r
@@ -1412,7 +1474,7 @@ void XMLAttribute::SetAttribute( float v )
 \r
 // --------- XMLElement ---------- //\r
 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),\r
-    _closingType( 0 ),\r
+    _closingType( OPEN ),\r
     _rootAttribute( 0 )\r
 {\r
 }\r
@@ -1451,6 +1513,47 @@ const char* XMLElement::Attribute( const char* name, const char* value ) const
     return 0;\r
 }\r
 \r
+int XMLElement::IntAttribute(const char* name, int defaultValue) const \r
+{\r
+       int i = defaultValue;\r
+       QueryIntAttribute(name, &i);\r
+       return i;\r
+}\r
+\r
+unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const \r
+{\r
+       unsigned i = defaultValue;\r
+       QueryUnsignedAttribute(name, &i);\r
+       return i;\r
+}\r
+\r
+int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const \r
+{\r
+       int64_t i = defaultValue;\r
+       QueryInt64Attribute(name, &i);\r
+       return i;\r
+}\r
+\r
+bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const \r
+{\r
+       bool b = defaultValue;\r
+       QueryBoolAttribute(name, &b);\r
+       return b;\r
+}\r
+\r
+double XMLElement::DoubleAttribute(const char* name, double defaultValue) const \r
+{\r
+       double d = defaultValue;\r
+       QueryDoubleAttribute(name, &d);\r
+       return d;\r
+}\r
+\r
+float XMLElement::FloatAttribute(const char* name, float defaultValue) const \r
+{\r
+       float f = defaultValue;\r
+       QueryFloatAttribute(name, &f);\r
+       return f;\r
+}\r
 \r
 const char* XMLElement::GetText() const\r
 {\r
@@ -1597,6 +1700,47 @@ XMLError XMLElement::QueryFloatText( float* fval ) const
     return XML_NO_TEXT_NODE;\r
 }\r
 \r
+int XMLElement::IntText(int defaultValue) const\r
+{\r
+       int i = defaultValue;\r
+       QueryIntText(&i);\r
+       return i;\r
+}\r
+\r
+unsigned XMLElement::UnsignedText(unsigned defaultValue) const\r
+{\r
+       unsigned i = defaultValue;\r
+       QueryUnsignedText(&i);\r
+       return i;\r
+}\r
+\r
+int64_t XMLElement::Int64Text(int64_t defaultValue) const\r
+{\r
+       int64_t i = defaultValue;\r
+       QueryInt64Text(&i);\r
+       return i;\r
+}\r
+\r
+bool XMLElement::BoolText(bool defaultValue) const\r
+{\r
+       bool b = defaultValue;\r
+       QueryBoolText(&b);\r
+       return b;\r
+}\r
+\r
+double XMLElement::DoubleText(double defaultValue) const\r
+{\r
+       double d = defaultValue;\r
+       QueryDoubleText(&d);\r
+       return d;\r
+}\r
+\r
+float XMLElement::FloatText(float defaultValue) const\r
+{\r
+       float f = defaultValue;\r
+       QueryFloatText(&f);\r
+       return f;\r
+}\r
 \r
 \r
 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )\r
@@ -1611,17 +1755,17 @@ XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
         }\r
     }\r
     if ( !attrib ) {\r
-        TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );\r
-        attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();\r
-        attrib->_memPool = &_document->_attributePool;\r
+        attrib = CreateAttribute();\r
+        TIXMLASSERT( attrib );\r
         if ( last ) {\r
+            TIXMLASSERT( last->_next == 0 );\r
             last->_next = attrib;\r
         }\r
         else {\r
+            TIXMLASSERT( _rootAttribute == 0 );\r
             _rootAttribute = attrib;\r
         }\r
         attrib->SetName( name );\r
-        attrib->_memPool->SetTracked(); // always created and linked.\r
     }\r
     return attrib;\r
 }\r
@@ -1646,30 +1790,31 @@ void XMLElement::DeleteAttribute( const char* name )
 }\r
 \r
 \r
-char* XMLElement::ParseAttributes( char* p )\r
+char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )\r
 {\r
     const char* start = p;\r
     XMLAttribute* prevAttribute = 0;\r
 \r
     // Read the attributes.\r
     while( p ) {\r
-        p = XMLUtil::SkipWhiteSpace( p );\r
+        p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\r
         if ( !(*p) ) {\r
-            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );\r
+            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );\r
             return 0;\r
         }\r
 \r
         // attribute.\r
         if (XMLUtil::IsNameStartChar( *p ) ) {\r
-            TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );\r
-            XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();\r
-            attrib->_memPool = &_document->_attributePool;\r
-                       attrib->_memPool->SetTracked();\r
+            XMLAttribute* attrib = CreateAttribute();\r
+            TIXMLASSERT( attrib );\r
+            attrib->_parseLineNum = _document->_parseCurLineNum;\r
+\r
+            int attrLineNum = attrib->_parseLineNum;\r
 \r
-            p = attrib->ParseDeep( p, _document->ProcessEntities() );\r
+            p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );\r
             if ( !p || Attribute( attrib->Name() ) ) {\r
                 DeleteAttribute( attrib );\r
-                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );\r
+                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );\r
                 return 0;\r
             }\r
             // There is a minor bug here: if the attribute in the source xml\r
@@ -1678,9 +1823,11 @@ char* XMLElement::ParseAttributes( char* p )
             // avoids re-scanning the attribute list. Preferring performance for\r
             // now, may reconsider in the future.\r
             if ( prevAttribute ) {\r
+                TIXMLASSERT( prevAttribute->_next == 0 );\r
                 prevAttribute->_next = attrib;\r
             }\r
             else {\r
+                TIXMLASSERT( _rootAttribute == 0 );\r
                 _rootAttribute = attrib;\r
             }\r
             prevAttribute = attrib;\r
@@ -1696,7 +1843,7 @@ char* XMLElement::ParseAttributes( char* p )
             return p+2;        // done; sealed element.\r
         }\r
         else {\r
-            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );\r
+            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );\r
             return 0;\r
         }\r
     }\r
@@ -1713,14 +1860,24 @@ void XMLElement::DeleteAttribute( XMLAttribute* attribute )
     pool->Free( attribute );\r
 }\r
 \r
+XMLAttribute* XMLElement::CreateAttribute()\r
+{\r
+    TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );\r
+    XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();\r
+    TIXMLASSERT( attrib );\r
+    attrib->_memPool = &_document->_attributePool;\r
+    attrib->_memPool->SetTracked();\r
+    return attrib;\r
+}\r
+\r
 //\r
 //     <ele></ele>\r
 //     <ele>foo<b>bar</b></ele>\r
 //\r
-char* XMLElement::ParseDeep( char* p, StrPair* strPair )\r
+char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )\r
 {\r
     // Read the element name.\r
-    p = XMLUtil::SkipWhiteSpace( p );\r
+    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\r
 \r
     // The closing element is the </element> form. It is\r
     // parsed just like a regular element then deleted from\r
@@ -1735,12 +1892,12 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair )
         return 0;\r
     }\r
 \r
-    p = ParseAttributes( p );\r
-    if ( !p || !*p || _closingType ) {\r
+    p = ParseAttributes( p, curLineNumPtr );\r
+    if ( !p || !*p || _closingType != OPEN ) {\r
         return p;\r
     }\r
 \r
-    p = XMLNode::ParseDeep( p, strPair );\r
+    p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );\r
     return p;\r
 }\r
 \r
@@ -1826,15 +1983,15 @@ const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
 };\r
 \r
 \r
-XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :\r
+XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :\r
     XMLNode( 0 ),\r
     _writeBOM( false ),\r
     _processEntities( processEntities ),\r
     _errorID(XML_SUCCESS),\r
-    _whitespace( whitespace ),\r
-    _errorStr1( 0 ),\r
-    _errorStr2( 0 ),\r
-    _charBuffer( 0 )\r
+    _whitespaceMode( whitespaceMode ),\r
+    _errorLineNum( 0 ),\r
+    _charBuffer( 0 ),\r
+    _parseCurLineNum( 0 )\r
 {\r
     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)\r
     _document = this;\r
@@ -1847,16 +2004,30 @@ XMLDocument::~XMLDocument()
 }\r
 \r
 \r
+void XMLDocument::MarkInUse(XMLNode* node)\r
+{\r
+       TIXMLASSERT(node);\r
+       TIXMLASSERT(node->_parent == 0);\r
+\r
+       for (int i = 0; i < _unlinked.Size(); ++i) {\r
+               if (node == _unlinked[i]) {\r
+                       _unlinked.SwapRemove(i);\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
 void XMLDocument::Clear()\r
 {\r
     DeleteChildren();\r
+       while( _unlinked.Size()) {\r
+               DeleteNode(_unlinked[0]);       // Will remove from _unlinked as part of delete.\r
+       }\r
 \r
 #ifdef DEBUG\r
     const bool hadError = Error();\r
 #endif\r
-    _errorID = XML_SUCCESS;\r
-    _errorStr1 = 0;\r
-    _errorStr2 = 0;\r
+    ClearError();\r
 \r
     delete [] _charBuffer;\r
     _charBuffer = 0;\r
@@ -1879,11 +2050,22 @@ void XMLDocument::Clear()
 }\r
 \r
 \r
+void XMLDocument::DeepCopy(XMLDocument* target)\r
+{\r
+       TIXMLASSERT(target);\r
+    if (target == this) {\r
+        return; // technically success - a no-op.\r
+    }\r
+\r
+       target->Clear();\r
+       for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {\r
+               target->InsertEndChild(node->DeepClone(target));\r
+       }\r
+}\r
+\r
 XMLElement* XMLDocument::NewElement( const char* name )\r
 {\r
-    TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );\r
-    XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );\r
-    ele->_memPool = &_elementPool;\r
+    XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );\r
     ele->SetName( name );\r
     return ele;\r
 }\r
@@ -1891,9 +2073,7 @@ XMLElement* XMLDocument::NewElement( const char* name )
 \r
 XMLComment* XMLDocument::NewComment( const char* str )\r
 {\r
-    TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );\r
-    XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );\r
-    comment->_memPool = &_commentPool;\r
+    XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );\r
     comment->SetValue( str );\r
     return comment;\r
 }\r
@@ -1901,9 +2081,7 @@ XMLComment* XMLDocument::NewComment( const char* str )
 \r
 XMLText* XMLDocument::NewText( const char* str )\r
 {\r
-    TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );\r
-    XMLText* text = new (_textPool.Alloc()) XMLText( this );\r
-    text->_memPool = &_textPool;\r
+    XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );\r
     text->SetValue( str );\r
     return text;\r
 }\r
@@ -1911,9 +2089,7 @@ XMLText* XMLDocument::NewText( const char* str )
 \r
 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )\r
 {\r
-    TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );\r
-    XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );\r
-    dec->_memPool = &_commentPool;\r
+    XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );\r
     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );\r
     return dec;\r
 }\r
@@ -1921,9 +2097,7 @@ XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
 \r
 XMLUnknown* XMLDocument::NewUnknown( const char* str )\r
 {\r
-    TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );\r
-    XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );\r
-    unk->_memPool = &_commentPool;\r
+    XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );\r
     unk->SetValue( str );\r
     return unk;\r
 }\r
@@ -1967,7 +2141,7 @@ XMLError XMLDocument::LoadFile( const char* filename )
     Clear();\r
     FILE* fp = callfopen( filename, "rb" );\r
     if ( !fp ) {\r
-        SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );\r
+        SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );\r
         return _errorID;\r
     }\r
     LoadFile( fp );\r
@@ -2004,7 +2178,7 @@ XMLError XMLDocument::LoadFile( FILE* fp )
 \r
     fseek( fp, 0, SEEK_SET );\r
     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {\r
-        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\r
+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );\r
         return _errorID;\r
     }\r
 \r
@@ -2012,19 +2186,19 @@ XMLError XMLDocument::LoadFile( FILE* fp )
     const long filelength = ftell( fp );\r
     fseek( fp, 0, SEEK_SET );\r
     if ( filelength == -1L ) {\r
-        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\r
+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );\r
         return _errorID;\r
     }\r
     TIXMLASSERT( filelength >= 0 );\r
 \r
     if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {\r
         // Cannot handle files which won't fit in buffer together with null terminator\r
-        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\r
+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );\r
         return _errorID;\r
     }\r
 \r
     if ( filelength == 0 ) {\r
-        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );\r
+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );\r
         return _errorID;\r
     }\r
 \r
@@ -2033,7 +2207,7 @@ XMLError XMLDocument::LoadFile( FILE* fp )
     _charBuffer = new char[size+1];\r
     size_t read = fread( _charBuffer, 1, size, fp );\r
     if ( read != size ) {\r
-        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\r
+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );\r
         return _errorID;\r
     }\r
 \r
@@ -2048,7 +2222,7 @@ XMLError XMLDocument::SaveFile( const char* filename, bool compact )
 {\r
     FILE* fp = callfopen( filename, "w" );\r
     if ( !fp ) {\r
-        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );\r
+        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );\r
         return _errorID;\r
     }\r
     SaveFile(fp, compact);\r
@@ -2061,7 +2235,7 @@ XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
 {\r
     // Clear any error from the last save, otherwise it will get reported\r
     // for *this* call.\r
-       SetError(XML_SUCCESS, 0, 0);\r
+    ClearError();\r
     XMLPrinter stream( fp, compact );\r
     Print( &stream );\r
     return _errorID;\r
@@ -2073,7 +2247,7 @@ XMLError XMLDocument::Parse( const char* p, size_t len )
     Clear();\r
 \r
     if ( len == 0 || !p || !*p ) {\r
-        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );\r
+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );\r
         return _errorID;\r
     }\r
     if ( len == (size_t)(-1) ) {\r
@@ -2111,22 +2285,34 @@ void XMLDocument::Print( XMLPrinter* streamer ) const
 }\r
 \r
 \r
-void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )\r
+void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )\r
 {\r
     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );\r
     _errorID = error;\r
-    _errorStr1 = str1;\r
-    _errorStr2 = str2;\r
+       \r
+       _errorStr1.Reset();\r
+       _errorStr2.Reset();\r
+    _errorLineNum = lineNum;\r
+\r
+       if (str1)\r
+               _errorStr1.SetStr(str1);\r
+       if (str2)\r
+               _errorStr2.SetStr(str2);\r
 }\r
 \r
-const char* XMLDocument::ErrorName() const\r
+/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)\r
 {\r
-       TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );\r
-    const char* errorName = _errorNames[_errorID];\r
+       TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );\r
+    const char* errorName = _errorNames[errorID];\r
     TIXMLASSERT( errorName && errorName[0] );\r
     return errorName;\r
 }\r
 \r
+const char* XMLDocument::ErrorName() const\r
+{\r
+    return ErrorIDToName(_errorID);\r
+}\r
+\r
 void XMLDocument::PrintError() const\r
 {\r
     if ( Error() ) {\r
@@ -2134,18 +2320,18 @@ void XMLDocument::PrintError() const
         char buf1[LEN] = { 0 };\r
         char buf2[LEN] = { 0 };\r
 \r
-        if ( _errorStr1 ) {\r
-            TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );\r
+        if ( !_errorStr1.Empty() ) {\r
+            TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );\r
         }\r
-        if ( _errorStr2 ) {\r
-            TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );\r
+        if ( !_errorStr2.Empty() ) {\r
+            TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );\r
         }\r
 \r
         // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that\r
         // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning\r
         TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );\r
-        printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",\r
-                static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );\r
+        printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",\r
+                static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );\r
     }\r
 }\r
 \r
@@ -2153,14 +2339,16 @@ void XMLDocument::Parse()
 {\r
     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously\r
     TIXMLASSERT( _charBuffer );\r
+    _parseCurLineNum = 1;\r
+    _parseLineNum = 1;\r
     char* p = _charBuffer;\r
-    p = XMLUtil::SkipWhiteSpace( p );\r
+    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );\r
     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );\r
     if ( !*p ) {\r
-        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );\r
+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );\r
         return;\r
     }\r
-    ParseDeep(p, 0 );\r
+    ParseDeep(p, 0, &_parseCurLineNum );\r
 }\r
 \r
 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :\r
@@ -2178,7 +2366,7 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
     }\r
     for( int i=0; i<NUM_ENTITIES; ++i ) {\r
         const char entityValue = entities[i].value;\r
-        TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );\r
+        TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );\r
         _entityFlag[ (unsigned char)entityValue ] = true;\r
     }\r
     _restrictedEntityFlag[(unsigned char)'&'] = true;\r
@@ -2397,6 +2585,13 @@ void XMLPrinter::PushText( const char* text, bool cdata )
     }\r
 }\r
 \r
+void XMLPrinter::PushText( int64_t value )\r
+{\r
+    char buf[BUF_SIZE];\r
+    XMLUtil::ToStr( value, buf, BUF_SIZE );\r
+    PushText( buf, false );\r
+}\r
+\r
 void XMLPrinter::PushText( int value )\r
 {\r
     char buf[BUF_SIZE];\r
index fb4376d3007508c8c37a0e95083c4e0dbaa67f82..dea324ef5b13faa5dfadce15a843b14befc0e7c9 100755 (executable)
@@ -53,7 +53,7 @@ distribution.
         AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h\r
 */\r
 \r
-#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)\r
+#if defined( _DEBUG ) || defined (__DEBUG__)\r
 #   ifndef DEBUG\r
 #       define DEBUG\r
 #   endif\r
@@ -72,6 +72,8 @@ distribution.
 #   else\r
 #       define TINYXML2_LIB\r
 #   endif\r
+#elif __GNUC__ >= 4\r
+#   define TINYXML2_LIB __attribute__((visibility("default")))\r
 #else\r
 #   define TINYXML2_LIB\r
 #endif\r
@@ -96,9 +98,9 @@ distribution.
 /* Versioning, past 1.0.14:\r
        http://semver.org/\r
 */\r
-static const int TIXML2_MAJOR_VERSION = 4;\r
+static const int TIXML2_MAJOR_VERSION = 5;\r
 static const int TIXML2_MINOR_VERSION = 0;\r
-static const int TIXML2_PATCH_VERSION = 1;\r
+static const int TIXML2_PATCH_VERSION = 0;\r
 \r
 namespace tinyxml2\r
 {\r
@@ -125,18 +127,20 @@ public:
         NEEDS_NEWLINE_NORMALIZATION            = 0x02,\r
         NEEDS_WHITESPACE_COLLAPSING     = 0x04,\r
 \r
-        TEXT_ELEMENT                           = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\r
+        TEXT_ELEMENT                       = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\r
         TEXT_ELEMENT_LEAVE_ENTITIES            = NEEDS_NEWLINE_NORMALIZATION,\r
-        ATTRIBUTE_NAME                         = 0,\r
-        ATTRIBUTE_VALUE                                = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\r
-        ATTRIBUTE_VALUE_LEAVE_ENTITIES         = NEEDS_NEWLINE_NORMALIZATION,\r
-        COMMENT                                        = NEEDS_NEWLINE_NORMALIZATION\r
+        ATTRIBUTE_NAME                     = 0,\r
+        ATTRIBUTE_VALUE                            = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\r
+        ATTRIBUTE_VALUE_LEAVE_ENTITIES  = NEEDS_NEWLINE_NORMALIZATION,\r
+        COMMENT                                                        = NEEDS_NEWLINE_NORMALIZATION\r
     };\r
 \r
     StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}\r
     ~StrPair();\r
 \r
     void Set( char* start, char* end, int flags ) {\r
+        TIXMLASSERT( start );\r
+        TIXMLASSERT( end );\r
         Reset();\r
         _start  = start;\r
         _end    = end;\r
@@ -156,13 +160,13 @@ public:
 \r
     void SetStr( const char* str, int flags=0 );\r
 \r
-    char* ParseText( char* in, const char* endTag, int strFlags );\r
+    char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );\r
     char* ParseName( char* in );\r
 \r
     void TransferTo( StrPair* other );\r
+       void Reset();\r
 \r
 private:\r
-    void Reset();\r
     void CollapseWhitespace();\r
 \r
     enum {\r
@@ -207,7 +211,8 @@ public:
     void Push( T t ) {\r
         TIXMLASSERT( _size < INT_MAX );\r
         EnsureCapacity( _size+1 );\r
-        _mem[_size++] = t;\r
+        _mem[_size] = t;\r
+        ++_size;\r
     }\r
 \r
     T* PushArr( int count ) {\r
@@ -221,7 +226,8 @@ public:
 \r
     T Pop() {\r
         TIXMLASSERT( _size > 0 );\r
-        return _mem[--_size];\r
+        --_size;\r
+        return _mem[_size];\r
     }\r
 \r
     void PopArr( int count ) {\r
@@ -258,6 +264,13 @@ public:
         return _allocated;\r
     }\r
 \r
+       void SwapRemove(int i) {\r
+               TIXMLASSERT(i >= 0 && i < _size);\r
+               TIXMLASSERT(_size > 0);\r
+               _mem[i] = _mem[_size - 1];\r
+               --_size;\r
+       }\r
+\r
     const T* Mem() const                               {\r
         TIXMLASSERT( _mem );\r
         return _mem;\r
@@ -278,6 +291,7 @@ private:
             TIXMLASSERT( cap <= INT_MAX / 2 );\r
             int newAllocated = cap * 2;\r
             T* newMem = new T[newAllocated];\r
+            TIXMLASSERT( newAllocated >= _size );\r
             memcpy( newMem, _mem, sizeof(T)*_size );   // warning: not using constructors, only works for PODs\r
             if ( _mem != _pool ) {\r
                 delete [] _mem;\r
@@ -315,7 +329,7 @@ public:
 /*\r
        Template child class to create pools of the correct type.\r
 */\r
-template< int SIZE >\r
+template< int ITEM_SIZE >\r
 class MemPoolT : public MemPool\r
 {\r
 public:\r
@@ -338,7 +352,7 @@ public:
     }\r
 \r
     virtual int ItemSize() const       {\r
-        return SIZE;\r
+        return ITEM_SIZE;\r
     }\r
     int CurrentAllocs() const          {\r
         return _currentAllocs;\r
@@ -350,21 +364,23 @@ public:
             Block* block = new Block();\r
             _blockPtrs.Push( block );\r
 \r
-            for( int i=0; i<COUNT-1; ++i ) {\r
-                block->chunk[i].next = &block->chunk[i+1];\r
+            Item* blockItems = block->items;\r
+            for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {\r
+                blockItems[i].next = &(blockItems[i + 1]);\r
             }\r
-            block->chunk[COUNT-1].next = 0;\r
-            _root = block->chunk;\r
+            blockItems[ITEMS_PER_BLOCK - 1].next = 0;\r
+            _root = blockItems;\r
         }\r
-        void* result = _root;\r
+        Item* const result = _root;\r
+        TIXMLASSERT( result != 0 );\r
         _root = _root->next;\r
 \r
         ++_currentAllocs;\r
         if ( _currentAllocs > _maxAllocs ) {\r
             _maxAllocs = _currentAllocs;\r
         }\r
-        _nAllocs++;\r
-        _nUntracked++;\r
+        ++_nAllocs;\r
+        ++_nUntracked;\r
         return result;\r
     }\r
     \r
@@ -373,20 +389,21 @@ public:
             return;\r
         }\r
         --_currentAllocs;\r
-        Chunk* chunk = static_cast<Chunk*>( mem );\r
+        Item* item = static_cast<Item*>( mem );\r
 #ifdef DEBUG\r
-        memset( chunk, 0xfe, sizeof(Chunk) );\r
+        memset( item, 0xfe, sizeof( *item ) );\r
 #endif\r
-        chunk->next = _root;\r
-        _root = chunk;\r
+        item->next = _root;\r
+        _root = item;\r
     }\r
     void Trace( const char* name ) {\r
         printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",\r
-                name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() );\r
+                name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,\r
+                ITEM_SIZE, _nAllocs, _blockPtrs.Size() );\r
     }\r
 \r
     void SetTracked() {\r
-        _nUntracked--;\r
+        --_nUntracked;\r
     }\r
 \r
     int Untracked() const {\r
@@ -402,21 +419,23 @@ public:
        //              16k:    5200\r
        //              32k:    4300\r
        //              64k:    4000    21000\r
-    enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private\r
+    // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK\r
+    // in private part if ITEMS_PER_BLOCK is private\r
+    enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };\r
 \r
 private:\r
     MemPoolT( const MemPoolT& ); // not supported\r
     void operator=( const MemPoolT& ); // not supported\r
 \r
-    union Chunk {\r
-        Chunk*  next;\r
-        char    mem[SIZE];\r
+    union Item {\r
+        Item*   next;\r
+        char    itemData[ITEM_SIZE];\r
     };\r
     struct Block {\r
-        Chunk chunk[COUNT];\r
+        Item items[ITEMS_PER_BLOCK];\r
     };\r
     DynArray< Block*, 10 > _blockPtrs;\r
-    Chunk* _root;\r
+    Item* _root;\r
 \r
     int _currentAllocs;\r
     int _nAllocs;\r
@@ -516,19 +535,23 @@ enum XMLError {
 /*\r
        Utility functionality.\r
 */\r
-class XMLUtil\r
+class TINYXML2_LIB XMLUtil\r
 {\r
 public:\r
-    static const char* SkipWhiteSpace( const char* p ) {\r
+    static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr )     {\r
         TIXMLASSERT( p );\r
+\r
         while( IsWhiteSpace(*p) ) {\r
+            if (curLineNumPtr && *p == '\n') {\r
+                ++(*curLineNumPtr);\r
+            }\r
             ++p;\r
         }\r
         TIXMLASSERT( p );\r
         return p;\r
     }\r
-    static char* SkipWhiteSpace( char* p )                             {\r
-        return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p) ) );\r
+    static char* SkipWhiteSpace( char* p, int* curLineNumPtr )                         {\r
+        return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );\r
     }\r
 \r
     // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't\r
@@ -559,6 +582,9 @@ public:
         if ( p == q ) {\r
             return true;\r
         }\r
+        TIXMLASSERT( p );\r
+        TIXMLASSERT( q );\r
+        TIXMLASSERT( nChar >= 0 );\r
         return strncmp( p, q, nChar ) == 0;\r
     }\r
     \r
@@ -587,6 +613,17 @@ public:
     static bool        ToFloat( const char* str, float* value );\r
     static bool ToDouble( const char* str, double* value );\r
        static bool ToInt64(const char* str, int64_t* value);\r
+\r
+       // Changes what is serialized for a boolean value.\r
+       // Default to "true" and "false". Shouldn't be changed\r
+       // unless you have a special testing or compatibility need.\r
+       // Be careful: static, global, & not thread safe.\r
+       // Be sure to set static const memory as parameters.\r
+       static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);\r
+\r
+private:\r
+       static const char* writeBoolTrue;\r
+       static const char* writeBoolFalse;\r
 };\r
 \r
 \r
@@ -692,6 +729,9 @@ public:
     */\r
     void SetValue( const char* val, bool staticMem=false );\r
 \r
+    /// Gets the line number the node is in, if the document was parsed from a file.\r
+    int GetLineNum() const { return _parseLineNum; }\r
+\r
     /// Get the parent of this node on the DOM.\r
     const XMLNode*     Parent() const                  {\r
         return _parent;\r
@@ -825,6 +865,21 @@ public:
     */\r
     virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;\r
 \r
+       /**\r
+               Make a copy of this node and all its children.\r
+\r
+               If the 'target' is null, then the nodes will\r
+               be allocated in the current document. If 'target' \r
+        is specified, the memory will be allocated is the \r
+        specified XMLDocument.\r
+\r
+               NOTE: This is probably not the correct tool to \r
+               copy a document, since XMLDocuments can have multiple\r
+               top level XMLNodes. You probably want to use\r
+        XMLDocument::DeepCopy()\r
+       */\r
+       XMLNode* DeepClone( XMLDocument* target ) const;\r
+\r
     /**\r
        Test if 2 nodes are the same, but don't test children.\r
        The 2 nodes do not need to be in the same Document.\r
@@ -875,11 +930,12 @@ protected:
     XMLNode( XMLDocument* );\r
     virtual ~XMLNode();\r
 \r
-    virtual char* ParseDeep( char*, StrPair* );\r
+    virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);\r
 \r
     XMLDocument*       _document;\r
     XMLNode*           _parent;\r
     mutable StrPair    _value;\r
+    int             _parseLineNum;\r
 \r
     XMLNode*           _firstChild;\r
     XMLNode*           _lastChild;\r
@@ -894,6 +950,7 @@ private:
     void Unlink( XMLNode* child );\r
     static void DeleteNode( XMLNode* node );\r
     void InsertChildPreamble( XMLNode* insertThis ) const;\r
+    const XMLElement* ToElementWithName( const char* name ) const;\r
 \r
     XMLNode( const XMLNode& ); // not supported\r
     XMLNode& operator=( const XMLNode& );      // not supported\r
@@ -941,7 +998,7 @@ protected:
     XMLText( XMLDocument* doc )        : XMLNode( doc ), _isCData( false )     {}\r
     virtual ~XMLText()                                                                                         {}\r
 \r
-    char* ParseDeep( char*, StrPair* endTag );\r
+    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );\r
 \r
 private:\r
     bool _isCData;\r
@@ -972,7 +1029,7 @@ protected:
     XMLComment( XMLDocument* doc );\r
     virtual ~XMLComment();\r
 \r
-    char* ParseDeep( char*, StrPair* endTag );\r
+    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);\r
 \r
 private:\r
     XMLComment( const XMLComment& );   // not supported\r
@@ -1011,7 +1068,7 @@ protected:
     XMLDeclaration( XMLDocument* doc );\r
     virtual ~XMLDeclaration();\r
 \r
-    char* ParseDeep( char*, StrPair* endTag );\r
+    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );\r
 \r
 private:\r
     XMLDeclaration( const XMLDeclaration& );   // not supported\r
@@ -1046,7 +1103,7 @@ protected:
     XMLUnknown( XMLDocument* doc );\r
     virtual ~XMLUnknown();\r
 \r
-    char* ParseDeep( char*, StrPair* endTag );\r
+    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );\r
 \r
 private:\r
     XMLUnknown( const XMLUnknown& );   // not supported\r
@@ -1071,6 +1128,9 @@ public:
     /// The value of the attribute.\r
     const char* Value() const;\r
 \r
+    /// Gets the line number the attribute is in, if the document was parsed from a file.\r
+    int GetLineNum() const { return _parseLineNum; }\r
+\r
     /// The next attribute in the list.\r
     const XMLAttribute* Next() const {\r
         return _next;\r
@@ -1118,7 +1178,7 @@ public:
     }\r
 \r
     /** QueryIntValue interprets the attribute as an integer, and returns the value\r
-       in the provided parameter. The function will return XML_NO_ERROR on success,\r
+       in the provided parameter. The function will return XML_SUCCESS on success,\r
        and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.\r
     */\r
     XMLError QueryIntValue( int* value ) const;\r
@@ -1151,17 +1211,18 @@ public:
 private:\r
     enum { BUF_SIZE = 200 };\r
 \r
-    XMLAttribute() : _next( 0 ), _memPool( 0 ) {}\r
+    XMLAttribute() : _parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}\r
     virtual ~XMLAttribute()    {}\r
 \r
     XMLAttribute( const XMLAttribute& );       // not supported\r
     void operator=( const XMLAttribute& );     // not supported\r
     void SetName( const char* name );\r
 \r
-    char* ParseDeep( char* p, bool processEntities );\r
+    char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );\r
 \r
     mutable StrPair _name;\r
     mutable StrPair _value;\r
+    int             _parseLineNum;\r
     XMLAttribute*   _next;\r
     MemPool*        _memPool;\r
 };\r
@@ -1218,51 +1279,25 @@ public:
     const char* Attribute( const char* name, const char* value=0 ) const;\r
 \r
     /** Given an attribute name, IntAttribute() returns the value\r
-       of the attribute interpreted as an integer. 0 will be\r
-       returned if there is an error. For a method with error\r
-       checking, see QueryIntAttribute()\r
+       of the attribute interpreted as an integer. The default\r
+        value will be returned if the attribute isn't present,\r
+        or if there is an error. (For a method with error\r
+       checking, see QueryIntAttribute()).\r
     */\r
-    int                 IntAttribute( const char* name ) const         {\r
-        int i=0;\r
-        QueryIntAttribute( name, &i );\r
-        return i;\r
-    }\r
-\r
+       int IntAttribute(const char* name, int defaultValue = 0) const;\r
     /// See IntAttribute()\r
-    unsigned UnsignedAttribute( const char* name ) const {\r
-        unsigned i=0;\r
-        QueryUnsignedAttribute( name, &i );\r
-        return i;\r
-    }\r
-\r
+       unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;\r
        /// See IntAttribute()\r
-       int64_t Int64Attribute(const char* name) const {\r
-               int64_t i = 0;\r
-               QueryInt64Attribute(name, &i);\r
-               return i;\r
-       }\r
-\r
+       int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;\r
        /// See IntAttribute()\r
-    bool BoolAttribute( const char* name ) const       {\r
-        bool b=false;\r
-        QueryBoolAttribute( name, &b );\r
-        return b;\r
-    }\r
+       bool BoolAttribute(const char* name, bool defaultValue = false) const;\r
     /// See IntAttribute()\r
-    double DoubleAttribute( const char* name ) const   {\r
-        double d=0;\r
-        QueryDoubleAttribute( name, &d );\r
-        return d;\r
-    }\r
+       double DoubleAttribute(const char* name, double defaultValue = 0) const;\r
     /// See IntAttribute()\r
-    float FloatAttribute( const char* name ) const     {\r
-        float f=0;\r
-        QueryFloatAttribute( name, &f );\r
-        return f;\r
-    }\r
+       float FloatAttribute(const char* name, float defaultValue = 0) const;\r
 \r
     /** Given an attribute name, QueryIntAttribute() returns\r
-       XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion\r
+       XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion\r
        can't be performed, or XML_NO_ATTRIBUTE if the attribute\r
        doesn't exist. If successful, the result of the conversion\r
        will be written to 'value'. If not successful, nothing will\r
@@ -1327,7 +1362,7 @@ public:
 \r
        \r
     /** Given an attribute name, QueryAttribute() returns\r
-       XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion\r
+       XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion\r
        can't be performed, or XML_NO_ATTRIBUTE if the attribute\r
        doesn't exist. It is overloaded for the primitive types,\r
                and is a generally more convenient replacement of\r
@@ -1533,20 +1568,33 @@ public:
     /// See QueryIntText()\r
     XMLError QueryFloatText( float* fval ) const;\r
 \r
+       int IntText(int defaultValue = 0) const;\r
+\r
+       /// See QueryIntText()\r
+       unsigned UnsignedText(unsigned defaultValue = 0) const;\r
+       /// See QueryIntText()\r
+       int64_t Int64Text(int64_t defaultValue = 0) const;\r
+       /// See QueryIntText()\r
+       bool BoolText(bool defaultValue = false) const;\r
+       /// See QueryIntText()\r
+       double DoubleText(double defaultValue = 0) const;\r
+       /// See QueryIntText()\r
+       float FloatText(float defaultValue = 0) const;\r
+\r
     // internal:\r
-    enum {\r
+    enum ElementClosingType {\r
         OPEN,          // <foo>\r
         CLOSED,                // <foo/>\r
         CLOSING                // </foo>\r
     };\r
-    int ClosingType() const {\r
+    ElementClosingType ClosingType() const {\r
         return _closingType;\r
     }\r
     virtual XMLNode* ShallowClone( XMLDocument* document ) const;\r
     virtual bool ShallowEqual( const XMLNode* compare ) const;\r
 \r
 protected:\r
-    char* ParseDeep( char* p, StrPair* endTag );\r
+    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );\r
 \r
 private:\r
     XMLElement( XMLDocument* doc );\r
@@ -1559,11 +1607,12 @@ private:
     }\r
     XMLAttribute* FindOrCreateAttribute( const char* name );\r
     //void LinkAttribute( XMLAttribute* attrib );\r
-    char* ParseAttributes( char* p );\r
+    char* ParseAttributes( char* p, int* curLineNumPtr );\r
     static void DeleteAttribute( XMLAttribute* attribute );\r
+    XMLAttribute* CreateAttribute();\r
 \r
     enum { BUF_SIZE = 200 };\r
-    int _closingType;\r
+    ElementClosingType _closingType;\r
     // The attribute list is ordered; there is no 'lastAttribute'\r
     // because the list needs to be scanned for dupes before adding\r
     // a new attribute.\r
@@ -1587,7 +1636,7 @@ class TINYXML2_LIB XMLDocument : public XMLNode
     friend class XMLElement;\r
 public:\r
     /// constructor\r
-    XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE );\r
+    XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );\r
     ~XMLDocument();\r
 \r
     virtual XMLDocument* ToDocument()                          {\r
@@ -1601,7 +1650,7 @@ public:
 \r
     /**\r
        Parse an XML file from a character string.\r
-       Returns XML_NO_ERROR (0) on success, or\r
+       Returns XML_SUCCESS (0) on success, or\r
        an errorID.\r
 \r
        You may optionally pass in the 'nBytes', which is\r
@@ -1613,7 +1662,7 @@ public:
 \r
     /**\r
        Load an XML file from disk.\r
-       Returns XML_NO_ERROR (0) on success, or\r
+       Returns XML_SUCCESS (0) on success, or\r
        an errorID.\r
     */\r
     XMLError LoadFile( const char* filename );\r
@@ -1626,14 +1675,14 @@ public:
         not text in order for TinyXML-2 to correctly\r
         do newline normalization.\r
 \r
-       Returns XML_NO_ERROR (0) on success, or\r
+       Returns XML_SUCCESS (0) on success, or\r
        an errorID.\r
     */\r
     XMLError LoadFile( FILE* );\r
 \r
     /**\r
        Save the XML file to disk.\r
-       Returns XML_NO_ERROR (0) on success, or\r
+       Returns XML_SUCCESS (0) on success, or\r
        an errorID.\r
     */\r
     XMLError SaveFile( const char* filename, bool compact = false );\r
@@ -1642,7 +1691,7 @@ public:
        Save the XML file to disk. You are responsible\r
        for providing and closing the FILE*.\r
 \r
-       Returns XML_NO_ERROR (0) on success, or\r
+       Returns XML_SUCCESS (0) on success, or\r
        an errorID.\r
     */\r
     XMLError SaveFile( FILE* fp, bool compact = false );\r
@@ -1651,7 +1700,7 @@ public:
         return _processEntities;\r
     }\r
     Whitespace WhitespaceMode() const  {\r
-        return _whitespace;\r
+        return _whitespaceMode;\r
     }\r
 \r
     /**\r
@@ -1736,7 +1785,11 @@ public:
     */\r
     void DeleteNode( XMLNode* node );\r
 \r
-    void SetError( XMLError error, const char* str1, const char* str2 );\r
+    void SetError( XMLError error, const char* str1, const char* str2, int lineNum );\r
+\r
+    void ClearError() {\r
+        SetError(XML_SUCCESS, 0, 0, 0);\r
+    }\r
 \r
     /// Return true if there was an error parsing the document.\r
     bool Error() const {\r
@@ -1747,14 +1800,20 @@ public:
         return _errorID;\r
     }\r
        const char* ErrorName() const;\r
+    static const char* ErrorIDToName(XMLError errorID);\r
 \r
     /// Return a possibly helpful diagnostic location or string.\r
     const char* GetErrorStr1() const {\r
-        return _errorStr1;\r
+        return _errorStr1.GetStr();\r
     }\r
     /// Return a possibly helpful secondary diagnostic location or string.\r
     const char* GetErrorStr2() const {\r
-        return _errorStr2;\r
+        return _errorStr2.GetStr();\r
+    }\r
+    /// Return the line where the error occured, or zero if unknown.\r
+    int GetErrorLineNum() const\r
+    {\r
+        return _errorLineNum;\r
     }\r
     /// If there is an error, print it to stdout.\r
     void PrintError() const;\r
@@ -1762,9 +1821,21 @@ public:
     /// Clear the document, resetting it to the initial state.\r
     void Clear();\r
 \r
-    // internal\r
+       /**\r
+               Copies this document to a target document.\r
+               The target will be completely cleared before the copy.\r
+               If you want to copy a sub-tree, see XMLNode::DeepClone().\r
+\r
+               NOTE: that the 'target' must be non-null.\r
+       */\r
+       void DeepCopy(XMLDocument* target);\r
+\r
+       // internal\r
     char* Identify( char* p, XMLNode** node );\r
 \r
+       // internal\r
+       void MarkInUse(XMLNode*);\r
+\r
     virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const   {\r
         return 0;\r
     }\r
@@ -1776,13 +1847,22 @@ private:
     XMLDocument( const XMLDocument& ); // not supported\r
     void operator=( const XMLDocument& );      // not supported\r
 \r
-    bool        _writeBOM;\r
-    bool        _processEntities;\r
-    XMLError    _errorID;\r
-    Whitespace  _whitespace;\r
-    const char* _errorStr1;\r
-    const char* _errorStr2;\r
-    char*       _charBuffer;\r
+    bool                       _writeBOM;\r
+    bool                       _processEntities;\r
+    XMLError           _errorID;\r
+    Whitespace         _whitespaceMode;\r
+    mutable StrPair    _errorStr1;\r
+    mutable StrPair    _errorStr2;\r
+    int             _errorLineNum;\r
+    char*                      _charBuffer;\r
+    int                                _parseCurLineNum;\r
+       // Memory tracking does add some overhead.\r
+       // However, the code assumes that you don't\r
+       // have a bunch of unlinked nodes around.\r
+       // Therefore it takes less memory to track\r
+       // in the document vs. a linked list in the XMLNode,\r
+       // and the performance is the same.\r
+       DynArray<XMLNode*, 10> _unlinked;\r
 \r
     MemPoolT< sizeof(XMLElement) >      _elementPool;\r
     MemPoolT< sizeof(XMLAttribute) > _attributePool;\r
@@ -1792,8 +1872,23 @@ private:
        static const char* _errorNames[XML_ERROR_COUNT];\r
 \r
     void Parse();\r
+\r
+    template<class NodeType, int PoolElementSize>\r
+    NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );\r
 };\r
 \r
+template<class NodeType, int PoolElementSize>\r
+inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )\r
+{\r
+    TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );\r
+    TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );\r
+    NodeType* returnNode = new (pool.Alloc()) NodeType( this );\r
+    TIXMLASSERT( returnNode );\r
+    returnNode->_memPool = &pool;\r
+\r
+       _unlinked.Push(returnNode);\r
+    return returnNode;\r
+}\r
 \r
 /**\r
        A XMLHandle is a class that wraps a node pointer with null checks; this is\r
@@ -1910,19 +2005,19 @@ public:
     }\r
     /// Safe cast to XMLElement. This can return null.\r
     XMLElement* ToElement()                                    {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToElement() );\r
+        return ( _node ? _node->ToElement() : 0 );\r
     }\r
     /// Safe cast to XMLText. This can return null.\r
     XMLText* ToText()                                                  {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToText() );\r
+        return ( _node ? _node->ToText() : 0 );\r
     }\r
     /// Safe cast to XMLUnknown. This can return null.\r
     XMLUnknown* ToUnknown()                                    {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToUnknown() );\r
+        return ( _node ? _node->ToUnknown() : 0 );\r
     }\r
     /// Safe cast to XMLDeclaration. This can return null.\r
     XMLDeclaration* ToDeclaration()                    {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() );\r
+        return ( _node ? _node->ToDeclaration() : 0 );\r
     }\r
 \r
 private:\r
@@ -1982,16 +2077,16 @@ public:
         return _node;\r
     }\r
     const XMLElement* ToElement() const                        {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToElement() );\r
+        return ( _node ? _node->ToElement() : 0 );\r
     }\r
     const XMLText* ToText() const                              {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToText() );\r
+        return ( _node ? _node->ToText() : 0 );\r
     }\r
     const XMLUnknown* ToUnknown() const                        {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToUnknown() );\r
+        return ( _node ? _node->ToUnknown() : 0 );\r
     }\r
     const XMLDeclaration* ToDeclaration() const        {\r
-        return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() );\r
+        return ( _node ? _node->ToDeclaration() : 0 );\r
     }\r
 \r
 private:\r
@@ -2125,6 +2220,7 @@ public:
     void ClearBuffer() {\r
         _buffer.Clear();\r
         _buffer.Push(0);\r
+               _firstElement = true;\r
     }\r
 \r
 protected:\r
index d46eb75d66304708ab237b14f128a3c045cbe932..9929f75687198102a54777a65f8271a18056ad98 100644 (file)
   <PropertyGroup Label="UserMacros" />\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'" />\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'">\r
-    <IntDir>$(SolutionDir)$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
     <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'" />\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">\r
-    <IntDir>$(SolutionDir)$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
     <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'" />\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'">\r
-    <IntDir>$(SolutionDir)$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
     <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'" />\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'">\r
-    <IntDir>$(SolutionDir)$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
     <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'">\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'">\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'">\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'">\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'">\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'">\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'">\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'">\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">\r
     <ClCompile>\r
index 4c46354ab9256e1a50730f6122150d46a3789667..a91d72d960e85ac9398148589abd62ef81ad735c 100755 (executable)
   <PropertyGroup Label="UserMacros" />\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">\r
     <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'">\r
     <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'">\r
     <LinkIncremental>true</LinkIncremental>\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'">\r
     <LinkIncremental>true</LinkIncremental>\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'">\r
     <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'">\r
     <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'">\r
     <LinkIncremental>false</LinkIncremental>\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'">\r
     <LinkIncremental>false</LinkIncremental>\r
-    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>\r
-    <IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>\r
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>\r
   </PropertyGroup>\r
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">\r
     <ClCompile>\r
index 7451fbe5a3080c2b2d0e8ce5363ce16b3f7074b0..3ed25b889b2af21fc20e659c8fc237f80e9a6f52 100644 (file)
 #include <ctime>\r
 \r
 #if defined( _MSC_VER )\r
-       #include <direct.h>             // _mkdir\r
        #include <crtdbg.h>\r
        #define WIN32_LEAN_AND_MEAN\r
        #include <windows.h>\r
        _CrtMemState startMemState;\r
        _CrtMemState endMemState;\r
-#elif defined(MINGW32) || defined(__MINGW32__)\r
-    #include <io.h>  // mkdir\r
-#else\r
-       #include <sys/stat.h>   // mkdir\r
 #endif\r
 \r
 using namespace tinyxml2;\r
@@ -63,6 +58,15 @@ bool XMLTest (const char* testString, const char* expected, const char* found, b
        return pass;\r
 }\r
 \r
+bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)\r
+{\r
+    return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);\r
+}\r
+\r
+bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)\r
+{\r
+    return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);\r
+}\r
 \r
 template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )\r
 {\r
@@ -288,17 +292,10 @@ int main( int argc, const char ** argv )
                _CrtMemCheckpoint( &startMemState );\r
                // Enable MS Visual C++ debug heap memory leaks dump on exit\r
                _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);\r
-       #endif\r
-\r
-       #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__)\r
-               #if defined __MINGW64_VERSION_MAJOR && defined __MINGW64_VERSION_MINOR\r
-                       //MINGW64: both 32 and 64-bit\r
-                       mkdir( "resources/out/" );\r
-                #else\r
-                       _mkdir( "resources/out/" );\r
-                #endif\r
-       #else\r
-               mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);\r
+               {\r
+                       int leaksOnStart = _CrtDumpMemoryLeaks();\r
+                       XMLTest( "No leaks on start?", FALSE, leaksOnStart );\r
+               }\r
        #endif\r
 \r
        {\r
@@ -436,10 +433,12 @@ int main( int argc, const char ** argv )
                element->LastChildElement()->DeleteAttribute( "attrib" );\r
 \r
                XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );\r
-               int value = 10;\r
-               int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );\r
+               int value1 = 10;\r
+               int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );\r
+               int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );\r
                XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );\r
-               XMLTest( "Programmatic DOM", value, 10 );\r
+               XMLTest( "Programmatic DOM", value1, 10 );\r
+               XMLTest( "Programmatic DOM", value2, 10 );\r
 \r
                doc->Print();\r
 \r
@@ -451,7 +450,7 @@ int main( int argc, const char ** argv )
                {\r
                        XMLPrinter streamer( 0, true );\r
                        doc->Print( &streamer );\r
-                       XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );\r
+                       XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );\r
                }\r
                doc->SaveFile( "./resources/out/pretty.xml" );\r
                doc->SaveFile( "./resources/out/compact.xml", true );\r
@@ -517,16 +516,24 @@ int main( int argc, const char ** argv )
                result = ele->QueryDoubleAttribute( "attr0", &dVal );\r
                XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);\r
                XMLTest( "Query attribute: int as double", (int)dVal, 1 );\r
+               XMLTest( "Query attribute: int as double", (int)ele->DoubleAttribute("attr0"), 1);\r
+\r
                result = ele->QueryDoubleAttribute( "attr1", &dVal );\r
                XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);\r
-               XMLTest( "Query attribute: double as double", (int)dVal, 2 );\r
+               XMLTest( "Query attribute: double as double", dVal, 2.0 );\r
+               XMLTest( "Query attribute: double as double", ele->DoubleAttribute("attr1"), 2.0 );\r
+\r
                result = ele->QueryIntAttribute( "attr1", &iVal );\r
                XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);\r
                XMLTest( "Query attribute: double as int", iVal, 2 );\r
+\r
                result = ele->QueryIntAttribute( "attr2", &iVal );\r
                XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );\r
+               XMLTest( "Query attribute: not a number", ele->DoubleAttribute("attr2", 4.0), 4.0 );\r
+\r
                result = ele->QueryIntAttribute( "bar", &iVal );\r
                XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );\r
+               XMLTest( "Query attribute: does not exist", ele->BoolAttribute("bar", true), true );\r
        }\r
 \r
        {\r
@@ -557,6 +564,8 @@ int main( int argc, const char ** argv )
                XMLTest( "Attribute round trip. double.", -1, (int)dVal );\r
                XMLTest( "Alternate query", true, iVal == iVal2 );\r
                XMLTest( "Alternate query", true, dVal == dVal2 );\r
+               XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );\r
+               XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );             \r
        }\r
 \r
        {\r
@@ -679,7 +688,7 @@ int main( int argc, const char ** argv )
                XMLTest( "SetText types", "1", element->GetText() );\r
 \r
                element->SetText( true );\r
-               XMLTest( "SetText types", "1", element->GetText() ); // TODO: should be 'true'?\r
+               XMLTest( "SetText types", "true", element->GetText() );\r
 \r
                element->SetText( 1.5f );\r
                XMLTest( "SetText types", "1.5", element->GetText() );\r
@@ -702,6 +711,7 @@ int main( int argc, const char ** argv )
                        XMLTest("Attribute: int", -100, v, true);\r
                        element->QueryAttribute("attrib", &v);\r
                        XMLTest("Attribute: int", -100, v, true);\r
+                       XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);\r
                }\r
                {\r
                        element->SetAttribute("attrib", unsigned(100));\r
@@ -710,6 +720,7 @@ int main( int argc, const char ** argv )
                        XMLTest("Attribute: unsigned", unsigned(100), v, true);\r
                        element->QueryAttribute("attrib", &v);\r
                        XMLTest("Attribute: unsigned", unsigned(100), v, true);\r
+                       XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);\r
                }\r
                {\r
                        element->SetAttribute("attrib", BIG);\r
@@ -718,6 +729,7 @@ int main( int argc, const char ** argv )
                        XMLTest("Attribute: int64_t", BIG, v, true);\r
                        element->QueryAttribute("attrib", &v);\r
                        XMLTest("Attribute: int64_t", BIG, v, true);\r
+                       XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);\r
                }\r
                {\r
                        element->SetAttribute("attrib", true);\r
@@ -726,6 +738,19 @@ int main( int argc, const char ** argv )
                        XMLTest("Attribute: bool", true, v, true);\r
                        element->QueryAttribute("attrib", &v);\r
                        XMLTest("Attribute: bool", true, v, true);\r
+                       XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);\r
+               }\r
+               {\r
+                       element->SetAttribute("attrib", true);\r
+                       const char* result = element->Attribute("attrib");\r
+                       XMLTest("Bool true is 'true'", "true", result);\r
+\r
+                       XMLUtil::SetBoolSerialization("1", "0");\r
+                       element->SetAttribute("attrib", true);\r
+                       result = element->Attribute("attrib");\r
+                       XMLTest("Bool true is '1'", "1", result);\r
+\r
+                       XMLUtil::SetBoolSerialization(0, 0);\r
                }\r
                {\r
                        element->SetAttribute("attrib", 100.0);\r
@@ -734,6 +759,7 @@ int main( int argc, const char ** argv )
                        XMLTest("Attribute: double", 100.0, v, true);\r
                        element->QueryAttribute("attrib", &v);\r
                        XMLTest("Attribute: double", 100.0, v, true);\r
+                       XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);\r
                }\r
                {\r
                        element->SetAttribute("attrib", 100.0f);\r
@@ -742,6 +768,7 @@ int main( int argc, const char ** argv )
                        XMLTest("Attribute: float", 100.0f, v, true);\r
                        element->QueryAttribute("attrib", &v);\r
                        XMLTest("Attribute: float", 100.0f, v, true);\r
+                       XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);\r
                }\r
                {\r
                        element->SetText(BIG);\r
@@ -1104,6 +1131,86 @@ int main( int argc, const char ** argv )
        }\r
 \r
        {\r
+               // Deep Cloning of root element.\r
+               XMLDocument doc2;\r
+               XMLPrinter printer1;\r
+               {\r
+                       // Make sure doc1 is deleted before we test doc2\r
+                       const char* xml =\r
+                               "<root>"\r
+                               "    <child1 foo='bar'/>"\r
+                               "    <!-- comment thing -->"\r
+                               "    <child2 val='1'>Text</child2>"\r
+                               "</root>";\r
+                       XMLDocument doc;\r
+                       doc.Parse(xml);\r
+\r
+                       doc.Print(&printer1);\r
+                       XMLNode* root = doc.RootElement()->DeepClone(&doc2);\r
+                       doc2.InsertFirstChild(root);\r
+               }\r
+               XMLPrinter printer2;\r
+               doc2.Print(&printer2);\r
+\r
+               XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);\r
+       }\r
+\r
+       {\r
+               // Deep Cloning of sub element.\r
+               XMLDocument doc2;\r
+               XMLPrinter printer1;\r
+               {\r
+                       // Make sure doc1 is deleted before we test doc2\r
+                       const char* xml =\r
+                               "<?xml version ='1.0'?>"\r
+                               "<root>"\r
+                               "    <child1 foo='bar'/>"\r
+                               "    <!-- comment thing -->"\r
+                               "    <child2 val='1'>Text</child2>"\r
+                               "</root>";\r
+                       XMLDocument doc;\r
+                       doc.Parse(xml);\r
+\r
+                       const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");\r
+                       subElement->Accept(&printer1);\r
+\r
+                       XMLNode* clonedSubElement = subElement->DeepClone(&doc2);\r
+                       doc2.InsertFirstChild(clonedSubElement);\r
+               }\r
+               XMLPrinter printer2;\r
+               doc2.Print(&printer2);\r
+\r
+               XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);\r
+       }\r
+\r
+       {\r
+               // Deep cloning of document.\r
+               XMLDocument doc2;\r
+               XMLPrinter printer1;\r
+               {\r
+                       // Make sure doc1 is deleted before we test doc2\r
+                       const char* xml =\r
+                               "<?xml version ='1.0'?>"\r
+                               "<!-- Top level comment. -->"\r
+                               "<root>"\r
+                               "    <child1 foo='bar'/>"\r
+                               "    <!-- comment thing -->"\r
+                               "    <child2 val='1'>Text</child2>"\r
+                               "</root>";\r
+                       XMLDocument doc;\r
+                       doc.Parse(xml);\r
+                       doc.Print(&printer1);\r
+\r
+                       doc.DeepCopy(&doc2);\r
+               }\r
+               XMLPrinter printer2;\r
+               doc2.Print(&printer2);\r
+\r
+               XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);\r
+       }\r
+\r
+\r
+       {\r
                // This shouldn't crash.\r
                XMLDocument doc;\r
                if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))\r
@@ -1570,22 +1677,31 @@ int main( int argc, const char ** argv )
        }\r
 \r
        {\r
-               // Check that declarations are parsed only as the FirstChild\r
+               // Check that declarations are allowed only at beginning of document\r
            const char* xml0 = "<?xml version=\"1.0\" ?>"\r
                               "   <!-- xml version=\"1.1\" -->"\r
                               "<first />";\r
            const char* xml1 = "<?xml version=\"1.0\" ?>"\r
-                              "   <?xml version=\"1.1\" ?>"\r
+                              "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"\r
                               "<first />";\r
            const char* xml2 = "<first />"\r
                               "<?xml version=\"1.0\" ?>";\r
+           const char* xml3 = "<first></first>"\r
+                              "<?xml version=\"1.0\" ?>";\r
+\r
+           const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";\r
+\r
            XMLDocument doc;\r
            doc.Parse(xml0);\r
            XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);\r
            doc.Parse(xml1);\r
-           XMLTest("Test that the second declaration throws an error", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);\r
+           XMLTest("Test that the second declaration is allowed", doc.Error(), false);\r
            doc.Parse(xml2);\r
-           XMLTest("Test that declaration after a child throws an error", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);\r
+           XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);\r
+           doc.Parse(xml3);\r
+           XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);\r
+           doc.Parse(xml4);\r
+           XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);\r
        }\r
 \r
     {\r
@@ -1604,11 +1720,221 @@ int main( int argc, const char ** argv )
        {\r
                XMLDocument doc;\r
                for( int i = 0; i < XML_ERROR_COUNT; i++ ) {\r
-                       doc.SetError( (XMLError)i, 0, 0 );\r
+                       doc.SetError( (XMLError)i, 0, 0, 0 );\r
                        doc.ErrorName();\r
                }\r
        }\r
 \r
+       {\r
+               // Evil memory leaks. \r
+               // If an XMLElement (etc) is allocated via NewElement() (etc.)\r
+               // and NOT added to the XMLDocument, what happens?\r
+               //\r
+               // Previously (buggy):\r
+               //              The memory would be free'd when the XMLDocument is\r
+               //      destructed. But the destructor wasn't called, so that\r
+               //      memory allocated by the XMLElement would not be free'd.\r
+               //      In practice this meant strings allocated by the XMLElement\r
+               //      would leak. An edge case, but annoying.\r
+               // Now:\r
+               //      The destructor is called. But the list of unlinked nodes\r
+               //      has to be tracked. This has a minor performance impact\r
+               //      that can become significant if you have a lot. (But why\r
+               //      would you do that?)\r
+               // The only way to see this bug is in a leak tracker. This\r
+               // is compiled in by default on Windows Debug.\r
+               {\r
+                       XMLDocument doc;\r
+                       doc.NewElement("LEAK 1");\r
+               }\r
+               {\r
+                       XMLDocument doc;\r
+                       XMLElement* ele = doc.NewElement("LEAK 2");\r
+                       doc.DeleteNode(ele);\r
+               }\r
+       }\r
+\r
+       {\r
+               // Crashing reported via email.\r
+               const char* xml =\r
+                       "<playlist id='playlist1'>"\r
+                       "<property name='track_name'>voice</property>"\r
+                       "<property name='audio_track'>1</property>"\r
+                       "<entry out = '604' producer = '4_playlist1' in = '0' />"\r
+                       "<blank length = '1' />"\r
+                       "<entry out = '1625' producer = '3_playlist' in = '0' />"\r
+                       "<blank length = '2' />"\r
+                       "<entry out = '946' producer = '2_playlist1' in = '0' />"\r
+                       "<blank length = '1' />"\r
+                       "<entry out = '128' producer = '1_playlist1' in = '0' />"\r
+                       "</playlist>";\r
+\r
+               // It's not a good idea to delete elements as you walk the\r
+               // list. I'm not sure this technically should work; but it's\r
+               // an interesting test case.\r
+               XMLDocument doc;\r
+               XMLError err = doc.Parse(xml);\r
+               XMLElement* playlist = doc.FirstChildElement("playlist");\r
+\r
+               XMLTest("Crash bug parsing", err, XML_SUCCESS);\r
+               XMLTest("Crash bug parsing", true, playlist != 0);\r
+\r
+               tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");\r
+               XMLTest("Crash bug parsing", true, entry != 0);\r
+               while (entry) {\r
+                       tinyxml2::XMLElement* todelete = entry;\r
+                       entry = entry->NextSiblingElement("entry");\r
+                       playlist->DeleteChild(todelete);\r
+               };\r
+               tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");\r
+               while (blank) {\r
+                       tinyxml2::XMLElement* todelete = blank;\r
+                       blank = blank->NextSiblingElement("blank");\r
+                       playlist->DeleteChild(todelete);\r
+               };\r
+\r
+               tinyxml2::XMLPrinter printer;\r
+               playlist->Accept(&printer);\r
+               printf("%s\n", printer.CStr());\r
+\r
+               // No test; it only need to not crash. \r
+               // Still, wrap it up with a sanity check\r
+               int nProperty = 0;\r
+               for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {\r
+                       nProperty++;\r
+               }\r
+               XMLTest("Crash bug parsing", nProperty, 2);\r
+       }\r
+\r
+    // ----------- Line Number Tracking --------------\r
+    {\r
+        struct TestUtil: XMLVisitor\r
+        {\r
+            void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)\r
+            {\r
+                XMLDocument doc;\r
+                XMLError err = doc.Parse(docStr);\r
+\r
+                XMLTest(testString, true, doc.Error());\r
+                XMLTest(testString, expected_error, err);\r
+                XMLTest(testString, expectedLine, doc.GetErrorLineNum());\r
+            };\r
+\r
+            void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)\r
+            {\r
+                XMLDocument doc;\r
+                doc.Parse(docStr);\r
+                XMLTest(testString, false, doc.Error());\r
+                TestDocLines(testString, doc, expectedLines);\r
+            }\r
+\r
+            void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)\r
+            {\r
+                XMLDocument doc;\r
+                doc.LoadFile(file_name);\r
+                XMLTest(testString, false, doc.Error());\r
+                TestDocLines(testString, doc, expectedLines);\r
+            }\r
+\r
+        private:\r
+            DynArray<char, 10> str;\r
+\r
+            void Push(char type, int lineNum)\r
+            {\r
+                str.Push(type);\r
+                str.Push(char('0' + (lineNum / 10)));\r
+                str.Push(char('0' + (lineNum % 10)));\r
+            }\r
+\r
+            bool VisitEnter(const XMLDocument& doc)\r
+            {\r
+                Push('D', doc.GetLineNum());\r
+                return true;\r
+            }\r
+            bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)\r
+            {\r
+                Push('E', element.GetLineNum());\r
+                for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())\r
+                    Push('A', attr->GetLineNum());\r
+                return true;\r
+            }\r
+            bool Visit(const XMLDeclaration& declaration)\r
+            {\r
+                Push('L', declaration.GetLineNum());\r
+                return true;\r
+            }\r
+            bool Visit(const XMLText& text)\r
+            {\r
+                Push('T', text.GetLineNum());\r
+                return true;\r
+            }\r
+            bool Visit(const XMLComment& comment)\r
+            {\r
+                Push('C', comment.GetLineNum());\r
+                return true;\r
+            }\r
+            bool Visit(const XMLUnknown& unknown)\r
+            {\r
+                Push('U', unknown.GetLineNum());\r
+                return true;\r
+            }\r
+\r
+            void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)\r
+            {\r
+                str.Clear();\r
+                doc.Accept(this);\r
+                str.Push(0);\r
+                XMLTest(testString, expectedLines, str.Mem());\r
+            }\r
+        } tester;\r
+\r
+               tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);\r
+        tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);\r
+        tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);\r
+        tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);\r
+        tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);\r
+        tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);\r
+        tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);\r
+        tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);\r
+        tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);\r
+        tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);\r
+        tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);\r
+\r
+               tester.TestStringLines(\r
+            "LineNumbers-String",\r
+\r
+            "<?xml version=\"1.0\"?>\n"                                        // 1 Doc, DecL\r
+                "<root a='b' \n"                                               // 2 Element Attribute\r
+                "c='d'> d <blah/>  \n"                                 // 3 Attribute Text Element\r
+                "newline in text \n"                                   // 4 Text\r
+                "and second <zxcv/><![CDATA[\n"                        // 5 Element Text\r
+                " cdata test ]]><!-- comment -->\n"            // 6 Comment\r
+                "<! unknown></root>",                                  // 7 Unknown\r
+\r
+            "D01L01E02A02A03T03E03T04E05T05C06U07");\r
+\r
+               tester.TestStringLines(\r
+            "LineNumbers-CRLF",\r
+\r
+            "\r\n"                                                                             // 1 Doc (arguably should be line 2)\r
+            "<?xml version=\"1.0\"?>\n"                                        // 2 DecL\r
+            "<root>\r\n"                                                               // 3 Element\r
+            "\n"                                                                               // 4\r
+            "text contining new line \n"                               // 5 Text\r
+            " and also containing crlf \r\n"                   // 6\r
+            "<sub><![CDATA[\n"                                                 // 7 Element Text\r
+            "cdata containing new line \n"                             // 8\r
+            " and also containing cflr\r\n"                            // 9\r
+            "]]></sub><sub2/></root>",                                 // 10 Element\r
+\r
+            "D01L02E03T05E07T07E10");\r
+\r
+               tester.TestFileLines(\r
+            "LineNumbers-File",\r
+            "resources/utf8test.xml",\r
+            "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");\r
+    }\r
+\r
     // ----------- Performance tracking --------------\r
        {\r
 #if defined( _MSC_VER )\r
@@ -1618,7 +1944,7 @@ int main( int argc, const char ** argv )
 \r
                FILE* perfFP = fopen("resources/dream.xml", "r");\r
                fseek(perfFP, 0, SEEK_END);\r
-               long size = ftell(fp);\r
+               long size = ftell(perfFP);\r
                fseek(perfFP, 0, SEEK_SET);\r
 \r
                char* mem = new char[size + 1];\r
@@ -1664,6 +1990,11 @@ int main( int argc, const char ** argv )
                _CrtMemState diffMemState;\r
                _CrtMemDifference( &diffMemState, &startMemState, &endMemState );\r
                _CrtMemDumpStatistics( &diffMemState );\r
+\r
+               {\r
+                       int leaksBeforeExit = _CrtDumpMemoryLeaks();\r
+                       XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );\r
+               }\r
        #endif\r
 \r
        printf ("\nPass %d, Fail %d\n", gPass, gFail);\r