[tinyxml2] Update: 10.0.0 -> 10.1.0

This commit is contained in:
David Korth 2025-03-08 17:35:42 -05:00
parent 9f9338fe40
commit d6953b866d
8 changed files with 176 additions and 162 deletions

View File

@ -1,6 +1,6 @@
# rom-properties: Disable CMake version requirement.
#cmake_minimum_required(VERSION 3.15)
project(tinyxml2 VERSION 10.0.0)
project(tinyxml2 VERSION 10.1.0)
IF(0) # rom-properties: Disable tests.
include(CTest)
@ -93,7 +93,11 @@ endif ()
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
## Custom locations
## Custom settings
# rom-properties: Disabled.
#option(tinyxml2_INSTALL_PKGCONFIG "Create and install pkgconfig files" ON)
set(tinyxml2_INSTALL_PKGCONFIG "Create and install pkgconfig files" OFF)
set(tinyxml2_INSTALL_PKGCONFIGDIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
CACHE PATH "Directory for pkgconfig files")
@ -140,6 +144,7 @@ IF(WIN32 AND BUILD_SHARED_LIBS AND INSTALL_DEBUG)
UNSET(PDB_FILENAME_R)
ENDIF(WIN32 AND BUILD_SHARED_LIBS AND INSTALL_DEBUG)
IF(0) # rom-properties
# Type-specific targets
if (BUILD_SHARED_LIBS)
@ -148,7 +153,6 @@ else ()
set(type static)
endif ()
IF(0) # rom-properties
install(
EXPORT tinyxml2-targets
DESTINATION "${tinyxml2_INSTALL_CMAKEDIR}"
@ -156,7 +160,6 @@ install(
FILE tinyxml2-${type}-targets.cmake
COMPONENT tinyxml2_development
)
ENDIF(0) # rom-properties
# Auto-generated version compatibility file
write_basic_package_version_file(
@ -164,7 +167,6 @@ write_basic_package_version_file(
COMPATIBILITY SameMajorVersion
)
IF(0) # rom-properties
install(
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/tinyxml2-config.cmake"
@ -172,26 +174,24 @@ install(
DESTINATION "${tinyxml2_INSTALL_CMAKEDIR}"
COMPONENT tinyxml2_development
)
ENDIF(0) # rom-properties
## Headers
IF(0) # rom-properties
install(
FILES tinyxml2.h
TYPE INCLUDE
COMPONENT tinyxml2_development
)
ENDIF(0) # rom-properties
## pkg-config
IF(0) # rom-properties
configure_file(cmake/tinyxml2.pc.in tinyxml2.pc.gen @ONLY)
file(GENERATE OUTPUT tinyxml2.pc INPUT "${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc.gen")
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc"
DESTINATION "${tinyxml2_INSTALL_PKGCONFIGDIR}"
COMPONENT tinyxml2_development
)
if (tinyxml2_INSTALL_PKGCONFIG)
configure_file(cmake/tinyxml2.pc.in tinyxml2.pc.gen @ONLY)
file(GENERATE OUTPUT tinyxml2.pc INPUT "${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc.gen")
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc"
DESTINATION "${tinyxml2_INSTALL_PKGCONFIGDIR}"
COMPONENT tinyxml2_development
)
endif ()
ENDIF(0) # rom-properties

View File

@ -1,11 +1,9 @@
This copy of tinyxml2-10.0.0 is a modified version of the original.
This copy of tinyxml2-10.1.0 is a modified version of the original.
commit 321ea883b7190d4e85cae5512a12e5eaa8f8731f
Merge pull request #965 from leethomason/v10.0.0
commit 57eea48c5bfc354ac45d53b2eb499e66c80d63e0
version to 10.1.0
V10.0.0
Tag: 10.0.0
Tag: 10.1.0
The following changes have been made to the original:
@ -21,5 +19,5 @@ The following changes have been made to the original:
- Fixed several -Wformat warnings.
To obtain the original tinyxml2-10.0.0, visit:
To obtain the original tinyxml2-10.1.0, visit:
https://github.com/leethomason/tinyxml2

View File

@ -7,7 +7,7 @@
// In HTML5, there are 16 so-called "void" elements. "void elements" NEVER have
// inner content (but they MAY have attributes), and are assumed to be self-closing.
// An example of a self-closig HTML5 element is "<br/>" (line break)
// An example of a self-closing HTML5 element is "<br/>" (line break)
// All other elements are called "non-void" and MUST never self-close.
// Examples: "<div class='lolcats'></div>".

2
extlib/tinyxml2/dox vendored
View File

@ -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 = 10.0.0
PROJECT_NUMBER = 10.1.0
# 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

View File

@ -24,7 +24,7 @@ distribution.
#include "tinyxml2.h"
#include <new> // yes, this one new style header, is in the Android SDK.
#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) || defined(__CC_ARM)
# include <stddef.h>
# include <stdarg.h>
#else
@ -106,14 +106,9 @@ distribution.
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
#define TIXML_FSEEK fseeko
#define TIXML_FTELL ftello
#elif defined(__ANDROID__)
#if __ANDROID_API__ > 24
#define TIXML_FSEEK fseeko64
#define TIXML_FTELL ftello64
#else
#define TIXML_FSEEK fseeko
#define TIXML_FTELL ftello
#endif
#elif defined(__ANDROID__) && __ANDROID_API__ > 24
#define TIXML_FSEEK fseeko64
#define TIXML_FTELL ftello64
#else
#define TIXML_FSEEK fseek
#define TIXML_FTELL ftell
@ -239,13 +234,13 @@ char* StrPair::ParseName( char* p )
if ( !p || !(*p) ) {
return 0;
}
if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
if ( !XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
return 0;
}
char* const start = p;
++p;
while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) {
while ( *p && XMLUtil::IsNameChar( static_cast<unsigned char>(*p) ) ) {
++p;
}
@ -472,102 +467,94 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length
}
const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)
{
// Presume an entity, and pull it out.
// Assume an entity, and pull it out.
*length = 0;
if ( *(p+1) == '#' && *(p+2) ) {
unsigned long ucs = 0;
TIXMLASSERT( sizeof( ucs ) >= 4 );
static const uint32_t MAX_CODE_POINT = 0x10FFFF;
if (*(p + 1) == '#' && *(p + 2)) {
uint32_t ucs = 0;
ptrdiff_t delta = 0;
unsigned mult = 1;
uint32_t mult = 1;
static const char SEMICOLON = ';';
if ( *(p+2) == 'x' ) {
bool hex = false;
uint32_t radix = 10;
const char* q = 0;
char terminator = '#';
if (*(p + 2) == 'x') {
// Hexadecimal.
const char* q = p+3;
if ( !(*q) ) {
return 0;
}
hex = true;
radix = 16;
terminator = 'x';
q = strchr( q, SEMICOLON );
if ( !q ) {
return 0;
}
TIXMLASSERT( *q == SEMICOLON );
delta = q-p;
--q;
while ( *q != 'x' ) {
unsigned int digit = 0;
if ( *q >= '0' && *q <= '9' ) {
digit = *q - '0';
}
else if ( *q >= 'a' && *q <= 'f' ) {
digit = *q - 'a' + 10;
}
else if ( *q >= 'A' && *q <= 'F' ) {
digit = *q - 'A' + 10;
}
else {
return 0;
}
TIXMLASSERT( digit < 16 );
TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
const unsigned int digitScaled = mult * digit;
TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
ucs += digitScaled;
TIXMLASSERT( mult <= UINT_MAX / 16 );
mult *= 16;
--q;
}
q = p + 3;
}
else {
// Decimal.
const char* q = p+2;
if ( !(*q) ) {
q = p + 2;
}
if (!(*q)) {
return 0;
}
q = strchr(q, SEMICOLON);
if (!q) {
return 0;
}
TIXMLASSERT(*q == SEMICOLON);
delta = q - p;
--q;
while (*q != terminator) {
uint32_t digit = 0;
if (*q >= '0' && *q <= '9') {
digit = *q - '0';
}
else if (hex && (*q >= 'a' && *q <= 'f')) {
digit = *q - 'a' + 10;
}
else if (hex && (*q >= 'A' && *q <= 'F')) {
digit = *q - 'A' + 10;
}
else {
return 0;
}
TIXMLASSERT(digit < radix);
q = strchr( q, SEMICOLON );
if ( !q ) {
return 0;
const unsigned int digitScaled = mult * digit;
ucs += digitScaled;
mult *= radix;
// Security check: could a value exist that is out of range?
// Easily; limit to the MAX_CODE_POINT, which also allows for a
// bunch of leading zeroes.
if (mult > MAX_CODE_POINT) {
mult = MAX_CODE_POINT;
}
TIXMLASSERT( *q == SEMICOLON );
delta = q-p;
--q;
while ( *q != '#' ) {
if ( *q >= '0' && *q <= '9' ) {
const unsigned int digit = *q - '0';
TIXMLASSERT( digit < 10 );
TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
const unsigned int digitScaled = mult * digit;
TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
ucs += digitScaled;
}
else {
return 0;
}
TIXMLASSERT( mult <= UINT_MAX / 10 );
mult *= 10;
--q;
}
}
// Out of range:
if (ucs > MAX_CODE_POINT) {
return 0;
}
// convert the UCS to UTF-8
ConvertUTF32ToUTF8( ucs, value, length );
ConvertUTF32ToUTF8(ucs, value, length);
if (length == 0) {
// If length is 0, there was an error. (Security? Bad input?)
// Fail safely.
return 0;
}
return p + delta + 1;
}
return p+1;
return p + 1;
}
void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
{
TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
@ -610,7 +597,7 @@ void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )
void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )
{
// horrible syntax trick to make the compiler happy about %llu
TIXML_SNPRINTF(buffer, bufferSize, "%llu", (unsigned long long)v);
TIXML_SNPRINTF(buffer, bufferSize, "%llu", static_cast<unsigned long long>(v));
}
bool XMLUtil::ToInt(const char* str, int* value)
@ -705,7 +692,7 @@ bool XMLUtil::ToInt64(const char* str, int64_t* value)
bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) {
*value = (uint64_t)v;
*value = static_cast<uint64_t>(v);
return true;
}
return false;
@ -1982,7 +1969,7 @@ char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
}
// attribute.
if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
if (XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
XMLAttribute* attrib = CreateAttribute();
TIXMLASSERT( attrib );
attrib->_parseLineNum = _document->_parseCurLineNum;
@ -2226,7 +2213,7 @@ void XMLDocument::MarkInUse(const XMLNode* const node)
TIXMLASSERT(node);
TIXMLASSERT(node->_parent == 0);
for (int i = 0; i < _unlinked.Size(); ++i) {
for (size_t i = 0; i < _unlinked.Size(); ++i) {
if (node == _unlinked[i]) {
_unlinked.SwapRemove(i);
break;
@ -2509,7 +2496,7 @@ void XMLDocument::ClearError() {
void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
{
TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT);
_errorID = error;
_errorLineNum = lineNum;
_errorStr.Reset();
@ -2518,7 +2505,8 @@ void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ...
char* buffer = new char[BUFFER_SIZE];
TIXMLASSERT(sizeof(error) <= sizeof(int));
TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), (unsigned int)error, lineNum);
TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d",
ErrorIDToName(error), static_cast<int>(error), static_cast<unsigned int>(error), lineNum);
if (format) {
size_t len = strlen(buffer);

View File

@ -62,7 +62,7 @@ distribution.
#endif
// rom-properties: Allow overriding symbol visibility on Linux.
#ifdef _WIN32
#ifdef _MSC_VER
# ifdef TINYXML2_EXPORT
# define TINYXML2_LIB __declspec(dllexport)
# elif defined(TINYXML2_IMPORT)
@ -98,11 +98,11 @@ distribution.
http://semver.org/
*/
static const int TIXML2_MAJOR_VERSION = 10;
static const int TIXML2_MINOR_VERSION = 0;
static const int TIXML2_MINOR_VERSION = 1;
static const int TIXML2_PATCH_VERSION = 0;
#define TINYXML2_MAJOR_VERSION 10
#define TINYXML2_MINOR_VERSION 0
#define TINYXML2_MINOR_VERSION 1
#define TINYXML2_PATCH_VERSION 0
// A fixed element depth limit is problematic. There needs to be a
@ -200,7 +200,7 @@ private:
Has a small initial memory pool, so that low or no usage will not
cause a call to new/delete
*/
template <class T, int INITIAL_SIZE>
template <class T, size_t INITIAL_SIZE>
class DynArray
{
public:
@ -228,9 +228,8 @@ public:
++_size;
}
T* PushArr( int count ) {
TIXMLASSERT( count >= 0 );
TIXMLASSERT( _size <= INT_MAX - count );
T* PushArr( size_t count ) {
TIXMLASSERT( _size <= SIZE_MAX - count );
EnsureCapacity( _size+count );
T* ret = &_mem[_size];
_size += count;
@ -243,7 +242,7 @@ public:
return _mem[_size];
}
void PopArr( int count ) {
void PopArr( size_t count ) {
TIXMLASSERT( _size >= count );
_size -= count;
}
@ -252,13 +251,13 @@ public:
return _size == 0;
}
T& operator[](int i) {
TIXMLASSERT( i>= 0 && i < _size );
T& operator[](size_t i) {
TIXMLASSERT( i < _size );
return _mem[i];
}
const T& operator[](int i) const {
TIXMLASSERT( i>= 0 && i < _size );
const T& operator[](size_t i) const {
TIXMLASSERT( i < _size );
return _mem[i];
}
@ -267,18 +266,18 @@ public:
return _mem[ _size - 1];
}
int Size() const {
size_t Size() const {
TIXMLASSERT( _size >= 0 );
return _size;
}
int Capacity() const {
size_t Capacity() const {
TIXMLASSERT( _allocated >= INITIAL_SIZE );
return _allocated;
}
void SwapRemove(int i) {
TIXMLASSERT(i >= 0 && i < _size);
void SwapRemove(size_t i) {
TIXMLASSERT(i < _size);
TIXMLASSERT(_size > 0);
_mem[i] = _mem[_size - 1];
--_size;
@ -298,14 +297,14 @@ private:
DynArray( const DynArray& ); // not supported
void operator=( const DynArray& ); // not supported
void EnsureCapacity( int cap ) {
void EnsureCapacity( size_t cap ) {
TIXMLASSERT( cap > 0 );
if ( cap > _allocated ) {
TIXMLASSERT( cap <= INT_MAX / 2 );
const int newAllocated = cap * 2;
T* newMem = new T[static_cast<unsigned int>(newAllocated)];
TIXMLASSERT( cap <= SIZE_MAX / 2 / sizeof(T));
const size_t newAllocated = cap * 2;
T* newMem = new T[newAllocated];
TIXMLASSERT( newAllocated >= _size );
memcpy( newMem, _mem, sizeof(T)*static_cast<size_t>(_size) ); // warning: not using constructors, only works for PODs
memcpy( newMem, _mem, sizeof(T) * _size ); // warning: not using constructors, only works for PODs
if ( _mem != _pool ) {
delete [] _mem;
}
@ -315,9 +314,9 @@ private:
}
T* _mem;
T _pool[static_cast<size_t>(INITIAL_SIZE)];
int _allocated; // objects allocated
int _size; // number objects in use
T _pool[INITIAL_SIZE];
size_t _allocated; // objects allocated
size_t _size; // number objects in use
};
@ -331,7 +330,7 @@ public:
MemPool() {}
virtual ~MemPool() {}
virtual int ItemSize() const = 0;
virtual size_t ItemSize() const = 0;
virtual void* Alloc() = 0;
virtual void Free( void* ) = 0;
virtual void SetTracked() = 0;
@ -341,7 +340,7 @@ public:
/*
Template child class to create pools of the correct type.
*/
template< int ITEM_SIZE >
template< size_t ITEM_SIZE >
class MemPoolT : public MemPool
{
public:
@ -363,10 +362,10 @@ public:
_nUntracked = 0;
}
virtual int ItemSize() const override{
virtual size_t ItemSize() const override {
return ITEM_SIZE;
}
int CurrentAllocs() const {
size_t CurrentAllocs() const {
return _currentAllocs;
}
@ -377,7 +376,7 @@ public:
_blockPtrs.Push( block );
Item* blockItems = block->items;
for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
for( size_t i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
blockItems[i].next = &(blockItems[i + 1]);
}
blockItems[ITEMS_PER_BLOCK - 1].next = 0;
@ -418,7 +417,7 @@ public:
--_nUntracked;
}
int Untracked() const {
size_t Untracked() const {
return _nUntracked;
}
@ -449,10 +448,10 @@ private:
DynArray< Block*, 10 > _blockPtrs;
Item* _root;
int _currentAllocs;
int _nAllocs;
int _maxAllocs;
int _nUntracked;
size_t _currentAllocs;
size_t _nAllocs;
size_t _maxAllocs;
size_t _nUntracked;
};
@ -893,7 +892,7 @@ public:
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
is specified, the memory will be allocated in the
specified XMLDocument.
NOTE: This is probably not the correct tool to
@ -1982,11 +1981,11 @@ private:
void PushDepth();
void PopDepth();
template<class NodeType, int PoolElementSize>
template<class NodeType, size_t PoolElementSize>
NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
};
template<class NodeType, int PoolElementSize>
template<class NodeType, size_t PoolElementSize>
inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
{
TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );
@ -2316,7 +2315,7 @@ public:
of the XML file in memory. (Note the size returned
includes the terminating null.)
*/
int CStrSize() const {
size_t CStrSize() const {
return _buffer.Size();
}
/**
@ -2376,7 +2375,7 @@ private:
};
} // tinyxml2
} // namespace tinyxml2
#if defined(_MSC_VER)
# pragma warning(pop)

View File

@ -1,7 +1,7 @@
#include <windows.h>
#define TINYXML2_VERSION_NUMERIC 10,0,0,0
#define TINYXML2_VERSION_STRING "10.0.0"
#define TINYXML2_VERSION_NUMERIC 10,1,0,0
#define TINYXML2_VERSION_STRING "10.1.0"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
@ -29,7 +29,7 @@ BEGIN
#else
VALUE "InternalName", "tinyxml2.dll\0"
#endif
VALUE "LegalCopyright", "(C) 2000-2023 Lee Thomason\0"
VALUE "LegalCopyright", "(C) 2000-2025 Lee Thomason\0"
#ifdef _DEBUG
VALUE "OriginalFilename", "tinyxml2d.dll\0"
#else

View File

@ -1005,7 +1005,7 @@ int main( int argc, const char ** argv )
FILE* fp1 = fopen("resources/out/printer_1.xml", "w");
XMLPrinter printer(fp1);
printer.PushDeclaration("version = '1.0' enconding = 'utf-8'");
printer.PushDeclaration("version = '1.0' encoding = 'utf-8'");
printer.OpenElement("foo");
printer.PushAttribute("attrib-text", "text");
@ -1096,7 +1096,7 @@ int main( int argc, const char ** argv )
const XMLDeclaration* declaration = cdoc.FirstChild()->ToDeclaration();
const char* declaration_value = declaration->Value();
XMLTest("PushDeclaration() test", "version = '1.0' enconding = 'utf-8'", declaration_value);
XMLTest("PushDeclaration() test", "version = '1.0' encoding = 'utf-8'", declaration_value);
}
}
@ -1642,7 +1642,7 @@ int main( int argc, const char ** argv )
static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
XMLTest( "BOM and default declaration", result, printer.CStr(), false );
XMLTest( "CStrSize", 42, printer.CStrSize(), false );
XMLTest( "CStrSize", true, printer.CStrSize() == 42, false );
}
{
const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
@ -2639,7 +2639,7 @@ int main( int argc, const char ** argv )
"<?xml version=\"1.0\"?>\n" // 2 DecL
"<root>\r\n" // 3 Element
"\n" // 4
"text contining new line \n" // 5 Text
"text containing new line \n" // 5 Text
" and also containing crlf \r\n" // 6
"<sub><![CDATA[\n" // 7 Element Text
"cdata containing new line \n" // 8
@ -2666,6 +2666,35 @@ int main( int argc, const char ** argv )
doc.PrintError();
}
// ---------- CVE-2024-50615 -----------
{
const char* xml = "<Hello value='12&#65;34' value2='56&#x42;78'>Text</Hello>";
XMLDocument doc;
doc.Parse(xml);
const char* value = doc.FirstChildElement()->Attribute("value");
const char* value2 = doc.FirstChildElement()->Attribute("value2");
XMLTest("Test attribute encode", false, doc.Error());
XMLTest("Test decimal value", value, "12A34");
XMLTest("Test hex encode", value2, "56B78");
}
{
const char* xml = "<Hello value='&#ABC9000000065;' value2='&#xffffffff;' value3='&#5000000000;' value4='&#x00000045;' value5='&#x000000000000000021;'>Text</Hello>";
XMLDocument doc;
doc.Parse(xml);
const char* value = doc.FirstChildElement()->Attribute("value");
const char* value2 = doc.FirstChildElement()->Attribute("value2");
const char* value3 = doc.FirstChildElement()->Attribute("value3");
const char* value4 = doc.FirstChildElement()->Attribute("value4");
const char* value5 = doc.FirstChildElement()->Attribute("value5");
XMLTest("Test attribute encode", false, doc.Error());
XMLTest("Test attribute encode too long value", value, "&#ABC9000000065;"); // test long value
XMLTest("Test attribute encode out of unicode range", value2, "&#xffffffff;"); // out of unicode range
XMLTest("Test attribute encode out of int max value", value3, "&#5000000000;"); // out of int max value
XMLTest("Test attribute encode with a Hex value", value4, "E"); // hex value in unicode value
XMLTest("Test attribute encode with a Hex value", value5, "!"); // hex value in unicode value
}
// ----------- Performance tracking --------------
{
#if defined( _MSC_VER )