Compare commits
155 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37bc3aca42 | ||
|
|
8c9e3133c4 | ||
|
|
563ee82093 | ||
|
|
4ee9ebdfd2 | ||
|
|
a4f48c1167 | ||
|
|
9832a5f05d | ||
|
|
48d45b29a9 | ||
|
|
5381145957 | ||
|
|
a5ab98a582 | ||
|
|
369f306b37 | ||
|
|
8bba8b41d6 | ||
|
|
3f169ac424 | ||
|
|
86be0cdfe5 | ||
|
|
aea64c4b75 | ||
|
|
dfcf5488ea | ||
|
|
9201bb96d3 | ||
|
|
3f63f21cf5 | ||
|
|
9e2d29b373 | ||
|
|
82bb074b49 | ||
|
|
224ef775c6 | ||
|
|
8a763619ac | ||
|
|
bc527554e8 | ||
|
|
5cfb946953 | ||
|
|
275067a91f | ||
|
|
ed78570c66 | ||
|
|
c2f677b05e | ||
|
|
1346a174ae | ||
|
|
1bbc66b193 | ||
|
|
e84f68a68a | ||
|
|
b754ddf0fb | ||
|
|
7ce75bc2bb | ||
|
|
816d3fa0cd | ||
|
|
53858b4490 | ||
|
|
ced18c05b9 | ||
|
|
a30f8bd136 | ||
|
|
b29f556ab0 | ||
|
|
7085f00e40 | ||
|
|
f66441e3e7 | ||
|
|
33a1f8bd6c | ||
|
|
7538286750 | ||
|
|
243ddf5304 | ||
|
|
105f32f64d | ||
|
|
174a5df3a3 | ||
|
|
9333cfd394 | ||
|
|
7b40ce1942 | ||
|
|
b840b7e673 | ||
|
|
10b8ecc99b | ||
|
|
2b0453f43e | ||
|
|
e503563f47 | ||
|
|
fc05f63575 | ||
|
|
ba68a3aea6 | ||
|
|
395ea09f83 | ||
|
|
71e2c08a7e | ||
|
|
7221b49fea | ||
|
|
ae8a82a734 | ||
|
|
92c0ef327f | ||
|
|
2aebfb7123 | ||
|
|
1e0b4e6b8a | ||
|
|
7f2ce0dc0e | ||
|
|
6bf64fb149 | ||
|
|
47c7d70064 | ||
|
|
b37cb42b78 | ||
|
|
0f42e24c47 | ||
|
|
969b8c2234 | ||
|
|
5277134efa | ||
|
|
4a07484e47 | ||
|
|
962732fd3e | ||
|
|
d120d64b86 | ||
|
|
1f5ab7cd0b | ||
|
|
f89bd3ef68 | ||
|
|
c5c99c2ba0 | ||
|
|
f458d265c1 | ||
|
|
ce667c9233 | ||
|
|
5b733ff481 | ||
|
|
c3a19156ff | ||
|
|
e90e901041 | ||
|
|
002713856b | ||
|
|
855a66c0ff | ||
|
|
ef7fe0fd98 | ||
|
|
34a3f8e34d | ||
|
|
19d8ea836f | ||
|
|
e353181a46 | ||
|
|
e3d44159e3 | ||
|
|
4f756161d0 | ||
|
|
2489afcc61 | ||
|
|
a43ff7210e | ||
|
|
ec6941503c | ||
|
|
156bc1b99f | ||
|
|
5bbb6fb052 | ||
|
|
5a70071241 | ||
|
|
0d2cef0cba | ||
|
|
a60caa28cc | ||
|
|
f80d78d938 | ||
|
|
ebb1660c2f | ||
|
|
7de0b6dd8c | ||
|
|
d04f21cab8 | ||
|
|
446c3bcae3 | ||
|
|
cd47f8e0d3 | ||
|
|
4336431272 | ||
|
|
13cbc9a708 | ||
|
|
c9a6102bf1 | ||
|
|
6bbcda0215 | ||
|
|
15ad07170d | ||
|
|
ed2627e5a7 | ||
|
|
c5f1e7ce6e | ||
|
|
3c21d6fbb7 | ||
|
|
f6106bec9a | ||
|
|
ecb9b07476 | ||
|
|
edb3261c51 | ||
|
|
01f6cca9e1 | ||
|
|
513e69ba68 | ||
|
|
cf3dd09b08 | ||
|
|
e8157ff9ae | ||
|
|
b2f4dc2a7b | ||
|
|
0d3de1edbe | ||
|
|
318252a973 | ||
|
|
3c97724d0e | ||
|
|
21f996960d | ||
|
|
f00c179eba | ||
|
|
7fcf31b2c3 | ||
|
|
6f1ad6153e | ||
|
|
aad61870a9 | ||
|
|
3b9cf99916 | ||
|
|
e9b547a9ee | ||
|
|
3a621f5b6e | ||
|
|
fed511276f | ||
|
|
584af57086 | ||
|
|
2e14517c89 | ||
|
|
24694e9519 | ||
|
|
0d667f8fef | ||
|
|
3161a33c86 | ||
|
|
2449582eaf | ||
|
|
6fc38ec7cc | ||
|
|
f9f3c3e85c | ||
|
|
4fe8c102da | ||
|
|
a369d4b614 | ||
|
|
1f212f3ab0 | ||
|
|
de45d04711 | ||
|
|
9cb4eca596 | ||
|
|
0bb5901961 | ||
|
|
9faf14df53 | ||
|
|
cb6461ca9c | ||
|
|
c7805c541c | ||
|
|
caa72a641e | ||
|
|
4de7abb573 | ||
|
|
8170bdc693 | ||
|
|
a8e7ea7fb0 | ||
|
|
88145b8ae6 | ||
|
|
75c8f40640 | ||
|
|
1043f6feed | ||
|
|
db02b21bc5 | ||
|
|
e1a82c1a50 | ||
|
|
74d44acb17 | ||
|
|
c9445466de | ||
|
|
5bf60e9dc6 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -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
|
||||
@@ -12,4 +12,4 @@ before_script: cmake .
|
||||
|
||||
script:
|
||||
- make -j3
|
||||
- ./xmltest
|
||||
- make test
|
||||
|
||||
144
CMakeLists.txt
144
CMakeLists.txt
@@ -7,9 +7,13 @@ IF(BIICODE)
|
||||
ENDIF(BIICODE)
|
||||
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
|
||||
cmake_policy(VERSION 2.6)
|
||||
if(POLICY CMP0063)
|
||||
cmake_policy(SET CMP0063 OLD)
|
||||
endif()
|
||||
|
||||
project(tinyxml2)
|
||||
include(GNUInstallDirs)
|
||||
include(CTest)
|
||||
#enable_testing()
|
||||
|
||||
#CMAKE_BUILD_TOOL
|
||||
@@ -17,52 +21,32 @@ include(GNUInstallDirs)
|
||||
################################
|
||||
# set lib version here
|
||||
|
||||
set(GENERIC_LIB_VERSION "4.0.0")
|
||||
set(GENERIC_LIB_SOVERSION "4")
|
||||
|
||||
|
||||
################################
|
||||
# Add common source
|
||||
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/.")
|
||||
|
||||
################################
|
||||
# Add custom target to copy all data
|
||||
|
||||
set(TARGET_DATA_COPY DATA_COPY)
|
||||
set(DATA_COPY_FILES)
|
||||
if(NOT ${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
|
||||
foreach(data dream.xml empty.xml utf8test.xml utf8testverify.xml)
|
||||
set(DATA_COPY_SRC ${CMAKE_CURRENT_SOURCE_DIR}/resources/${data})
|
||||
set(DATA_COPY_DEST ${CMAKE_CURRENT_BINARY_DIR}/resources/${data})
|
||||
add_custom_command(
|
||||
OUTPUT ${DATA_COPY_DEST}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy ${DATA_COPY_SRC} ${DATA_COPY_DEST}
|
||||
DEPENDS ${DATA_COPY_SRC})
|
||||
list(APPEND DATA_COPY_FILES ${DATA_COPY_DEST})
|
||||
endforeach(data)
|
||||
endif(NOT ${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_custom_target(${TARGET_DATA_COPY} DEPENDS ${DATA_COPY_FILES})
|
||||
set(GENERIC_LIB_VERSION "5.0.1")
|
||||
set(GENERIC_LIB_SOVERSION "5")
|
||||
|
||||
################################
|
||||
# Add definitions
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif(MSVC)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||
|
||||
################################
|
||||
# Add targets
|
||||
# By Default shared libray is being built
|
||||
# To build static libs also - Do cmake . -DBUILD_STATIC_LIBS:BOOL=ON
|
||||
# User can choose not to build shared library by using cmake -BUILD_SHARED_LIBS:BOOL:OFF
|
||||
# User can choose not to build shared library by using cmake -DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
# To build only static libs use cmake . -DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_STATIC_LIBS:BOOL=ON
|
||||
# To build the tests, use cmake . -DBUILD_TESTS:BOOL=ON
|
||||
# To disable the building of the tests, use cmake . -DBUILD_TESTS:BOOL=OFF
|
||||
|
||||
option(BUILD_SHARED_LIBS "build as shared library" ON)
|
||||
option(BUILD_STATIC_LIBS "build as static library" OFF)
|
||||
option(BUILD_TESTS "build xmltest (deprecated: Use BUILD_TESTING)" ON)
|
||||
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
||||
|
||||
# to distinguish between debug and release lib
|
||||
set(CMAKE_DEBUG_POSTFIX "d")
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
add_library(tinyxml2 SHARED tinyxml2.cpp tinyxml2.h)
|
||||
@@ -72,11 +56,29 @@ set_target_properties(tinyxml2 PROPERTIES
|
||||
VERSION "${GENERIC_LIB_VERSION}"
|
||||
SOVERSION "${GENERIC_LIB_SOVERSION}")
|
||||
|
||||
|
||||
if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
|
||||
target_include_directories(tinyxml2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/.")
|
||||
target_include_directories(tinyxml2 PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif(MSVC)
|
||||
else()
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif(MSVC)
|
||||
endif()
|
||||
|
||||
# export targets for find_package config mode
|
||||
export(TARGETS tinyxml2
|
||||
FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)
|
||||
|
||||
install(TARGETS tinyxml2
|
||||
EXPORT ${CMAKE_PROJECT_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
@@ -90,27 +92,54 @@ set_target_properties(tinyxml2_static PROPERTIES
|
||||
SOVERSION "${GENERIC_LIB_SOVERSION}")
|
||||
set_target_properties( tinyxml2_static PROPERTIES OUTPUT_NAME tinyxml2 )
|
||||
|
||||
target_compile_definitions(tinyxml2_static PUBLIC -D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
|
||||
target_include_directories(tinyxml2_static INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/.")
|
||||
target_include_directories(tinyxml2_static PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(tinyxml2_static PUBLIC -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif(MSVC)
|
||||
else()
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif(MSVC)
|
||||
endif()
|
||||
|
||||
# export targets for find_package config mode
|
||||
export(TARGETS tinyxml2_static
|
||||
FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)
|
||||
|
||||
install(TARGETS tinyxml2_static
|
||||
EXPORT ${CMAKE_PROJECT_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
add_executable(xmltest xmltest.cpp)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
add_dependencies(xmltest tinyxml2)
|
||||
add_dependencies(xmltest ${TARGET_DATA_COPY})
|
||||
target_link_libraries(xmltest tinyxml2)
|
||||
else(BUILD_STATIC_LIBS)
|
||||
add_dependencies(xmltest tinyxml2_static)
|
||||
add_dependencies(xmltest ${TARGET_DATA_COPY})
|
||||
target_link_libraries(xmltest tinyxml2_static)
|
||||
if(BUILD_TESTING AND BUILD_TESTS)
|
||||
add_executable(xmltest xmltest.cpp)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
add_dependencies(xmltest tinyxml2)
|
||||
target_link_libraries(xmltest tinyxml2)
|
||||
else(BUILD_STATIC_LIBS)
|
||||
add_dependencies(xmltest tinyxml2_static)
|
||||
target_link_libraries(xmltest tinyxml2_static)
|
||||
endif()
|
||||
|
||||
# Copy test resources and create test output directory
|
||||
add_custom_command(TARGET xmltest POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources $<TARGET_FILE_DIR:xmltest>/resources
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:xmltest>/resources/out
|
||||
COMMENT "Configuring xmltest resources directory: ${CMAKE_BINARY_DIR}/resources"
|
||||
)
|
||||
|
||||
add_test(NAME xmltest COMMAND xmltest)
|
||||
endif()
|
||||
install(TARGETS DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
install(FILES tinyxml2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
@@ -124,13 +153,24 @@ endforeach()
|
||||
configure_file(tinyxml2.pc.in tinyxml2.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
#add_test(xmltest ${SAMPLE_NAME} COMMAND $<TARGET_FILE:${SAMPLE_NAME}>)
|
||||
|
||||
# uninstall target
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
file(WRITE
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
|
||||
"include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n")
|
||||
|
||||
install(FILES
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
|
||||
DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
|
||||
|
||||
install(EXPORT ${CMAKE_PROJECT_NAME}Targets
|
||||
DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
|
||||
|
||||
@@ -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
|
||||
|
||||
2
dox
2
dox
@@ -38,7 +38,7 @@ PROJECT_NAME = "TinyXML-2"
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 4.0.0
|
||||
PROJECT_NUMBER = 5.0.1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
16
readme.md
16
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
|
||||
|
||||
512
tinyxml2.cpp
512
tinyxml2.cpp
File diff suppressed because it is too large
Load Diff
332
tinyxml2.h
332
tinyxml2.h
@@ -53,7 +53,7 @@ distribution.
|
||||
AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
|
||||
*/
|
||||
|
||||
#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
|
||||
#if defined( _DEBUG ) || defined (__DEBUG__)
|
||||
# ifndef DEBUG
|
||||
# define DEBUG
|
||||
# endif
|
||||
@@ -72,6 +72,8 @@ distribution.
|
||||
# else
|
||||
# define TINYXML2_LIB
|
||||
# endif
|
||||
#elif __GNUC__ >= 4
|
||||
# define TINYXML2_LIB __attribute__((visibility("default")))
|
||||
#else
|
||||
# define TINYXML2_LIB
|
||||
#endif
|
||||
@@ -96,9 +98,9 @@ distribution.
|
||||
/* Versioning, past 1.0.14:
|
||||
http://semver.org/
|
||||
*/
|
||||
static const int TIXML2_MAJOR_VERSION = 4;
|
||||
static const int TIXML2_MAJOR_VERSION = 5;
|
||||
static const int TIXML2_MINOR_VERSION = 0;
|
||||
static const int TIXML2_PATCH_VERSION = 0;
|
||||
static const int TIXML2_PATCH_VERSION = 1;
|
||||
|
||||
namespace tinyxml2
|
||||
{
|
||||
@@ -125,18 +127,20 @@ public:
|
||||
NEEDS_NEWLINE_NORMALIZATION = 0x02,
|
||||
NEEDS_WHITESPACE_COLLAPSING = 0x04,
|
||||
|
||||
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
|
||||
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
|
||||
TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
|
||||
ATTRIBUTE_NAME = 0,
|
||||
ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
|
||||
ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
|
||||
COMMENT = NEEDS_NEWLINE_NORMALIZATION
|
||||
ATTRIBUTE_NAME = 0,
|
||||
ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
|
||||
ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
|
||||
COMMENT = NEEDS_NEWLINE_NORMALIZATION
|
||||
};
|
||||
|
||||
StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
|
||||
~StrPair();
|
||||
|
||||
void Set( char* start, char* end, int flags ) {
|
||||
TIXMLASSERT( start );
|
||||
TIXMLASSERT( end );
|
||||
Reset();
|
||||
_start = start;
|
||||
_end = end;
|
||||
@@ -156,13 +160,13 @@ public:
|
||||
|
||||
void SetStr( const char* str, int flags=0 );
|
||||
|
||||
char* ParseText( char* in, const char* endTag, int strFlags );
|
||||
char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );
|
||||
char* ParseName( char* in );
|
||||
|
||||
void TransferTo( StrPair* other );
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
void CollapseWhitespace();
|
||||
|
||||
enum {
|
||||
@@ -207,7 +211,8 @@ public:
|
||||
void Push( T t ) {
|
||||
TIXMLASSERT( _size < INT_MAX );
|
||||
EnsureCapacity( _size+1 );
|
||||
_mem[_size++] = t;
|
||||
_mem[_size] = t;
|
||||
++_size;
|
||||
}
|
||||
|
||||
T* PushArr( int count ) {
|
||||
@@ -221,7 +226,8 @@ public:
|
||||
|
||||
T Pop() {
|
||||
TIXMLASSERT( _size > 0 );
|
||||
return _mem[--_size];
|
||||
--_size;
|
||||
return _mem[_size];
|
||||
}
|
||||
|
||||
void PopArr( int count ) {
|
||||
@@ -258,6 +264,13 @@ public:
|
||||
return _allocated;
|
||||
}
|
||||
|
||||
void SwapRemove(int i) {
|
||||
TIXMLASSERT(i >= 0 && i < _size);
|
||||
TIXMLASSERT(_size > 0);
|
||||
_mem[i] = _mem[_size - 1];
|
||||
--_size;
|
||||
}
|
||||
|
||||
const T* Mem() const {
|
||||
TIXMLASSERT( _mem );
|
||||
return _mem;
|
||||
@@ -278,6 +291,7 @@ private:
|
||||
TIXMLASSERT( cap <= INT_MAX / 2 );
|
||||
int newAllocated = cap * 2;
|
||||
T* newMem = new T[newAllocated];
|
||||
TIXMLASSERT( newAllocated >= _size );
|
||||
memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
|
||||
if ( _mem != _pool ) {
|
||||
delete [] _mem;
|
||||
@@ -315,7 +329,7 @@ public:
|
||||
/*
|
||||
Template child class to create pools of the correct type.
|
||||
*/
|
||||
template< int SIZE >
|
||||
template< int ITEM_SIZE >
|
||||
class MemPoolT : public MemPool
|
||||
{
|
||||
public:
|
||||
@@ -338,7 +352,7 @@ public:
|
||||
}
|
||||
|
||||
virtual int ItemSize() const {
|
||||
return SIZE;
|
||||
return ITEM_SIZE;
|
||||
}
|
||||
int CurrentAllocs() const {
|
||||
return _currentAllocs;
|
||||
@@ -350,21 +364,23 @@ public:
|
||||
Block* block = new Block();
|
||||
_blockPtrs.Push( block );
|
||||
|
||||
for( int i=0; i<COUNT-1; ++i ) {
|
||||
block->chunk[i].next = &block->chunk[i+1];
|
||||
Item* blockItems = block->items;
|
||||
for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
|
||||
blockItems[i].next = &(blockItems[i + 1]);
|
||||
}
|
||||
block->chunk[COUNT-1].next = 0;
|
||||
_root = block->chunk;
|
||||
blockItems[ITEMS_PER_BLOCK - 1].next = 0;
|
||||
_root = blockItems;
|
||||
}
|
||||
void* result = _root;
|
||||
Item* const result = _root;
|
||||
TIXMLASSERT( result != 0 );
|
||||
_root = _root->next;
|
||||
|
||||
++_currentAllocs;
|
||||
if ( _currentAllocs > _maxAllocs ) {
|
||||
_maxAllocs = _currentAllocs;
|
||||
}
|
||||
_nAllocs++;
|
||||
_nUntracked++;
|
||||
++_nAllocs;
|
||||
++_nUntracked;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -373,20 +389,21 @@ public:
|
||||
return;
|
||||
}
|
||||
--_currentAllocs;
|
||||
Chunk* chunk = static_cast<Chunk*>( mem );
|
||||
Item* item = static_cast<Item*>( mem );
|
||||
#ifdef DEBUG
|
||||
memset( chunk, 0xfe, sizeof(Chunk) );
|
||||
memset( item, 0xfe, sizeof( *item ) );
|
||||
#endif
|
||||
chunk->next = _root;
|
||||
_root = chunk;
|
||||
item->next = _root;
|
||||
_root = item;
|
||||
}
|
||||
void Trace( const char* name ) {
|
||||
printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
|
||||
name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() );
|
||||
name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,
|
||||
ITEM_SIZE, _nAllocs, _blockPtrs.Size() );
|
||||
}
|
||||
|
||||
void SetTracked() {
|
||||
_nUntracked--;
|
||||
--_nUntracked;
|
||||
}
|
||||
|
||||
int Untracked() const {
|
||||
@@ -402,21 +419,23 @@ public:
|
||||
// 16k: 5200
|
||||
// 32k: 4300
|
||||
// 64k: 4000 21000
|
||||
enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private
|
||||
// Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
|
||||
// in private part if ITEMS_PER_BLOCK is private
|
||||
enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };
|
||||
|
||||
private:
|
||||
MemPoolT( const MemPoolT& ); // not supported
|
||||
void operator=( const MemPoolT& ); // not supported
|
||||
|
||||
union Chunk {
|
||||
Chunk* next;
|
||||
char mem[SIZE];
|
||||
union Item {
|
||||
Item* next;
|
||||
char itemData[ITEM_SIZE];
|
||||
};
|
||||
struct Block {
|
||||
Chunk chunk[COUNT];
|
||||
Item items[ITEMS_PER_BLOCK];
|
||||
};
|
||||
DynArray< Block*, 10 > _blockPtrs;
|
||||
Chunk* _root;
|
||||
Item* _root;
|
||||
|
||||
int _currentAllocs;
|
||||
int _nAllocs;
|
||||
@@ -494,10 +513,10 @@ enum XMLError {
|
||||
XML_ERROR_FILE_NOT_FOUND,
|
||||
XML_ERROR_FILE_COULD_NOT_BE_OPENED,
|
||||
XML_ERROR_FILE_READ_ERROR,
|
||||
XML_ERROR_ELEMENT_MISMATCH,
|
||||
UNUSED_XML_ERROR_ELEMENT_MISMATCH, // remove at next major version
|
||||
XML_ERROR_PARSING_ELEMENT,
|
||||
XML_ERROR_PARSING_ATTRIBUTE,
|
||||
XML_ERROR_IDENTIFYING_TAG,
|
||||
UNUSED_XML_ERROR_IDENTIFYING_TAG, // remove at next major version
|
||||
XML_ERROR_PARSING_TEXT,
|
||||
XML_ERROR_PARSING_CDATA,
|
||||
XML_ERROR_PARSING_COMMENT,
|
||||
@@ -516,19 +535,23 @@ enum XMLError {
|
||||
/*
|
||||
Utility functionality.
|
||||
*/
|
||||
class XMLUtil
|
||||
class TINYXML2_LIB XMLUtil
|
||||
{
|
||||
public:
|
||||
static const char* SkipWhiteSpace( const char* p ) {
|
||||
static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) {
|
||||
TIXMLASSERT( p );
|
||||
|
||||
while( IsWhiteSpace(*p) ) {
|
||||
if (curLineNumPtr && *p == '\n') {
|
||||
++(*curLineNumPtr);
|
||||
}
|
||||
++p;
|
||||
}
|
||||
TIXMLASSERT( p );
|
||||
return p;
|
||||
}
|
||||
static char* SkipWhiteSpace( char* p ) {
|
||||
return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p) ) );
|
||||
static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) {
|
||||
return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );
|
||||
}
|
||||
|
||||
// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
|
||||
@@ -559,6 +582,9 @@ public:
|
||||
if ( p == q ) {
|
||||
return true;
|
||||
}
|
||||
TIXMLASSERT( p );
|
||||
TIXMLASSERT( q );
|
||||
TIXMLASSERT( nChar >= 0 );
|
||||
return strncmp( p, q, nChar ) == 0;
|
||||
}
|
||||
|
||||
@@ -587,6 +613,17 @@ public:
|
||||
static bool ToFloat( const char* str, float* value );
|
||||
static bool ToDouble( const char* str, double* value );
|
||||
static bool ToInt64(const char* str, int64_t* value);
|
||||
|
||||
// Changes what is serialized for a boolean value.
|
||||
// Default to "true" and "false". Shouldn't be changed
|
||||
// unless you have a special testing or compatibility need.
|
||||
// Be careful: static, global, & not thread safe.
|
||||
// Be sure to set static const memory as parameters.
|
||||
static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
|
||||
|
||||
private:
|
||||
static const char* writeBoolTrue;
|
||||
static const char* writeBoolFalse;
|
||||
};
|
||||
|
||||
|
||||
@@ -692,6 +729,9 @@ public:
|
||||
*/
|
||||
void SetValue( const char* val, bool staticMem=false );
|
||||
|
||||
/// Gets the line number the node is in, if the document was parsed from a file.
|
||||
int GetLineNum() const { return _parseLineNum; }
|
||||
|
||||
/// Get the parent of this node on the DOM.
|
||||
const XMLNode* Parent() const {
|
||||
return _parent;
|
||||
@@ -825,6 +865,21 @@ public:
|
||||
*/
|
||||
virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
|
||||
|
||||
/**
|
||||
Make a copy of this node and all its children.
|
||||
|
||||
If the 'target' is null, then the nodes will
|
||||
be allocated in the current document. If 'target'
|
||||
is specified, the memory will be allocated is the
|
||||
specified XMLDocument.
|
||||
|
||||
NOTE: This is probably not the correct tool to
|
||||
copy a document, since XMLDocuments can have multiple
|
||||
top level XMLNodes. You probably want to use
|
||||
XMLDocument::DeepCopy()
|
||||
*/
|
||||
XMLNode* DeepClone( XMLDocument* target ) const;
|
||||
|
||||
/**
|
||||
Test if 2 nodes are the same, but don't test children.
|
||||
The 2 nodes do not need to be in the same Document.
|
||||
@@ -875,11 +930,12 @@ protected:
|
||||
XMLNode( XMLDocument* );
|
||||
virtual ~XMLNode();
|
||||
|
||||
virtual char* ParseDeep( char*, StrPair* );
|
||||
virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
|
||||
|
||||
XMLDocument* _document;
|
||||
XMLNode* _parent;
|
||||
mutable StrPair _value;
|
||||
int _parseLineNum;
|
||||
|
||||
XMLNode* _firstChild;
|
||||
XMLNode* _lastChild;
|
||||
@@ -894,6 +950,7 @@ private:
|
||||
void Unlink( XMLNode* child );
|
||||
static void DeleteNode( XMLNode* node );
|
||||
void InsertChildPreamble( XMLNode* insertThis ) const;
|
||||
const XMLElement* ToElementWithName( const char* name ) const;
|
||||
|
||||
XMLNode( const XMLNode& ); // not supported
|
||||
XMLNode& operator=( const XMLNode& ); // not supported
|
||||
@@ -941,7 +998,7 @@ protected:
|
||||
XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
|
||||
virtual ~XMLText() {}
|
||||
|
||||
char* ParseDeep( char*, StrPair* endTag );
|
||||
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
|
||||
|
||||
private:
|
||||
bool _isCData;
|
||||
@@ -972,7 +1029,7 @@ protected:
|
||||
XMLComment( XMLDocument* doc );
|
||||
virtual ~XMLComment();
|
||||
|
||||
char* ParseDeep( char*, StrPair* endTag );
|
||||
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
|
||||
|
||||
private:
|
||||
XMLComment( const XMLComment& ); // not supported
|
||||
@@ -1011,7 +1068,7 @@ protected:
|
||||
XMLDeclaration( XMLDocument* doc );
|
||||
virtual ~XMLDeclaration();
|
||||
|
||||
char* ParseDeep( char*, StrPair* endTag );
|
||||
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
|
||||
|
||||
private:
|
||||
XMLDeclaration( const XMLDeclaration& ); // not supported
|
||||
@@ -1046,7 +1103,7 @@ protected:
|
||||
XMLUnknown( XMLDocument* doc );
|
||||
virtual ~XMLUnknown();
|
||||
|
||||
char* ParseDeep( char*, StrPair* endTag );
|
||||
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
|
||||
|
||||
private:
|
||||
XMLUnknown( const XMLUnknown& ); // not supported
|
||||
@@ -1071,6 +1128,9 @@ public:
|
||||
/// The value of the attribute.
|
||||
const char* Value() const;
|
||||
|
||||
/// Gets the line number the attribute is in, if the document was parsed from a file.
|
||||
int GetLineNum() const { return _parseLineNum; }
|
||||
|
||||
/// The next attribute in the list.
|
||||
const XMLAttribute* Next() const {
|
||||
return _next;
|
||||
@@ -1118,7 +1178,7 @@ public:
|
||||
}
|
||||
|
||||
/** QueryIntValue interprets the attribute as an integer, and returns the value
|
||||
in the provided parameter. The function will return XML_NO_ERROR on success,
|
||||
in the provided parameter. The function will return XML_SUCCESS on success,
|
||||
and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
|
||||
*/
|
||||
XMLError QueryIntValue( int* value ) const;
|
||||
@@ -1151,17 +1211,18 @@ public:
|
||||
private:
|
||||
enum { BUF_SIZE = 200 };
|
||||
|
||||
XMLAttribute() : _next( 0 ), _memPool( 0 ) {}
|
||||
XMLAttribute() : _parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
|
||||
virtual ~XMLAttribute() {}
|
||||
|
||||
XMLAttribute( const XMLAttribute& ); // not supported
|
||||
void operator=( const XMLAttribute& ); // not supported
|
||||
void SetName( const char* name );
|
||||
|
||||
char* ParseDeep( char* p, bool processEntities );
|
||||
char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );
|
||||
|
||||
mutable StrPair _name;
|
||||
mutable StrPair _value;
|
||||
int _parseLineNum;
|
||||
XMLAttribute* _next;
|
||||
MemPool* _memPool;
|
||||
};
|
||||
@@ -1218,51 +1279,25 @@ public:
|
||||
const char* Attribute( const char* name, const char* value=0 ) const;
|
||||
|
||||
/** Given an attribute name, IntAttribute() returns the value
|
||||
of the attribute interpreted as an integer. 0 will be
|
||||
returned if there is an error. For a method with error
|
||||
checking, see QueryIntAttribute()
|
||||
of the attribute interpreted as an integer. The default
|
||||
value will be returned if the attribute isn't present,
|
||||
or if there is an error. (For a method with error
|
||||
checking, see QueryIntAttribute()).
|
||||
*/
|
||||
int IntAttribute( const char* name ) const {
|
||||
int i=0;
|
||||
QueryIntAttribute( name, &i );
|
||||
return i;
|
||||
}
|
||||
|
||||
int IntAttribute(const char* name, int defaultValue = 0) const;
|
||||
/// See IntAttribute()
|
||||
unsigned UnsignedAttribute( const char* name ) const {
|
||||
unsigned i=0;
|
||||
QueryUnsignedAttribute( name, &i );
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
|
||||
/// See IntAttribute()
|
||||
int64_t Int64Attribute(const char* name) const {
|
||||
int64_t i = 0;
|
||||
QueryInt64Attribute(name, &i);
|
||||
return i;
|
||||
}
|
||||
|
||||
int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
|
||||
/// See IntAttribute()
|
||||
bool BoolAttribute( const char* name ) const {
|
||||
bool b=false;
|
||||
QueryBoolAttribute( name, &b );
|
||||
return b;
|
||||
}
|
||||
bool BoolAttribute(const char* name, bool defaultValue = false) const;
|
||||
/// See IntAttribute()
|
||||
double DoubleAttribute( const char* name ) const {
|
||||
double d=0;
|
||||
QueryDoubleAttribute( name, &d );
|
||||
return d;
|
||||
}
|
||||
double DoubleAttribute(const char* name, double defaultValue = 0) const;
|
||||
/// See IntAttribute()
|
||||
float FloatAttribute( const char* name ) const {
|
||||
float f=0;
|
||||
QueryFloatAttribute( name, &f );
|
||||
return f;
|
||||
}
|
||||
float FloatAttribute(const char* name, float defaultValue = 0) const;
|
||||
|
||||
/** Given an attribute name, QueryIntAttribute() returns
|
||||
XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
|
||||
XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
|
||||
can't be performed, or XML_NO_ATTRIBUTE if the attribute
|
||||
doesn't exist. If successful, the result of the conversion
|
||||
will be written to 'value'. If not successful, nothing will
|
||||
@@ -1327,7 +1362,7 @@ public:
|
||||
|
||||
|
||||
/** Given an attribute name, QueryAttribute() returns
|
||||
XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
|
||||
XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
|
||||
can't be performed, or XML_NO_ATTRIBUTE if the attribute
|
||||
doesn't exist. It is overloaded for the primitive types,
|
||||
and is a generally more convenient replacement of
|
||||
@@ -1533,20 +1568,33 @@ public:
|
||||
/// See QueryIntText()
|
||||
XMLError QueryFloatText( float* fval ) const;
|
||||
|
||||
int IntText(int defaultValue = 0) const;
|
||||
|
||||
/// See QueryIntText()
|
||||
unsigned UnsignedText(unsigned defaultValue = 0) const;
|
||||
/// See QueryIntText()
|
||||
int64_t Int64Text(int64_t defaultValue = 0) const;
|
||||
/// See QueryIntText()
|
||||
bool BoolText(bool defaultValue = false) const;
|
||||
/// See QueryIntText()
|
||||
double DoubleText(double defaultValue = 0) const;
|
||||
/// See QueryIntText()
|
||||
float FloatText(float defaultValue = 0) const;
|
||||
|
||||
// internal:
|
||||
enum {
|
||||
enum ElementClosingType {
|
||||
OPEN, // <foo>
|
||||
CLOSED, // <foo/>
|
||||
CLOSING // </foo>
|
||||
};
|
||||
int ClosingType() const {
|
||||
ElementClosingType ClosingType() const {
|
||||
return _closingType;
|
||||
}
|
||||
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
|
||||
virtual bool ShallowEqual( const XMLNode* compare ) const;
|
||||
|
||||
protected:
|
||||
char* ParseDeep( char* p, StrPair* endTag );
|
||||
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
|
||||
|
||||
private:
|
||||
XMLElement( XMLDocument* doc );
|
||||
@@ -1559,11 +1607,12 @@ private:
|
||||
}
|
||||
XMLAttribute* FindOrCreateAttribute( const char* name );
|
||||
//void LinkAttribute( XMLAttribute* attrib );
|
||||
char* ParseAttributes( char* p );
|
||||
char* ParseAttributes( char* p, int* curLineNumPtr );
|
||||
static void DeleteAttribute( XMLAttribute* attribute );
|
||||
XMLAttribute* CreateAttribute();
|
||||
|
||||
enum { BUF_SIZE = 200 };
|
||||
int _closingType;
|
||||
ElementClosingType _closingType;
|
||||
// The attribute list is ordered; there is no 'lastAttribute'
|
||||
// because the list needs to be scanned for dupes before adding
|
||||
// a new attribute.
|
||||
@@ -1587,7 +1636,7 @@ class TINYXML2_LIB XMLDocument : public XMLNode
|
||||
friend class XMLElement;
|
||||
public:
|
||||
/// constructor
|
||||
XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE );
|
||||
XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );
|
||||
~XMLDocument();
|
||||
|
||||
virtual XMLDocument* ToDocument() {
|
||||
@@ -1601,7 +1650,7 @@ public:
|
||||
|
||||
/**
|
||||
Parse an XML file from a character string.
|
||||
Returns XML_NO_ERROR (0) on success, or
|
||||
Returns XML_SUCCESS (0) on success, or
|
||||
an errorID.
|
||||
|
||||
You may optionally pass in the 'nBytes', which is
|
||||
@@ -1613,7 +1662,7 @@ public:
|
||||
|
||||
/**
|
||||
Load an XML file from disk.
|
||||
Returns XML_NO_ERROR (0) on success, or
|
||||
Returns XML_SUCCESS (0) on success, or
|
||||
an errorID.
|
||||
*/
|
||||
XMLError LoadFile( const char* filename );
|
||||
@@ -1626,14 +1675,14 @@ public:
|
||||
not text in order for TinyXML-2 to correctly
|
||||
do newline normalization.
|
||||
|
||||
Returns XML_NO_ERROR (0) on success, or
|
||||
Returns XML_SUCCESS (0) on success, or
|
||||
an errorID.
|
||||
*/
|
||||
XMLError LoadFile( FILE* );
|
||||
|
||||
/**
|
||||
Save the XML file to disk.
|
||||
Returns XML_NO_ERROR (0) on success, or
|
||||
Returns XML_SUCCESS (0) on success, or
|
||||
an errorID.
|
||||
*/
|
||||
XMLError SaveFile( const char* filename, bool compact = false );
|
||||
@@ -1642,7 +1691,7 @@ public:
|
||||
Save the XML file to disk. You are responsible
|
||||
for providing and closing the FILE*.
|
||||
|
||||
Returns XML_NO_ERROR (0) on success, or
|
||||
Returns XML_SUCCESS (0) on success, or
|
||||
an errorID.
|
||||
*/
|
||||
XMLError SaveFile( FILE* fp, bool compact = false );
|
||||
@@ -1651,7 +1700,7 @@ public:
|
||||
return _processEntities;
|
||||
}
|
||||
Whitespace WhitespaceMode() const {
|
||||
return _whitespace;
|
||||
return _whitespaceMode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1736,7 +1785,11 @@ public:
|
||||
*/
|
||||
void DeleteNode( XMLNode* node );
|
||||
|
||||
void SetError( XMLError error, const char* str1, const char* str2 );
|
||||
void SetError( XMLError error, const char* str1, const char* str2, int lineNum );
|
||||
|
||||
void ClearError() {
|
||||
SetError(XML_SUCCESS, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// Return true if there was an error parsing the document.
|
||||
bool Error() const {
|
||||
@@ -1747,14 +1800,18 @@ public:
|
||||
return _errorID;
|
||||
}
|
||||
const char* ErrorName() const;
|
||||
static const char* ErrorIDToName(XMLError errorID);
|
||||
|
||||
/// Return a possibly helpful diagnostic location or string.
|
||||
const char* GetErrorStr1() const {
|
||||
return _errorStr1;
|
||||
}
|
||||
const char* GetErrorStr1() const;
|
||||
|
||||
/// Return a possibly helpful secondary diagnostic location or string.
|
||||
const char* GetErrorStr2() const {
|
||||
return _errorStr2;
|
||||
const char* GetErrorStr2() const;
|
||||
|
||||
/// Return the line where the error occured, or zero if unknown.
|
||||
int GetErrorLineNum() const
|
||||
{
|
||||
return _errorLineNum;
|
||||
}
|
||||
/// If there is an error, print it to stdout.
|
||||
void PrintError() const;
|
||||
@@ -1762,9 +1819,21 @@ public:
|
||||
/// Clear the document, resetting it to the initial state.
|
||||
void Clear();
|
||||
|
||||
// internal
|
||||
/**
|
||||
Copies this document to a target document.
|
||||
The target will be completely cleared before the copy.
|
||||
If you want to copy a sub-tree, see XMLNode::DeepClone().
|
||||
|
||||
NOTE: that the 'target' must be non-null.
|
||||
*/
|
||||
void DeepCopy(XMLDocument* target);
|
||||
|
||||
// internal
|
||||
char* Identify( char* p, XMLNode** node );
|
||||
|
||||
// internal
|
||||
void MarkInUse(XMLNode*);
|
||||
|
||||
virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
|
||||
return 0;
|
||||
}
|
||||
@@ -1776,13 +1845,22 @@ private:
|
||||
XMLDocument( const XMLDocument& ); // not supported
|
||||
void operator=( const XMLDocument& ); // not supported
|
||||
|
||||
bool _writeBOM;
|
||||
bool _processEntities;
|
||||
XMLError _errorID;
|
||||
Whitespace _whitespace;
|
||||
const char* _errorStr1;
|
||||
const char* _errorStr2;
|
||||
char* _charBuffer;
|
||||
bool _writeBOM;
|
||||
bool _processEntities;
|
||||
XMLError _errorID;
|
||||
Whitespace _whitespaceMode;
|
||||
mutable StrPair _errorStr1;
|
||||
mutable StrPair _errorStr2;
|
||||
int _errorLineNum;
|
||||
char* _charBuffer;
|
||||
int _parseCurLineNum;
|
||||
// Memory tracking does add some overhead.
|
||||
// However, the code assumes that you don't
|
||||
// have a bunch of unlinked nodes around.
|
||||
// Therefore it takes less memory to track
|
||||
// in the document vs. a linked list in the XMLNode,
|
||||
// and the performance is the same.
|
||||
DynArray<XMLNode*, 10> _unlinked;
|
||||
|
||||
MemPoolT< sizeof(XMLElement) > _elementPool;
|
||||
MemPoolT< sizeof(XMLAttribute) > _attributePool;
|
||||
@@ -1792,8 +1870,23 @@ private:
|
||||
static const char* _errorNames[XML_ERROR_COUNT];
|
||||
|
||||
void Parse();
|
||||
|
||||
template<class NodeType, int PoolElementSize>
|
||||
NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
|
||||
};
|
||||
|
||||
template<class NodeType, int PoolElementSize>
|
||||
inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
|
||||
{
|
||||
TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );
|
||||
TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );
|
||||
NodeType* returnNode = new (pool.Alloc()) NodeType( this );
|
||||
TIXMLASSERT( returnNode );
|
||||
returnNode->_memPool = &pool;
|
||||
|
||||
_unlinked.Push(returnNode);
|
||||
return returnNode;
|
||||
}
|
||||
|
||||
/**
|
||||
A XMLHandle is a class that wraps a node pointer with null checks; this is
|
||||
@@ -1910,19 +2003,19 @@ public:
|
||||
}
|
||||
/// Safe cast to XMLElement. This can return null.
|
||||
XMLElement* ToElement() {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToElement() );
|
||||
return ( _node ? _node->ToElement() : 0 );
|
||||
}
|
||||
/// Safe cast to XMLText. This can return null.
|
||||
XMLText* ToText() {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToText() );
|
||||
return ( _node ? _node->ToText() : 0 );
|
||||
}
|
||||
/// Safe cast to XMLUnknown. This can return null.
|
||||
XMLUnknown* ToUnknown() {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToUnknown() );
|
||||
return ( _node ? _node->ToUnknown() : 0 );
|
||||
}
|
||||
/// Safe cast to XMLDeclaration. This can return null.
|
||||
XMLDeclaration* ToDeclaration() {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() );
|
||||
return ( _node ? _node->ToDeclaration() : 0 );
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1982,16 +2075,16 @@ public:
|
||||
return _node;
|
||||
}
|
||||
const XMLElement* ToElement() const {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToElement() );
|
||||
return ( _node ? _node->ToElement() : 0 );
|
||||
}
|
||||
const XMLText* ToText() const {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToText() );
|
||||
return ( _node ? _node->ToText() : 0 );
|
||||
}
|
||||
const XMLUnknown* ToUnknown() const {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToUnknown() );
|
||||
return ( _node ? _node->ToUnknown() : 0 );
|
||||
}
|
||||
const XMLDeclaration* ToDeclaration() const {
|
||||
return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() );
|
||||
return ( _node ? _node->ToDeclaration() : 0 );
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -2125,6 +2218,7 @@ public:
|
||||
void ClearBuffer() {
|
||||
_buffer.Clear();
|
||||
_buffer.Push(0);
|
||||
_firstElement = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -136,47 +136,47 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'">
|
||||
<IntDir>$(SolutionDir)$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">
|
||||
<IntDir>$(SolutionDir)$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'">
|
||||
<IntDir>$(SolutionDir)$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'">
|
||||
<IntDir>$(SolutionDir)$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'">
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'">
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'">
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'">
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'">
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'">
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'">
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'">
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">
|
||||
<ClCompile>
|
||||
|
||||
@@ -141,35 +141,43 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)bin\$(ProjectName)\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)temp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'">
|
||||
<ClCompile>
|
||||
|
||||
484
xmltest.cpp
484
xmltest.cpp
@@ -10,16 +10,11 @@
|
||||
#include <ctime>
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
#include <direct.h> // _mkdir
|
||||
#include <crtdbg.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
_CrtMemState startMemState;
|
||||
_CrtMemState endMemState;
|
||||
#elif defined(MINGW32) || defined(__MINGW32__)
|
||||
#include <io.h> // mkdir
|
||||
#else
|
||||
#include <sys/stat.h> // mkdir
|
||||
#endif
|
||||
|
||||
using namespace tinyxml2;
|
||||
@@ -63,6 +58,15 @@ bool XMLTest (const char* testString, const char* expected, const char* found, b
|
||||
return pass;
|
||||
}
|
||||
|
||||
bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
|
||||
{
|
||||
return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
|
||||
}
|
||||
|
||||
bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
|
||||
{
|
||||
return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
|
||||
}
|
||||
|
||||
template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
|
||||
{
|
||||
@@ -288,17 +292,10 @@ int main( int argc, const char ** argv )
|
||||
_CrtMemCheckpoint( &startMemState );
|
||||
// Enable MS Visual C++ debug heap memory leaks dump on exit
|
||||
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__)
|
||||
#if defined __MINGW64_VERSION_MAJOR && defined __MINGW64_VERSION_MINOR
|
||||
//MINGW64: both 32 and 64-bit
|
||||
mkdir( "resources/out/" );
|
||||
#else
|
||||
_mkdir( "resources/out/" );
|
||||
#endif
|
||||
#else
|
||||
mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
{
|
||||
int leaksOnStart = _CrtDumpMemoryLeaks();
|
||||
XMLTest( "No leaks on start?", FALSE, leaksOnStart );
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
@@ -426,7 +423,7 @@ int main( int argc, const char ** argv )
|
||||
XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
|
||||
XMLTest( "Programmatic DOM", "& Text!",
|
||||
doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
|
||||
XMLTest("User data", 2, (int)comment->GetUserData());
|
||||
XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
|
||||
|
||||
// And now deletion:
|
||||
element->DeleteChild( sub[2] );
|
||||
@@ -436,10 +433,12 @@ int main( int argc, const char ** argv )
|
||||
element->LastChildElement()->DeleteAttribute( "attrib" );
|
||||
|
||||
XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
|
||||
int value = 10;
|
||||
int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );
|
||||
XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
|
||||
XMLTest( "Programmatic DOM", value, 10 );
|
||||
int value1 = 10;
|
||||
int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
|
||||
XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
|
||||
XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
|
||||
XMLTest( "Programmatic DOM", 10, value1 );
|
||||
XMLTest( "Programmatic DOM", 10, value2 );
|
||||
|
||||
doc->Print();
|
||||
|
||||
@@ -451,7 +450,7 @@ int main( int argc, const char ** argv )
|
||||
{
|
||||
XMLPrinter streamer( 0, true );
|
||||
doc->Print( &streamer );
|
||||
XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );
|
||||
XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
|
||||
}
|
||||
doc->SaveFile( "./resources/out/pretty.xml" );
|
||||
doc->SaveFile( "./resources/out/compact.xml", true );
|
||||
@@ -500,7 +499,7 @@ int main( int argc, const char ** argv )
|
||||
|
||||
XMLDocument doc;
|
||||
doc.Parse( error );
|
||||
XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
|
||||
XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
|
||||
}
|
||||
|
||||
{
|
||||
@@ -511,22 +510,31 @@ int main( int argc, const char ** argv )
|
||||
|
||||
XMLElement* ele = doc.FirstChildElement();
|
||||
|
||||
int iVal, result;
|
||||
int iVal;
|
||||
XMLError result;
|
||||
double dVal;
|
||||
|
||||
result = ele->QueryDoubleAttribute( "attr0", &dVal );
|
||||
XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);
|
||||
XMLTest( "Query attribute: int as double", (int)dVal, 1 );
|
||||
XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
|
||||
XMLTest( "Query attribute: int as double", 1, (int)dVal );
|
||||
XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
|
||||
|
||||
result = ele->QueryDoubleAttribute( "attr1", &dVal );
|
||||
XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);
|
||||
XMLTest( "Query attribute: double as double", (int)dVal, 2 );
|
||||
XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
|
||||
XMLTest( "Query attribute: double as double", 2.0, dVal );
|
||||
XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
|
||||
|
||||
result = ele->QueryIntAttribute( "attr1", &iVal );
|
||||
XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);
|
||||
XMLTest( "Query attribute: double as int", iVal, 2 );
|
||||
XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
|
||||
XMLTest( "Query attribute: double as int", 2, iVal );
|
||||
|
||||
result = ele->QueryIntAttribute( "attr2", &iVal );
|
||||
XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
|
||||
XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
|
||||
XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
|
||||
|
||||
result = ele->QueryIntAttribute( "bar", &iVal );
|
||||
XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
|
||||
XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
|
||||
XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
|
||||
}
|
||||
|
||||
{
|
||||
@@ -551,12 +559,14 @@ int main( int argc, const char ** argv )
|
||||
ele->QueryAttribute( "int", &iVal2 );
|
||||
ele->QueryAttribute( "double", &dVal2 );
|
||||
|
||||
XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
|
||||
XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
|
||||
XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
|
||||
XMLTest( "Attribute round trip. int.", 1, iVal );
|
||||
XMLTest( "Attribute round trip. double.", -1, (int)dVal );
|
||||
XMLTest( "Alternate query", true, iVal == iVal2 );
|
||||
XMLTest( "Alternate query", true, dVal == dVal2 );
|
||||
XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
|
||||
XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
|
||||
}
|
||||
|
||||
{
|
||||
@@ -679,7 +689,7 @@ int main( int argc, const char ** argv )
|
||||
XMLTest( "SetText types", "1", element->GetText() );
|
||||
|
||||
element->SetText( true );
|
||||
XMLTest( "SetText types", "1", element->GetText() ); // TODO: should be 'true'?
|
||||
XMLTest( "SetText types", "true", element->GetText() );
|
||||
|
||||
element->SetText( 1.5f );
|
||||
XMLTest( "SetText types", "1.5", element->GetText() );
|
||||
@@ -702,6 +712,7 @@ int main( int argc, const char ** argv )
|
||||
XMLTest("Attribute: int", -100, v, true);
|
||||
element->QueryAttribute("attrib", &v);
|
||||
XMLTest("Attribute: int", -100, v, true);
|
||||
XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
|
||||
}
|
||||
{
|
||||
element->SetAttribute("attrib", unsigned(100));
|
||||
@@ -710,6 +721,7 @@ int main( int argc, const char ** argv )
|
||||
XMLTest("Attribute: unsigned", unsigned(100), v, true);
|
||||
element->QueryAttribute("attrib", &v);
|
||||
XMLTest("Attribute: unsigned", unsigned(100), v, true);
|
||||
XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
|
||||
}
|
||||
{
|
||||
element->SetAttribute("attrib", BIG);
|
||||
@@ -718,6 +730,7 @@ int main( int argc, const char ** argv )
|
||||
XMLTest("Attribute: int64_t", BIG, v, true);
|
||||
element->QueryAttribute("attrib", &v);
|
||||
XMLTest("Attribute: int64_t", BIG, v, true);
|
||||
XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
|
||||
}
|
||||
{
|
||||
element->SetAttribute("attrib", true);
|
||||
@@ -726,6 +739,19 @@ int main( int argc, const char ** argv )
|
||||
XMLTest("Attribute: bool", true, v, true);
|
||||
element->QueryAttribute("attrib", &v);
|
||||
XMLTest("Attribute: bool", true, v, true);
|
||||
XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
|
||||
}
|
||||
{
|
||||
element->SetAttribute("attrib", true);
|
||||
const char* result = element->Attribute("attrib");
|
||||
XMLTest("Bool true is 'true'", "true", result);
|
||||
|
||||
XMLUtil::SetBoolSerialization("1", "0");
|
||||
element->SetAttribute("attrib", true);
|
||||
result = element->Attribute("attrib");
|
||||
XMLTest("Bool true is '1'", "1", result);
|
||||
|
||||
XMLUtil::SetBoolSerialization(0, 0);
|
||||
}
|
||||
{
|
||||
element->SetAttribute("attrib", 100.0);
|
||||
@@ -734,6 +760,7 @@ int main( int argc, const char ** argv )
|
||||
XMLTest("Attribute: double", 100.0, v, true);
|
||||
element->QueryAttribute("attrib", &v);
|
||||
XMLTest("Attribute: double", 100.0, v, true);
|
||||
XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
|
||||
}
|
||||
{
|
||||
element->SetAttribute("attrib", 100.0f);
|
||||
@@ -742,6 +769,7 @@ int main( int argc, const char ** argv )
|
||||
XMLTest("Attribute: float", 100.0f, v, true);
|
||||
element->QueryAttribute("attrib", &v);
|
||||
XMLTest("Attribute: float", 100.0f, v, true);
|
||||
XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
|
||||
}
|
||||
{
|
||||
element->SetText(BIG);
|
||||
@@ -769,7 +797,7 @@ int main( int argc, const char ** argv )
|
||||
{
|
||||
XMLDocument doc;
|
||||
doc.LoadFile("resources/printer.xml");
|
||||
XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
|
||||
XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
|
||||
|
||||
const XMLDocument& cdoc = doc;
|
||||
|
||||
@@ -802,8 +830,8 @@ int main( int argc, const char ** argv )
|
||||
doc.Parse( str );
|
||||
doc.Print();
|
||||
|
||||
XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
|
||||
"I am > the rules!\n...since I make symbolic puns",
|
||||
XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
|
||||
doc.FirstChildElement()->FirstChild()->Value(),
|
||||
false );
|
||||
}
|
||||
|
||||
@@ -819,8 +847,9 @@ int main( int argc, const char ** argv )
|
||||
doc.Parse( str );
|
||||
doc.Print();
|
||||
|
||||
XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
|
||||
XMLTest( "CDATA parse. [ tixml1:1480107 ]",
|
||||
"<b>I am > the rules!</b>\n...since I make symbolic puns",
|
||||
doc.FirstChildElement()->FirstChild()->Value(),
|
||||
false );
|
||||
}
|
||||
|
||||
@@ -837,7 +866,7 @@ int main( int argc, const char ** argv )
|
||||
XMLNode* childNode0 = parent->InsertEndChild( childText0 );
|
||||
XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
|
||||
|
||||
XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
|
||||
XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
|
||||
}
|
||||
|
||||
{
|
||||
@@ -892,10 +921,11 @@ int main( int argc, const char ** argv )
|
||||
XMLDocument doc( false );
|
||||
doc.Parse( passages );
|
||||
|
||||
XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
|
||||
"Line 5 has "quotation marks" and 'apostrophe marks'." );
|
||||
XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
|
||||
"Crazy &ttk;" );
|
||||
XMLTest( "No entity parsing.",
|
||||
"Line 5 has "quotation marks" and 'apostrophe marks'.",
|
||||
doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
|
||||
XMLTest( "No entity parsing.", "Crazy &ttk;",
|
||||
doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
|
||||
doc.Print();
|
||||
}
|
||||
|
||||
@@ -904,9 +934,9 @@ int main( int argc, const char ** argv )
|
||||
|
||||
XMLDocument doc;
|
||||
doc.Parse( test );
|
||||
XMLTest( "dot in names", doc.Error(), false );
|
||||
XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
|
||||
XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
|
||||
XMLTest( "dot in names", false, doc.Error() );
|
||||
XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
|
||||
XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
|
||||
}
|
||||
|
||||
{
|
||||
@@ -917,7 +947,7 @@ int main( int argc, const char ** argv )
|
||||
|
||||
XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
|
||||
XMLTest( "Entity with one digit.",
|
||||
text->Value(), "1.1 Start easy ignore fin thickness\n",
|
||||
"1.1 Start easy ignore fin thickness\n", text->Value(),
|
||||
false );
|
||||
}
|
||||
|
||||
@@ -995,7 +1025,7 @@ int main( int argc, const char ** argv )
|
||||
XMLDocument doc;
|
||||
doc.Parse( "<test></test>" );
|
||||
const char result[] = { 0x0e, 0 };
|
||||
XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
|
||||
XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
|
||||
doc.Print();
|
||||
}
|
||||
|
||||
@@ -1003,18 +1033,18 @@ int main( int argc, const char ** argv )
|
||||
// Attribute values with trailing quotes not handled correctly
|
||||
XMLDocument doc;
|
||||
doc.Parse( "<foo attribute=bar\" />" );
|
||||
XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
|
||||
XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
|
||||
}
|
||||
|
||||
{
|
||||
// [ 1663758 ] Failure to report error on bad XML
|
||||
XMLDocument xml;
|
||||
xml.Parse("<x>");
|
||||
XMLTest("Missing end tag at end of input", xml.Error(), true);
|
||||
XMLTest("Missing end tag at end of input", true, xml.Error());
|
||||
xml.Parse("<x> ");
|
||||
XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
|
||||
XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
|
||||
xml.Parse("<x></y>");
|
||||
XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
|
||||
XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
|
||||
}
|
||||
|
||||
|
||||
@@ -1104,6 +1134,86 @@ int main( int argc, const char ** argv )
|
||||
}
|
||||
|
||||
{
|
||||
// Deep Cloning of root element.
|
||||
XMLDocument doc2;
|
||||
XMLPrinter printer1;
|
||||
{
|
||||
// Make sure doc1 is deleted before we test doc2
|
||||
const char* xml =
|
||||
"<root>"
|
||||
" <child1 foo='bar'/>"
|
||||
" <!-- comment thing -->"
|
||||
" <child2 val='1'>Text</child2>"
|
||||
"</root>";
|
||||
XMLDocument doc;
|
||||
doc.Parse(xml);
|
||||
|
||||
doc.Print(&printer1);
|
||||
XMLNode* root = doc.RootElement()->DeepClone(&doc2);
|
||||
doc2.InsertFirstChild(root);
|
||||
}
|
||||
XMLPrinter printer2;
|
||||
doc2.Print(&printer2);
|
||||
|
||||
XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
|
||||
}
|
||||
|
||||
{
|
||||
// Deep Cloning of sub element.
|
||||
XMLDocument doc2;
|
||||
XMLPrinter printer1;
|
||||
{
|
||||
// Make sure doc1 is deleted before we test doc2
|
||||
const char* xml =
|
||||
"<?xml version ='1.0'?>"
|
||||
"<root>"
|
||||
" <child1 foo='bar'/>"
|
||||
" <!-- comment thing -->"
|
||||
" <child2 val='1'>Text</child2>"
|
||||
"</root>";
|
||||
XMLDocument doc;
|
||||
doc.Parse(xml);
|
||||
|
||||
const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
|
||||
subElement->Accept(&printer1);
|
||||
|
||||
XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
|
||||
doc2.InsertFirstChild(clonedSubElement);
|
||||
}
|
||||
XMLPrinter printer2;
|
||||
doc2.Print(&printer2);
|
||||
|
||||
XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
|
||||
}
|
||||
|
||||
{
|
||||
// Deep cloning of document.
|
||||
XMLDocument doc2;
|
||||
XMLPrinter printer1;
|
||||
{
|
||||
// Make sure doc1 is deleted before we test doc2
|
||||
const char* xml =
|
||||
"<?xml version ='1.0'?>"
|
||||
"<!-- Top level comment. -->"
|
||||
"<root>"
|
||||
" <child1 foo='bar'/>"
|
||||
" <!-- comment thing -->"
|
||||
" <child2 val='1'>Text</child2>"
|
||||
"</root>";
|
||||
XMLDocument doc;
|
||||
doc.Parse(xml);
|
||||
doc.Print(&printer1);
|
||||
|
||||
doc.DeepCopy(&doc2);
|
||||
}
|
||||
XMLPrinter printer2;
|
||||
doc2.Print(&printer2);
|
||||
|
||||
XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// This shouldn't crash.
|
||||
XMLDocument doc;
|
||||
if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
|
||||
@@ -1179,7 +1289,7 @@ int main( int argc, const char ** argv )
|
||||
doc.Parse( xml );
|
||||
|
||||
XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
|
||||
XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
|
||||
XMLTest( "Handle, success, mutable", "sub", ele->Value() );
|
||||
|
||||
XMLHandle docH( doc );
|
||||
ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
|
||||
@@ -1208,8 +1318,8 @@ int main( int argc, const char ** argv )
|
||||
doc.Print( &printer );
|
||||
|
||||
static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
XMLTest( "BOM and default declaration", printer.CStr(), result, false );
|
||||
XMLTest( "CStrSize", printer.CStrSize(), 42, false );
|
||||
XMLTest( "BOM and default declaration", result, printer.CStr(), false );
|
||||
XMLTest( "CStrSize", 42, printer.CStrSize(), false );
|
||||
}
|
||||
{
|
||||
const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
|
||||
@@ -1239,50 +1349,50 @@ int main( int argc, const char ** argv )
|
||||
pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
|
||||
|
||||
|
||||
XMLTest( "QueryIntText", intValue, 1, false );
|
||||
XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
|
||||
XMLTest( "QueryFloatText", floatValue, 1.2f, false );
|
||||
XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
|
||||
XMLTest( "QueryBoolText", boolValue, true, false );
|
||||
XMLTest( "QueryIntText", 1, intValue, false );
|
||||
XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
|
||||
XMLTest( "QueryFloatText", 1.2f, floatValue, false );
|
||||
XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
|
||||
XMLTest( "QueryBoolText", true, boolValue, false );
|
||||
}
|
||||
|
||||
{
|
||||
const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
|
||||
XMLDocument doc;
|
||||
doc.Parse( xml );
|
||||
XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
|
||||
XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
|
||||
}
|
||||
|
||||
{
|
||||
const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
|
||||
XMLDocument doc;
|
||||
doc.Parse( xml );
|
||||
XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
|
||||
XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
|
||||
}
|
||||
|
||||
{
|
||||
const char* xml = "<3lement></3lement>";
|
||||
XMLDocument doc;
|
||||
doc.Parse( xml );
|
||||
XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
|
||||
XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
|
||||
}
|
||||
|
||||
{
|
||||
const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
|
||||
XMLDocument doc;
|
||||
doc.Parse( xml, 10 );
|
||||
XMLTest( "Set length of incoming data", doc.Error(), false );
|
||||
XMLTest( "Set length of incoming data", false, doc.Error() );
|
||||
}
|
||||
|
||||
{
|
||||
XMLDocument doc;
|
||||
XMLTest( "Document is initially empty", doc.NoChildren(), true );
|
||||
XMLTest( "Document is initially empty", true, doc.NoChildren() );
|
||||
doc.Clear();
|
||||
XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
|
||||
XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
|
||||
doc.LoadFile( "resources/dream.xml" );
|
||||
XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
|
||||
XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
|
||||
doc.Clear();
|
||||
XMLTest( "Document Clear()'s", doc.NoChildren(), true );
|
||||
XMLTest( "Document Clear()'s", true, doc.NoChildren() );
|
||||
}
|
||||
|
||||
// ----------- Whitespace ------------
|
||||
@@ -1570,22 +1680,31 @@ int main( int argc, const char ** argv )
|
||||
}
|
||||
|
||||
{
|
||||
// Check that declarations are parsed only as the FirstChild
|
||||
// Check that declarations are allowed only at beginning of document
|
||||
const char* xml0 = "<?xml version=\"1.0\" ?>"
|
||||
" <!-- xml version=\"1.1\" -->"
|
||||
"<first />";
|
||||
const char* xml1 = "<?xml version=\"1.0\" ?>"
|
||||
" <?xml version=\"1.1\" ?>"
|
||||
"<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
|
||||
"<first />";
|
||||
const char* xml2 = "<first />"
|
||||
"<?xml version=\"1.0\" ?>";
|
||||
const char* xml3 = "<first></first>"
|
||||
"<?xml version=\"1.0\" ?>";
|
||||
|
||||
const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
|
||||
|
||||
XMLDocument doc;
|
||||
doc.Parse(xml0);
|
||||
XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
|
||||
XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
|
||||
doc.Parse(xml1);
|
||||
XMLTest("Test that the second declaration throws an error", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
|
||||
XMLTest("Test that the second declaration is allowed", false, doc.Error() );
|
||||
doc.Parse(xml2);
|
||||
XMLTest("Test that declaration after a child throws an error", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
|
||||
XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
|
||||
doc.Parse(xml3);
|
||||
XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
|
||||
doc.Parse(xml4);
|
||||
XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1604,11 +1723,221 @@ int main( int argc, const char ** argv )
|
||||
{
|
||||
XMLDocument doc;
|
||||
for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
|
||||
doc.SetError( (XMLError)i, 0, 0 );
|
||||
doc.SetError( (XMLError)i, 0, 0, 0 );
|
||||
doc.ErrorName();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Evil memory leaks.
|
||||
// If an XMLElement (etc) is allocated via NewElement() (etc.)
|
||||
// and NOT added to the XMLDocument, what happens?
|
||||
//
|
||||
// Previously (buggy):
|
||||
// The memory would be free'd when the XMLDocument is
|
||||
// destructed. But the destructor wasn't called, so that
|
||||
// memory allocated by the XMLElement would not be free'd.
|
||||
// In practice this meant strings allocated by the XMLElement
|
||||
// would leak. An edge case, but annoying.
|
||||
// Now:
|
||||
// The destructor is called. But the list of unlinked nodes
|
||||
// has to be tracked. This has a minor performance impact
|
||||
// that can become significant if you have a lot. (But why
|
||||
// would you do that?)
|
||||
// The only way to see this bug is in a leak tracker. This
|
||||
// is compiled in by default on Windows Debug.
|
||||
{
|
||||
XMLDocument doc;
|
||||
doc.NewElement("LEAK 1");
|
||||
}
|
||||
{
|
||||
XMLDocument doc;
|
||||
XMLElement* ele = doc.NewElement("LEAK 2");
|
||||
doc.DeleteNode(ele);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Crashing reported via email.
|
||||
const char* xml =
|
||||
"<playlist id='playlist1'>"
|
||||
"<property name='track_name'>voice</property>"
|
||||
"<property name='audio_track'>1</property>"
|
||||
"<entry out = '604' producer = '4_playlist1' in = '0' />"
|
||||
"<blank length = '1' />"
|
||||
"<entry out = '1625' producer = '3_playlist' in = '0' />"
|
||||
"<blank length = '2' />"
|
||||
"<entry out = '946' producer = '2_playlist1' in = '0' />"
|
||||
"<blank length = '1' />"
|
||||
"<entry out = '128' producer = '1_playlist1' in = '0' />"
|
||||
"</playlist>";
|
||||
|
||||
// It's not a good idea to delete elements as you walk the
|
||||
// list. I'm not sure this technically should work; but it's
|
||||
// an interesting test case.
|
||||
XMLDocument doc;
|
||||
XMLError err = doc.Parse(xml);
|
||||
XMLTest("Crash bug parsing", XML_SUCCESS, err );
|
||||
|
||||
XMLElement* playlist = doc.FirstChildElement("playlist");
|
||||
XMLTest("Crash bug parsing", true, playlist != 0);
|
||||
|
||||
tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
|
||||
XMLTest("Crash bug parsing", true, entry != 0);
|
||||
while (entry) {
|
||||
tinyxml2::XMLElement* todelete = entry;
|
||||
entry = entry->NextSiblingElement("entry");
|
||||
playlist->DeleteChild(todelete);
|
||||
};
|
||||
tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
|
||||
while (blank) {
|
||||
tinyxml2::XMLElement* todelete = blank;
|
||||
blank = blank->NextSiblingElement("blank");
|
||||
playlist->DeleteChild(todelete);
|
||||
};
|
||||
|
||||
tinyxml2::XMLPrinter printer;
|
||||
playlist->Accept(&printer);
|
||||
printf("%s\n", printer.CStr());
|
||||
|
||||
// No test; it only need to not crash.
|
||||
// Still, wrap it up with a sanity check
|
||||
int nProperty = 0;
|
||||
for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
|
||||
nProperty++;
|
||||
}
|
||||
XMLTest("Crash bug parsing", 2, nProperty);
|
||||
}
|
||||
|
||||
// ----------- Line Number Tracking --------------
|
||||
{
|
||||
struct TestUtil: XMLVisitor
|
||||
{
|
||||
void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
|
||||
{
|
||||
XMLDocument doc;
|
||||
XMLError err = doc.Parse(docStr);
|
||||
|
||||
XMLTest(testString, true, doc.Error());
|
||||
XMLTest(testString, expected_error, err);
|
||||
XMLTest(testString, expectedLine, doc.GetErrorLineNum());
|
||||
};
|
||||
|
||||
void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
|
||||
{
|
||||
XMLDocument doc;
|
||||
doc.Parse(docStr);
|
||||
XMLTest(testString, false, doc.Error());
|
||||
TestDocLines(testString, doc, expectedLines);
|
||||
}
|
||||
|
||||
void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
|
||||
{
|
||||
XMLDocument doc;
|
||||
doc.LoadFile(file_name);
|
||||
XMLTest(testString, false, doc.Error());
|
||||
TestDocLines(testString, doc, expectedLines);
|
||||
}
|
||||
|
||||
private:
|
||||
DynArray<char, 10> str;
|
||||
|
||||
void Push(char type, int lineNum)
|
||||
{
|
||||
str.Push(type);
|
||||
str.Push(char('0' + (lineNum / 10)));
|
||||
str.Push(char('0' + (lineNum % 10)));
|
||||
}
|
||||
|
||||
bool VisitEnter(const XMLDocument& doc)
|
||||
{
|
||||
Push('D', doc.GetLineNum());
|
||||
return true;
|
||||
}
|
||||
bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
|
||||
{
|
||||
Push('E', element.GetLineNum());
|
||||
for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
|
||||
Push('A', attr->GetLineNum());
|
||||
return true;
|
||||
}
|
||||
bool Visit(const XMLDeclaration& declaration)
|
||||
{
|
||||
Push('L', declaration.GetLineNum());
|
||||
return true;
|
||||
}
|
||||
bool Visit(const XMLText& text)
|
||||
{
|
||||
Push('T', text.GetLineNum());
|
||||
return true;
|
||||
}
|
||||
bool Visit(const XMLComment& comment)
|
||||
{
|
||||
Push('C', comment.GetLineNum());
|
||||
return true;
|
||||
}
|
||||
bool Visit(const XMLUnknown& unknown)
|
||||
{
|
||||
Push('U', unknown.GetLineNum());
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
|
||||
{
|
||||
str.Clear();
|
||||
doc.Accept(this);
|
||||
str.Push(0);
|
||||
XMLTest(testString, expectedLines, str.Mem());
|
||||
}
|
||||
} tester;
|
||||
|
||||
tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
|
||||
tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
|
||||
tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
|
||||
tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
|
||||
tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
|
||||
tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
|
||||
tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
|
||||
tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
|
||||
tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
|
||||
tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
|
||||
tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
|
||||
|
||||
tester.TestStringLines(
|
||||
"LineNumbers-String",
|
||||
|
||||
"<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
|
||||
"<root a='b' \n" // 2 Element Attribute
|
||||
"c='d'> d <blah/> \n" // 3 Attribute Text Element
|
||||
"newline in text \n" // 4 Text
|
||||
"and second <zxcv/><![CDATA[\n" // 5 Element Text
|
||||
" cdata test ]]><!-- comment -->\n" // 6 Comment
|
||||
"<! unknown></root>", // 7 Unknown
|
||||
|
||||
"D01L01E02A02A03T03E03T04E05T05C06U07");
|
||||
|
||||
tester.TestStringLines(
|
||||
"LineNumbers-CRLF",
|
||||
|
||||
"\r\n" // 1 Doc (arguably should be line 2)
|
||||
"<?xml version=\"1.0\"?>\n" // 2 DecL
|
||||
"<root>\r\n" // 3 Element
|
||||
"\n" // 4
|
||||
"text contining new line \n" // 5 Text
|
||||
" and also containing crlf \r\n" // 6
|
||||
"<sub><![CDATA[\n" // 7 Element Text
|
||||
"cdata containing new line \n" // 8
|
||||
" and also containing cflr\r\n" // 9
|
||||
"]]></sub><sub2/></root>", // 10 Element
|
||||
|
||||
"D01L02E03T05E07T07E10");
|
||||
|
||||
tester.TestFileLines(
|
||||
"LineNumbers-File",
|
||||
"resources/utf8test.xml",
|
||||
"D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
|
||||
}
|
||||
|
||||
// ----------- Performance tracking --------------
|
||||
{
|
||||
#if defined( _MSC_VER )
|
||||
@@ -1618,7 +1947,7 @@ int main( int argc, const char ** argv )
|
||||
|
||||
FILE* perfFP = fopen("resources/dream.xml", "r");
|
||||
fseek(perfFP, 0, SEEK_END);
|
||||
long size = ftell(fp);
|
||||
long size = ftell(perfFP);
|
||||
fseek(perfFP, 0, SEEK_SET);
|
||||
|
||||
char* mem = new char[size + 1];
|
||||
@@ -1664,6 +1993,11 @@ int main( int argc, const char ** argv )
|
||||
_CrtMemState diffMemState;
|
||||
_CrtMemDifference( &diffMemState, &startMemState, &endMemState );
|
||||
_CrtMemDumpStatistics( &diffMemState );
|
||||
|
||||
{
|
||||
int leaksBeforeExit = _CrtDumpMemoryLeaks();
|
||||
XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
|
||||
}
|
||||
#endif
|
||||
|
||||
printf ("\nPass %d, Fail %d\n", gPass, gFail);
|
||||
|
||||
Reference in New Issue
Block a user