summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Jamfile.jam19
-rw-r--r--Jamrules.jam26
-rw-r--r--src/pugiconfig.hpp3
-rw-r--r--src/pugiutf.hpp358
-rw-r--r--src/pugixml.cpp2056
-rw-r--r--src/pugixml.hpp338
-rw-r--r--src/pugixpath.cpp498
-rw-r--r--tests/allocator.cpp89
-rw-r--r--tests/allocator.hpp7
-rw-r--r--tests/autotest.pl141
-rw-r--r--tests/data/empty.xml0
-rw-r--r--tests/data/multiline.xml3
-rw-r--r--tests/data/utftest_utf16_be.xmlbin0 -> 4176 bytes
-rw-r--r--tests/data/utftest_utf16_be_bom.xmlbin0 -> 4178 bytes
-rw-r--r--tests/data/utftest_utf16_be_clean.xmlbin0 -> 3932 bytes
-rw-r--r--tests/data/utftest_utf16_be_nodecl.xmlbin0 -> 4130 bytes
-rw-r--r--tests/data/utftest_utf16_le.xmlbin0 -> 4176 bytes
-rw-r--r--tests/data/utftest_utf16_le_bom.xmlbin0 -> 4178 bytes
-rw-r--r--tests/data/utftest_utf16_le_clean.xmlbin0 -> 3932 bytes
-rw-r--r--tests/data/utftest_utf16_le_nodecl.xmlbin0 -> 4130 bytes
-rw-r--r--tests/data/utftest_utf32_be.xmlbin0 -> 8348 bytes
-rw-r--r--tests/data/utftest_utf32_be_bom.xmlbin0 -> 8352 bytes
-rw-r--r--tests/data/utftest_utf32_be_clean.xmlbin0 -> 7860 bytes
-rw-r--r--tests/data/utftest_utf32_be_nodecl.xmlbin0 -> 8256 bytes
-rw-r--r--tests/data/utftest_utf32_le.xmlbin0 -> 8348 bytes
-rw-r--r--tests/data/utftest_utf32_le_bom.xmlbin0 -> 8352 bytes
-rw-r--r--tests/data/utftest_utf32_le_clean.xmlbin0 -> 7860 bytes
-rw-r--r--tests/data/utftest_utf32_le_nodecl.xmlbin0 -> 8256 bytes
-rw-r--r--tests/data/utftest_utf8.xml87
-rw-r--r--tests/data/utftest_utf8_bom.xml87
-rw-r--r--tests/data/utftest_utf8_clean.xml84
-rw-r--r--tests/data/utftest_utf8_nodecl.xml86
-rw-r--r--tests/helpers.hpp7
-rw-r--r--tests/main.cpp35
-rw-r--r--tests/test.cpp134
-rw-r--r--tests/test.hpp179
-rw-r--r--tests/test_document.cpp459
-rw-r--r--tests/test_dom_modify.cpp397
-rw-r--r--tests/test_dom_traverse.cpp465
-rw-r--r--tests/test_header_guard.cpp3
-rw-r--r--tests/test_header_iosfwd_1.cpp3
-rw-r--r--tests/test_header_iosfwd_2.cpp3
-rw-r--r--tests/test_header_iostream_1.cpp3
-rw-r--r--tests/test_header_iostream_2.cpp3
-rw-r--r--tests/test_header_string_1.cpp3
-rw-r--r--tests/test_header_string_2.cpp3
-rw-r--r--tests/test_memory.cpp14
-rw-r--r--tests/test_parse.cpp375
-rw-r--r--tests/test_unicode.cpp133
-rw-r--r--tests/test_write.cpp262
-rw-r--r--tests/test_xpath.cpp96
-rw-r--r--tests/test_xpath_api.cpp56
-rw-r--r--tests/test_xpath_functions.cpp662
-rw-r--r--tests/test_xpath_operators.cpp544
-rw-r--r--tests/test_xpath_parse.cpp82
-rw-r--r--tests/test_xpath_paths.cpp396
-rw-r--r--tests/test_xpath_paths_abbrev_w3c.cpp148
-rw-r--r--tests/test_xpath_paths_w3c.cpp212
-rw-r--r--tests/writer_string.cpp77
-rw-r--r--tests/writer_string.hpp27
60 files changed, 5814 insertions, 2849 deletions
diff --git a/Jamfile.jam b/Jamfile.jam
index 2e3a59f..beba202 100644
--- a/Jamfile.jam
+++ b/Jamfile.jam
@@ -28,8 +28,8 @@ if ( ! $(configuration) )
configuration = "debug" ;
}
-# remove empty define
-defines -= "" ;
+# split defines into list
+defines = [ Split $(defines) : ',' ] ;
# options
if ( $(defines) )
@@ -41,23 +41,24 @@ else
BUILD = build/$(toolset)/standard/$(configuration) ;
}
-if ( $(toolset:I=^mingw) )
+if ( $(toolset:I=^mingw) || $(toolset) = gcc )
{
CCFLAGS = -fprofile-arcs -ftest-coverage ;
LDFLAGS = -fprofile-arcs ;
GCOVFLAGS = -n ;
- if ( $(toolset) = mingw44 )
- {
- GCOVFLAGS += -o $(BUILD)/src ; # because stupid gcov can't find files via relative paths any more
- }
+ GCOVFLAGS += -o $(BUILD)/src ; # because stupid gcov can't find files via relative paths
}
# rules
include "Jamrules.jam" ;
+# enable dependency cache
+DEPCACHE.standard = build/.depcache ;
+
# targets
Library pugixml : src/pugixml.cpp src/pugixpath.cpp ;
-Application tests : tests/main.cpp [ Glob tests : test_*.cpp ] : pugixml ;
+Application tests : [ Glob tests : *.cpp ] : pugixml ;
Test run_tests : tests ;
-Coverage coverage : run_tests ;
+Coverage coverage : pugixml ;
+Depends coverage : run_tests ;
diff --git a/Jamrules.jam b/Jamrules.jam
index 54806a6..02bbe6f 100644
--- a/Jamrules.jam
+++ b/Jamrules.jam
@@ -8,7 +8,7 @@ if ( $(toolset:I=^mingw) || $(toolset) = "gcc" )
}
else
{
- GCCPATH = "%$(toolset)_PATH%\bin\\" ;
+ GCCPATH = "%$(toolset)_PATH%\\bin\\" ;
}
CCFLAGS += -D$(defines) ;
@@ -39,12 +39,12 @@ if ( $(toolset:I=^mingw) || $(toolset) = "gcc" )
actions LinkAction
{
- "$(GCCPATH)g++" $(>) -o $(<) -static-libgcc $(LDFLAGS)
+ "$(GCCPATH)g++" $(>) -o $(<) -static-libgcc -static $(LDFLAGS)
}
- actions CoverageAction
+ actions maxtargets 1 CoverageAction
{
- "$(GCCPATH)gcov" $(>:\\) $(GCOVFLAGS) | perl tests/gcov-filter.pl
+ "$(GCCPATH)gcov" $(>) $(GCOVFLAGS) | perl tests/gcov-filter.pl
}
}
else if ( $(toolset:I=^msvc) )
@@ -69,6 +69,15 @@ else if ( $(toolset:I=^msvc) )
CCFLAGS += /W3 ; # lots of warnings at W4 in standard library
}
+ if ( $(toolset) = msvc7 || $(toolset) = msvc71 || $(toolset) = msvc8 )
+ {
+ CCFLAGS += "/I\"%$(toolset)_PATH%\\PlatformSDK\\include\"" ;
+ }
+ else if ( $(toolset) != msvc6 )
+ {
+ CCFLAGS += "/I\"%WINSDK_PATH%\\Include\"" ;
+ }
+
if ( ! ( PUGIXML_NO_EXCEPTIONS in $(defines) ) )
{
CCFLAGS += /EHsc ;
@@ -107,7 +116,7 @@ else if ( $(toolset:I=^msvc) )
actions LinkAction
{
- "%$(toolset)_PATH%\bin$(postfix)\link.exe" /SUBSYSTEM:CONSOLE /NOLOGO /OUT:$(<) $(>) /LIBPATH:"%$(toolset)_PATH%\lib$(postfix)" /LIBPATH:"%$(toolset)_PATH%\PlatformSDK\lib" /LIBPATH:"%WINSDK_PATH%\Lib$(sdk_postfix)" $(LDFLAGS)
+ "%$(toolset)_PATH%\bin$(postfix)\link.exe" /SUBSYSTEM:CONSOLE /NOLOGO /OUT:$(<) /PDB:$(<:S=.pdb) $(>) /LIBPATH:"%$(toolset)_PATH%\lib$(postfix)" /LIBPATH:"%$(toolset)_PATH%\PlatformSDK\lib" /LIBPATH:"%WINSDK_PATH%\Lib$(sdk_postfix)" $(LDFLAGS)
}
actions CoverageAction
@@ -136,7 +145,7 @@ else if ( $(toolset) = "ic8" )
actions ObjectAction
{
- "%$(toolset)_PATH%\bin\icl.exe" /W4 /WX /Wport /Qwd981,444,280,383,909,304,167,177 /I"%$(msvc)_PATH%\include" /I"%$(toolset)_PATH%\include" /c $(>) /Fo$(<) /nologo $(CCFLAGS)
+ "%$(toolset)_PATH%\bin\icl.exe" /W4 /WX /Wport /Qwd981,444,280,383,909,304,167,177,1419 /I"%$(msvc)_PATH%\include" /I"%$(msvc)_PATH%\PlatformSDK\Include" /I"%$(toolset)_PATH%\include" /c $(>) /Fo$(<) /nologo $(CCFLAGS)
}
actions LibraryAction
@@ -183,7 +192,7 @@ else if ( $(toolset:I=^dmc) )
actions LinkAction
{
- "%$(toolset)_PATH%\bin\link.exe" $(>:\\) , $(<:\\) , nul , $(LDFLAGS:\\)
+ "%$(toolset)_PATH%\bin\link.exe" $(>:\\) , $(<:\\) , nul , $(LDFLAGS:\\) -L/co/ma
}
actions CoverageAction
@@ -400,6 +409,9 @@ rule CleanCoverage TARGET
# clean object files
local FILES = $($(SOURCE)_objects:S=.gcda) ;
+ # disable "independent target" warnings
+ NotFile $(FILES) ;
+
DeleteAction $(CLEAN_TARGET) : $(FILES) ;
}
diff --git a/src/pugiconfig.hpp b/src/pugiconfig.hpp
index 517c959..a62b7f4 100644
--- a/src/pugiconfig.hpp
+++ b/src/pugiconfig.hpp
@@ -14,6 +14,9 @@
#ifndef HEADER_PUGICONFIG_HPP
#define HEADER_PUGICONFIG_HPP
+// Uncomment this to enable wchar_t mode
+// #define PUGIXML_WCHAR_MODE
+
// Uncomment this to disable STL
// #define PUGIXML_NO_STL
diff --git a/src/pugiutf.hpp b/src/pugiutf.hpp
new file mode 100644
index 0000000..dfca940
--- /dev/null
+++ b/src/pugiutf.hpp
@@ -0,0 +1,358 @@
+/**
+ * pugixml parser - version 0.5
+ * --------------------------------------------------------
+ * Copyright (C) 2006-2009, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Report bugs and download new versions at http://code.google.com/p/pugixml/
+ *
+ * This library is distributed under the MIT License. See notice at the end
+ * of this file.
+ *
+ * This work is based on the pugxml parser, which is:
+ * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
+ */
+
+#ifndef HEADER_PUGIUTF_HPP
+#define HEADER_PUGIUTF_HPP
+
+namespace pugi
+{
+ namespace impl
+ {
+ typedef unsigned char char8_t;
+ typedef unsigned short char16_t;
+ typedef unsigned int char32_t;
+
+ inline char16_t endian_swap(char16_t value)
+ {
+ return static_cast<char16_t>(((value & 0xff) << 8) | (value >> 8));
+ }
+
+ inline char32_t endian_swap(char32_t value)
+ {
+ return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
+ }
+
+ struct utf8_counter
+ {
+ typedef size_t value_type;
+
+ static value_type low(value_type result, char32_t ch)
+ {
+ // U+0000..U+007F
+ if (ch < 0x80) return result + 1;
+ // U+0080..U+07FF
+ else if (ch < 0x800) return result + 2;
+ // U+0800..U+FFFF
+ else return result + 3;
+ }
+
+ static value_type high(value_type result, char32_t)
+ {
+ // U+10000..U+10FFFF
+ return result + 4;
+ }
+ };
+
+ struct utf8_writer
+ {
+ typedef char8_t* value_type;
+
+ static value_type low(value_type result, char32_t ch)
+ {
+ // U+0000..U+007F
+ if (ch < 0x80)
+ {
+ *result = static_cast<char8_t>(ch);
+ return result + 1;
+ }
+ // U+0080..U+07FF
+ else if (ch < 0x800)
+ {
+ result[0] = static_cast<char8_t>(0xC0 | (ch >> 6));
+ result[1] = static_cast<char8_t>(0x80 | (ch & 0x3F));
+ return result + 2;
+ }
+ // U+0800..U+FFFF
+ else
+ {
+ result[0] = static_cast<char8_t>(0xE0 | (ch >> 12));
+ result[1] = static_cast<char8_t>(0x80 | ((ch >> 6) & 0x3F));
+ result[2] = static_cast<char8_t>(0x80 | (ch & 0x3F));
+ return result + 3;
+ }
+ }
+
+ static value_type high(value_type result, char32_t ch)
+ {
+ // U+10000..U+10FFFF
+ result[0] = static_cast<char8_t>(0xF0 | (ch >> 18));
+ result[1] = static_cast<char8_t>(0x80 | ((ch >> 12) & 0x3F));
+ result[2] = static_cast<char8_t>(0x80 | ((ch >> 6) & 0x3F));
+ result[3] = static_cast<char8_t>(0x80 | (ch & 0x3F));
+ return result + 4;
+ }
+
+ static value_type any(value_type result, char32_t ch)
+ {
+ return (ch < 0x10000) ? low(result, ch) : high(result, ch);
+ }
+ };
+
+ struct utf16_counter
+ {
+ typedef size_t value_type;
+
+ static value_type low(value_type result, char32_t)
+ {
+ return result + 1;
+ }
+
+ static value_type high(value_type result, char32_t)
+ {
+ return result + 2;
+ }
+ };
+
+ struct utf16_writer
+ {
+ typedef char16_t* value_type;
+
+ static value_type low(value_type result, char32_t ch)
+ {
+ *result = static_cast<char16_t>(ch);
+
+ return result + 1;
+ }
+
+ static value_type high(value_type result, char32_t ch)
+ {
+ char32_t msh = (char32_t)(ch - 0x10000) >> 10;
+ char32_t lsh = (char32_t)(ch - 0x10000) & 0x3ff;
+
+ result[0] = static_cast<char16_t>(0xD800 + msh);
+ result[1] = static_cast<char16_t>(0xDC00 + lsh);
+
+ return result + 2;
+ }
+
+ static value_type any(value_type result, char32_t ch)
+ {
+ return (ch < 0x10000) ? low(result, ch) : high(result, ch);
+ }
+ };
+
+ struct utf32_counter
+ {
+ typedef size_t value_type;
+
+ static value_type low(value_type result, char32_t)
+ {
+ return result + 1;
+ }
+
+ static value_type high(value_type result, char32_t)
+ {
+ return result + 1;
+ }
+ };
+
+ struct utf32_writer
+ {
+ typedef char32_t* value_type;
+
+ static value_type low(value_type result, char32_t ch)
+ {
+ *result = ch;
+
+ return result + 1;
+ }
+
+ static value_type high(value_type result, char32_t ch)
+ {
+ *result = ch;
+
+ return result + 1;
+ }
+
+ static value_type any(value_type result, char32_t ch)
+ {
+ *result = ch;
+
+ return result + 1;
+ }
+ };
+
+ template <size_t size> struct wchar_selector;
+
+ template <> struct wchar_selector<2>
+ {
+ typedef char16_t type;
+ typedef utf16_counter counter;
+ typedef utf16_writer writer;
+ };
+
+ template <> struct wchar_selector<4>
+ {
+ typedef char32_t type;
+ typedef utf32_counter counter;
+ typedef utf32_writer writer;
+ };
+
+ typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
+ typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
+
+ template <typename Traits> static inline typename Traits::value_type decode_utf8_block(const char8_t* data, size_t size, typename Traits::value_type result, Traits = Traits())
+ {
+ const char8_t utf8_byte_mask = 0x3f;
+
+ const char8_t* end = data + size;
+
+ while (data < end)
+ {
+ char8_t lead = *data;
+
+ // 0xxxxxxx -> U+0000..U+007F
+ if (lead < 0x80)
+ {
+ result = Traits::low(result, lead);
+ data += 1;
+ }
+ // 110xxxxx -> U+0080..U+07FF
+ else if ((unsigned)(lead - 0xC0) < 0x20 && data + 1 < end && (data[1] & 0xc0) == 0x80)
+ {
+ result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
+ data += 2;
+ }
+ // 1110xxxx -> U+0800-U+FFFF
+ else if ((unsigned)(lead - 0xE0) < 0x10 && data + 2 < end && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
+ {
+ result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
+ data += 3;
+ }
+ // 11110xxx -> U+10000..U+10FFFF
+ else if ((unsigned)(lead - 0xF0) < 0x08 && data + 3 < end && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
+ {
+ result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
+ data += 4;
+ }
+ // 10xxxxxx or 11111xxx -> invalid
+ else
+ {
+ data += 1;
+ }
+ }
+
+ return result;
+ }
+
+ template <typename Traits, typename opt1> static inline typename Traits::value_type decode_utf16_block(const char16_t* data, size_t size, typename Traits::value_type result, opt1, Traits = Traits())
+ {
+ const bool swap = opt1::o1;
+
+ const char16_t* end = data + size;
+
+ while (data < end)
+ {
+ char16_t lead = swap ? endian_swap(*data) : *data;
+
+ // U+0000..U+D7FF
+ if (lead < 0xD800)
+ {
+ result = Traits::low(result, lead);
+ data += 1;
+ }
+ // U+E000..U+FFFF
+ else if ((unsigned)(lead - 0xE000) < 0x2000)
+ {
+ result = Traits::low(result, lead);
+ data += 1;
+ }
+ // surrogate pair lead
+ else if ((unsigned)(lead - 0xD800) < 0x400 && data + 1 < end)
+ {
+ char16_t next = swap ? endian_swap(data[1]) : data[1];
+
+ if ((unsigned)(next - 0xDC00) < 0x400)
+ {
+ result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
+ data += 2;
+ }
+ else
+ {
+ data += 1;
+ }
+ }
+ else
+ {
+ data += 1;
+ }
+ }
+
+ return result;
+ }
+
+ template <typename Traits, typename opt1> static inline typename Traits::value_type decode_utf32_block(const char32_t* data, size_t size, typename Traits::value_type result, opt1, Traits = Traits())
+ {
+ const bool swap = opt1::o1;
+
+ const char32_t* end = data + size;
+
+ while (data < end)
+ {
+ char32_t lead = swap ? endian_swap(*data) : *data;
+
+ // U+0000..U+FFFF
+ if (lead < 0x10000)
+ {
+ result = Traits::low(result, lead);
+ data += 1;
+ }
+ // U+10000..U+10FFFF
+ else
+ {
+ result = Traits::high(result, lead);
+ data += 1;
+ }
+ }
+
+ return result;
+ }
+
+ template <typename T> inline void convert_utf_endian_swap(T* result, const T* data, size_t length)
+ {
+ for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]);
+ }
+
+ inline void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
+ {
+ for (size_t i = 0; i < length; ++i) result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
+ }
+ }
+}
+
+#endif
+
+/**
+ * Copyright (c) 2006-2009 Arseny Kapoulkine
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 1bd6c68..d67919b 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -13,23 +13,27 @@
#include "pugixml.hpp"
+#if !defined(PUGIXML_NO_XPATH) && defined(PUGIXML_NO_EXCEPTIONS)
+#error No exception mode can not be used with XPath support
+#endif
+
+#include "pugiutf.hpp"
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
-
-// For placement new
-#include <new>
-
-#if !defined(PUGIXML_NO_XPATH) && defined(PUGIXML_NO_EXCEPTIONS)
-#error No exception mode can not be used with XPath support
-#endif
+#include <wchar.h>
#ifndef PUGIXML_NO_STL
# include <istream>
# include <ostream>
+# include <string>
#endif
+// For placement new
+#include <new>
+
#ifdef _MSC_VER
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4996) // this function or variable may be unsafe
@@ -48,6 +52,7 @@ using std::memcpy;
#define STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
+// Memory allocation
namespace
{
void* default_allocate(size_t size)
@@ -64,6 +69,155 @@ namespace
pugi::deallocation_function global_deallocate = default_deallocate;
}
+// String utilities prototypes
+namespace pugi
+{
+ namespace impl
+ {
+ size_t strlen(const char_t* s);
+ void strcpy(char_t* dst, const char_t* src);
+ bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count);
+ void widen_ascii(wchar_t* dest, const char* source);
+ }
+}
+
+// String utilities
+namespace pugi
+{
+ namespace impl
+ {
+ // Get string length
+ size_t strlen(const char_t* s)
+ {
+ #ifdef PUGIXML_WCHAR_MODE
+ return wcslen(s);
+ #else
+ return ::strlen(s);
+ #endif
+ }
+
+ // Copy one string into another
+ void strcpy(char_t* dst, const char_t* src)
+ {
+ #ifdef PUGIXML_WCHAR_MODE
+ wcscpy(dst, src);
+ #else
+ ::strcpy(dst, src);
+ #endif
+ }
+
+ // Compare two strings
+ bool PUGIXML_FUNCTION strequal(const char_t* src, const char_t* dst)
+ {
+ #ifdef PUGIXML_WCHAR_MODE
+ return wcscmp(src, dst) == 0;
+ #else
+ return strcmp(src, dst) == 0;
+ #endif
+ }
+
+ // Compare lhs with [rhs_begin, rhs_end)
+ bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
+ {
+ for (size_t i = 0; i < count; ++i)
+ if (lhs[i] != rhs[i])
+ return false;
+
+ return true;
+ }
+
+ // Character set pattern match.
+ static bool strequalwild_cset(const char_t** src, const char_t** dst)
+ {
+ int find = 0, excl = 0, star = 0;
+
+ if (**src == '!')
+ {
+ excl = 1;
+ ++(*src);
+ }
+
+ while (**src != ']' || star == 1)
+ {
+ if (find == 0)
+ {
+ if (**src == '-' && *(*src-1) < *(*src+1) && *(*src+1) != ']' && star == 0)
+ {
+ if (**dst >= *(*src-1) && **dst <= *(*src+1))
+ {
+ find = 1;
+ ++(*src);
+ }
+ }
+ else if (**src == **dst) find = 1;
+ }
+ ++(*src);
+ star = 0;
+ }
+
+ if (excl == 1) find = (1 - find);
+ if (find == 1) ++(*dst);
+
+ return find == 0;
+ }
+
+ // Wildcard pattern match.
+ static bool strequalwild_astr(const char_t** src, const char_t** dst)
+ {
+ int find = 1;
+ ++(*src);
+ while ((**dst != 0 && **src == '?') || **src == '*')
+ {
+ if(**src == '?') ++(*dst);
+ ++(*src);
+ }
+ while (**src == '*') ++(*src);
+ if (**dst == 0 && **src != 0) return 0;
+ if (**dst == 0 && **src == 0) return 1;
+ else
+ {
+ if (!impl::strequalwild(*src,*dst))
+ {
+ do
+ {
+ ++(*dst);
+ while(**src != **dst && **src != '[' && **dst != 0)
+ ++(*dst);
+ }
+ while ((**dst != 0) ? !impl::strequalwild(*src,*dst) : 0 != (find=0));
+ }
+ if (**dst == 0 && **src == 0) find = 1;
+ return find == 0;
+ }
+ }
+
+ // Compare two strings, with globbing, and character sets.
+ bool PUGIXML_FUNCTION strequalwild(const char_t* src, const char_t* dst)
+ {
+ int find = 1;
+ for(; *src != 0 && find == 1 && *dst != 0; ++src)
+ {
+ switch (*src)
+ {
+ case '?': ++dst; break;
+ case '[': ++src; find = !strequalwild_cset(&src,&dst); break;
+ case '*': find = !strequalwild_astr(&src,&dst); --src; break;
+ default : find = (int) (*src == *dst); ++dst;
+ }
+ }
+ while (*src == '*' && find == 1) ++src;
+ return (find == 1 && *dst == 0 && *src == 0);
+ }
+
+ // Convert string to wide string, assuming all symbols are ASCII
+ void widen_ascii(wchar_t* dest, const char* source)
+ {
+ for (const char* i = source; *i; ++i) *dest++ = *i;
+ *dest = 0;
+ }
+ }
+}
+
namespace pugi
{
struct xml_document_struct;
@@ -131,8 +285,8 @@ namespace pugi
unsigned int name_allocated : 1;
unsigned int value_allocated : 1;
- char* name; ///< Pointer to attribute name.
- char* value; ///< Pointer to attribute value.
+ char_t* name; ///< Pointer to attribute name.
+ char_t* value; ///< Pointer to attribute value.
xml_attribute_struct* prev_attribute; ///< Previous attribute
xml_attribute_struct* next_attribute; ///< Next attribute
@@ -208,8 +362,8 @@ namespace pugi
xml_node_struct* parent; ///< Pointer to parent
- char* name; ///< Pointer to element name.
- char* value; ///< Pointer to any associated string data.
+ char_t* name; ///< Pointer to element name.
+ char_t* value; ///< Pointer to any associated string data.
xml_node_struct* first_child; ///< First child
xml_node_struct* last_child; ///< Last child
@@ -228,7 +382,7 @@ namespace pugi
}
xml_allocator allocator;
- const char* buffer;
+ const char_t* buffer;
};
xml_document_struct* xml_allocator::allocate_document()
@@ -251,12 +405,7 @@ namespace
{
using namespace pugi;
- const unsigned char UTF8_BYTE_MASK = 0xBF;
- const unsigned char UTF8_BYTE_MARK = 0x80;
- const unsigned char UTF8_BYTE_MASK_READ = 0x3F;
- const unsigned char UTF8_FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
- enum chartype
+ enum chartype_t
{
ct_parse_pcdata = 1, // \0, &, \r, <
ct_parse_attr = 2, // \0, &, \r, ', "
@@ -288,182 +437,394 @@ namespace
192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
};
-
- inline bool is_chartype(char c, chartype ct)
+
+ inline bool is_chartype(char_t c, chartype_t ct)
{
+ #ifdef PUGIXML_WCHAR_MODE
+ unsigned int ch = static_cast<unsigned int>(c);
+
+ return !!((ch < 128 ? chartype_table[ch] : chartype_table[128]) & ct);
+ #else
return !!(chartype_table[static_cast<unsigned char>(c)] & ct);
+ #endif
+ }
+
+ enum output_chartype_t
+ {
+ oct_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
+ oct_special_attr = 2 // Any symbol >= 0 and < 32 (except \t), &, <, >, "
+ };
+
+ const unsigned char output_chartype_table[256] =
+ {
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
+ 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, // 48-63
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64-128
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ inline bool is_output_chartype(char_t c, output_chartype_t ct)
+ {
+ #ifdef PUGIXML_WCHAR_MODE
+ unsigned int ch = static_cast<unsigned int>(c);
+
+ return !!((ch < 128 ? output_chartype_table[ch] : output_chartype_table[128]) & ct);
+ #else
+ return !!(output_chartype_table[static_cast<unsigned char>(c)] & ct);
+ #endif
+ }
+
+ template <bool _1> struct opt1_to_type
+ {
+ static const bool o1;
+ };
+
+ template <bool _1> const bool opt1_to_type<_1>::o1 = _1;
+
+ template <bool _1, bool _2> struct opt2_to_type
+ {
+ static const bool o1;
+ static const bool o2;
+ };
+
+ template <bool _1, bool _2> const bool opt2_to_type<_1, _2>::o1 = _1;
+ template <bool _1, bool _2> const bool opt2_to_type<_1, _2>::o2 = _2;
+
+ template <bool _1, bool _2, bool _3, bool _4> struct opt4_to_type
+ {
+ static const bool o1;
+ static const bool o2;
+ static const bool o3;
+ static const bool o4;
+ };
+
+ template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o1 = _1;
+ template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o2 = _2;
+ template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o3 = _3;
+ template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o4 = _4;
+
+ bool is_little_endian()
+ {
+ unsigned int ui = 1;
+
+ return *reinterpret_cast<unsigned char*>(&ui) == 1;
}
- bool strcpy_insitu(char*& dest, bool& allocated, const char* source)
+ encoding_t get_wchar_encoding()
{
- size_t source_size = strlen(source);
+ STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
+
+ if (sizeof(wchar_t) == 2)
+ return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+ else
+ return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+ }
+
+ encoding_t get_buffer_encoding(encoding_t encoding, const void* contents, size_t size)
+ {
+ // replace wchar encoding with utf implementation
+ if (encoding == encoding_wchar) return get_wchar_encoding();
+
+ // replace utf16 encoding with utf16 with specific endianness
+ if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
- if (dest && strlen(dest) >= source_size)
+ // replace utf32 encoding with utf32 with specific endianness
+ if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+ // only do autodetection if no explicit encoding is requested
+ if (encoding != encoding_auto) return encoding;
+
+ // try to guess encoding (based on XML specification, Appendix F.1)
+ const impl::char8_t* data = static_cast<const impl::char8_t*>(contents);
+
+ // look for BOM in first few bytes
+ if (size > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0xfe && data[3] == 0xff) return encoding_utf32_be;
+ if (size > 4 && data[0] == 0xff && data[1] == 0xfe && data[2] == 0 && data[3] == 0) return encoding_utf32_le;
+ if (size > 2 && data[0] == 0xfe && data[1] == 0xff) return encoding_utf16_be;
+ if (size > 2 && data[0] == 0xff && data[1] == 0xfe) return encoding_utf16_le;
+ if (size > 3 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf) return encoding_utf8;
+
+ // look for <, <? or <?xm in various encodings
+ if (size > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0x3c) return encoding_utf32_be;
+ if (size > 4 && data[0] == 0x3c && data[1] == 0 && data[2] == 0 && data[3] == 0) return encoding_utf32_le;
+ if (size > 4 && data[0] == 0 && data[1] == 0x3c && data[2] == 0 && data[3] == 0x3f) return encoding_utf16_be;
+ if (size > 4 && data[0] == 0x3c && data[1] == 0 && data[2] == 0x3f && data[3] == 0) return encoding_utf16_le;
+ if (size > 4 && data[0] == 0x3c && data[1] == 0x3f && data[2] == 0x78 && data[3] == 0x6d) return encoding_utf8;
+
+ // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
+ if (size > 2 && data[0] == 0 && data[1] == 0x3c) return encoding_utf16_be;
+ if (size > 2 && data[0] == 0x3c && data[1] == 0) return encoding_utf16_le;
+
+ // no known BOM detected, assume utf8
+ return encoding_utf8;
+ }
+
+ bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
+ {
+ if (is_mutable)
{
- strcpy(dest, source);
-
- return true;
+ out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
}
else
{
- char* buf = static_cast<char*>(global_allocate(source_size + 1));
- if (!buf) return false;
-
- strcpy(buf, source);
+ void* buffer = global_allocate(size > 0 ? size : 1);
+ if (!buffer) return false;
- if (allocated) global_deallocate(dest);
-
- dest = buf;
- allocated = true;
+ memcpy(buffer, contents, size);
- return true;
+ out_buffer = static_cast<char_t*>(buffer);
}
+
+ out_length = size / sizeof(char_t);
+
+ return true;
+ }
+
+#ifdef PUGIXML_WCHAR_MODE
+ inline bool need_endian_swap_utf(encoding_t le, encoding_t re)
+ {
+ return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
+ (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
}
- // Get the size that is needed for strutf16_utf8 applied to all s characters
- size_t strutf16_utf8_size(const wchar_t* s)
+ bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
{
- size_t length = 0;
+ const char_t* data = static_cast<const char_t*>(contents);
+
+ out_buffer = is_mutable ? const_cast<char_t*>(data) : static_cast<char_t*>(global_allocate(size > 0 ? size : 1));
+ out_length = size / sizeof(char_t);
- for (; *s; ++s)
- {
- unsigned int ch = *s;
+ if (!out_buffer) return false;
- if (ch < 0x80) length += 1;
- else if (ch < 0x800) length += 2;
- else if (ch < 0x10000) length += 3;
- else if (ch < 0x200000) length += 4;
- }
+ impl::convert_wchar_endian_swap(out_buffer, data, out_length);
- return length;
+ return true;
}
- // Write utf16 char to stream, return position after the last written char
- // \return position after last char
- char* strutf16_utf8(char* s, unsigned int ch)
+ bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
{
- unsigned int length;
+ const impl::char8_t* data = static_cast<const impl::char8_t*>(contents);
- if (ch < 0x80) length = 1;
- else if (ch < 0x800) length = 2;
- else if (ch < 0x10000) length = 3;
- else if (ch < 0x200000) length = 4;
- else return s;
-
- s += length;
+ // first pass: get length in wchar_t units
+ out_length = impl::decode_utf8_block<impl::wchar_counter>(data, size, 0);
- // Scary scary fall throughs.
- switch (length)
- {
- case 4:
- *--s = (char)((ch | UTF8_BYTE_MARK) & UTF8_BYTE_MASK);
- ch >>= 6;
- case 3:
- *--s = (char)((ch | UTF8_BYTE_MARK) & UTF8_BYTE_MASK);
- ch >>= 6;
- case 2:
- *--s = (char)((ch | UTF8_BYTE_MARK) & UTF8_BYTE_MASK);
- ch >>= 6;
- case 1:
- *--s = (char)(ch | UTF8_FIRST_BYTE_MARK[length]);
- }
-
- return s + length;
+ // allocate buffer of suitable length
+ out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+ if (!out_buffer) return false;
+
+ // second pass: convert utf8 input to wchar_t
+ impl::wchar_writer::value_type out_begin = reinterpret_cast<impl::wchar_writer::value_type>(out_buffer);
+ impl::wchar_writer::value_type out_end = impl::decode_utf8_block<impl::wchar_writer>(data, size, out_begin);
+
+ assert(out_end == out_begin + out_length);
+ (void)!out_end;
+
+ return true;
}
- // Get the size that is needed for strutf8_utf16 applied to all s characters
- size_t strutf8_utf16_size(const char* s)
+ template <typename opt1> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt1)
{
- size_t length = 0;
+ const impl::char16_t* data = static_cast<const impl::char16_t*>(contents);
+ size_t length = size / sizeof(impl::char16_t);
- for (; *s; ++s)
- {
- unsigned char ch = static_cast<unsigned char>(*s);
+ // first pass: get length in wchar_t units
+ out_length = impl::decode_utf16_block<impl::wchar_counter>(data, length, 0, opt1());
- if (ch < 0x80 || (ch >= 0xC0 && ch < 0xFC)) ++length;
- }
+ // allocate buffer of suitable length
+ out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+ if (!out_buffer) return false;
- return length;
+ // second pass: convert utf16 input to wchar_t
+ impl::wchar_writer::value_type out_begin = reinterpret_cast<impl::wchar_writer::value_type>(out_buffer);
+ impl::wchar_writer::value_type out_end = impl::decode_utf16_block<impl::wchar_writer>(data, length, out_begin, opt1());
+
+ assert(out_end == out_begin + out_length);
+ (void)!out_end;
+
+ return true;
}
- // Read utf16 char from utf8 stream, return position after the last read char
- // \return position after the last char
- const char* strutf8_utf16(const char* s, unsigned int& ch)
+ template <typename opt1> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt1)
{
- unsigned int length;
+ const impl::char32_t* data = static_cast<const impl::char32_t*>(contents);
+ size_t length = size / sizeof(impl::char32_t);
+
+ // first pass: get length in wchar_t units
+ out_length = impl::decode_utf32_block<impl::wchar_counter>(data, length, 0, opt1());
+
+ // allocate buffer of suitable length
+ out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+ if (!out_buffer) return false;
- const unsigned char* str = reinterpret_cast<const unsigned char*>(s);
+ // second pass: convert utf32 input to wchar_t
+ impl::wchar_writer::value_type out_begin = reinterpret_cast<impl::wchar_writer::value_type>(out_buffer);
+ impl::wchar_writer::value_type out_end = impl::decode_utf32_block<impl::wchar_writer>(data, length, out_begin, opt1());
- if (*str < UTF8_BYTE_MARK)
+ assert(out_end == out_begin + out_length);
+ (void)!out_end;
+
+ return true;
+ }
+
+ bool convert_buffer(char_t*& out_buffer, size_t& out_length, encoding_t encoding, const void* contents, size_t size, bool is_mutable)
+ {
+ // get native encoding
+ encoding_t wchar_encoding = get_wchar_encoding();
+
+ // fast path: no conversion required
+ if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
+
+ // only endian-swapping is required
+ if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
+
+ // source encoding is utf8
+ if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size);
+
+ // source encoding is utf16
+ if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
{
- ch = *str;
- return s + 1;
+ encoding_t native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+ return (native_encoding == encoding) ?
+ convert_buffer_utf16(out_buffer, out_length, contents, size, opt1_to_type<false>()) :
+ convert_buffer_utf16(out_buffer, out_length, contents, size, opt1_to_type<true>());
}
- else if (*str < 0xC0)
+
+ // source encoding is utf32
+ if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
{
- ch = ' ';
- return s + 1;
+ encoding_t native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+ return (native_encoding == encoding) ?
+ convert_buffer_utf32(out_buffer, out_length, contents, size, opt1_to_type<false>()) :
+ convert_buffer_utf32(out_buffer, out_length, contents, size, opt1_to_type<true>());
}
- else if (*str < 0xE0) length = 2;
- else if (*str < 0xF0) length = 3;
- else if (*str < 0xF8) length = 4;
- else
+
+ // invalid encoding combination (this can't happen)
+ assert(false);
+
+ return false;
+ }
+#else
+ template <typename opt1> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt1)
+ {
+ const impl::char16_t* data = static_cast<const impl::char16_t*>(contents);
+ size_t length = size / sizeof(impl::char16_t);
+
+ // first pass: get length in utf8 units
+ out_length = impl::decode_utf16_block<impl::utf8_counter>(data, length, 0, opt1());
+
+ // allocate buffer of suitable length
+ out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+ if (!out_buffer) return false;
+
+ // second pass: convert utf16 input to utf8
+ impl::char8_t* out_begin = reinterpret_cast<impl::char8_t*>(out_buffer);
+ impl::char8_t* out_end = impl::decode_utf16_block<impl::utf8_writer>(data, length, out_begin, opt1());
+
+ assert(out_end == out_begin + out_length);
+ (void)!out_end;
+
+ return true;
+ }
+
+ template <typename opt1> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt1)
+ {
+ const impl::char32_t* data = static_cast<const impl::char32_t*>(contents);
+ size_t length = size / sizeof(impl::char32_t);
+
+ // first pass: get length in utf8 units
+ out_length = impl::decode_utf32_block<impl::utf8_counter>(data, length, 0, opt1());
+
+ // allocate buffer of suitable length
+ out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+ if (!out_buffer) return false;
+
+ // second pass: convert utf32 input to utf8
+ impl::char8_t* out_begin = reinterpret_cast<impl::char8_t*>(out_buffer);
+ impl::char8_t* out_end = impl::decode_utf32_block<impl::utf8_writer>(data, length, out_begin, opt1());
+
+ assert(out_end == out_begin + out_length);
+ (void)!out_end;
+
+ return true;
+ }
+
+ bool convert_buffer(char_t*& out_buffer, size_t& out_length, encoding_t encoding, const void* contents, size_t size, bool is_mutable)
+ {
+ // fast path: no conversion required
+ if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
+
+ // source encoding is utf16
+ if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
{
- ch = ' ';
- return s + 1;
+ encoding_t native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+ return (native_encoding == encoding) ?
+ convert_buffer_utf16(out_buffer, out_length, contents, size, opt1_to_type<false>()) :
+ convert_buffer_utf16(out_buffer, out_length, contents, size, opt1_to_type<true>());
}
- ch = (*str++ & ~UTF8_FIRST_BYTE_MARK[length]);
-
- // Scary scary fall throughs.
- switch (length)
+ // source encoding is utf32
+ if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
{
- case 4:
- ch <<= 6;
- ch += (*str++ & UTF8_BYTE_MASK_READ);
- case 3:
- ch <<= 6;
- ch += (*str++ & UTF8_BYTE_MASK_READ);
- case 2:
- ch <<= 6;
- ch += (*str++ & UTF8_BYTE_MASK_READ);
+ encoding_t native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+ return (native_encoding == encoding) ?
+ convert_buffer_utf32(out_buffer, out_length, contents, size, opt1_to_type<false>()) :
+ convert_buffer_utf32(out_buffer, out_length, contents, size, opt1_to_type<true>());
}
-
- return reinterpret_cast<const char*>(str);
- }
- template <bool _1> struct opt1_to_type
- {
- static const bool o1;
- };
+ // invalid encoding combination (this can't happen)
+ assert(false);
- template <bool _1> const bool opt1_to_type<_1>::o1 = _1;
+ return false;
+ }
+#endif
- template <bool _1, bool _2> struct opt2_to_type
+ bool strcpy_insitu(char_t*& dest, bool& allocated, const char_t* source)
{
- static const bool o1;
- static const bool o2;
- };
+ size_t source_length = impl::strlen(source);
- template <bool _1, bool _2> const bool opt2_to_type<_1, _2>::o1 = _1;
- template <bool _1, bool _2> const bool opt2_to_type<_1, _2>::o2 = _2;
+ if (dest && impl::strlen(dest) >= source_length)
+ {
+ impl::strcpy(dest, source);
+
+ return true;
+ }
+ else
+ {
+ char_t* buf = static_cast<char_t*>(global_allocate((source_length + 1) * sizeof(char_t)));
+ if (!buf) return false;
- template <bool _1, bool _2, bool _3, bool _4> struct opt4_to_type
- {
- static const bool o1;
- static const bool o2;
- static const bool o3;
- static const bool o4;
- };
+ impl::strcpy(buf, source);
- template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o1 = _1;
- template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o2 = _2;
- template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o3 = _3;
- template <bool _1, bool _2, bool _3, bool _4> const bool opt4_to_type<_1, _2, _3, _4>::o4 = _4;
+ if (allocated) global_deallocate(dest);
+
+ dest = buf;
+ allocated = true;
+
+ return true;
+ }
+ }
struct gap
{
- char* end;
+ char_t* end;
size_t size;
gap(): end(0), size(0)
@@ -472,12 +833,12 @@ namespace
// Push new gap, move s count bytes further (skipping the gap).
// Collapse previous gap.
- void push(char*& s, size_t count)
+ void push(char_t*& s, size_t count)
{
if (end) // there was a gap already; collapse it
{
// Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
- memmove(end - size, end, s - end);
+ memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
}
s += count; // end of current gap
@@ -488,12 +849,12 @@ namespace
}
// Collapse all gaps, return past-the-end pointer
- char* flush(char* s)
+ char_t* flush(char_t* s)
{
if (end)
{
// Move [old_gap_end, current_pos) to [old_gap_start, ...)
- memmove(end - size, end, s - end);
+ memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
return s - size;
}
@@ -501,9 +862,9 @@ namespace
}
};
- char* strconv_escape(char* s, gap& g)
+ char_t* strconv_escape(char_t* s, gap& g)
{
- char* stre = s + 1;
+ char_t* stre = s + 1;
switch (*stre)
{
@@ -545,7 +906,11 @@ namespace
++stre;
}
- s = strutf16_utf8(s, ucsc);
+ #ifdef PUGIXML_WCHAR_MODE
+ s = reinterpret_cast<char_t*>(impl::wchar_writer::any(reinterpret_cast<impl::wchar_writer::value_type>(s), ucsc));
+ #else
+ s = reinterpret_cast<char_t*>(impl::utf8_writer::any(reinterpret_cast<impl::char8_t*>(s), ucsc));
+ #endif
g.push(s, stre - s);
return stre;
@@ -619,7 +984,10 @@ namespace
return stre;
}
- char* strconv_comment(char* s)
+ // Utility macro for last character handling
+ #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
+
+ char_t* strconv_comment(char_t* s, char_t endch)
{
if (!*s) return 0;
@@ -635,11 +1003,11 @@ namespace
if (*s == '\n') g.push(s, 1);
}
- else if (*s == '-' && *(s+1) == '-' && *(s+2) == '>') // comment ends here
+ else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here
{
*g.flush(s) = 0;
- return s + 3;
+ return s + (s[2] == '>' ? 3 : 2);
}
else if (*s == 0)
{
@@ -649,7 +1017,7 @@ namespace
}
}
- char* strconv_cdata(char* s)
+ char_t* strconv_cdata(char_t* s, char_t endch)
{
if (!*s) return 0;
@@ -665,7 +1033,7 @@ namespace
if (*s == '\n') g.push(s, 1);
}
- else if (*s == ']' && *(s+1) == ']' && *(s+2) == '>') // CDATA ends here
+ else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here
{
*g.flush(s) = 0;
@@ -678,170 +1046,176 @@ namespace
else ++s;
}
}
+
+ typedef char_t* (*strconv_pcdata_t)(char_t*);
- template <typename opt2> char* strconv_pcdata_t(char* s, opt2)
+ template <typename opt2> struct strconv_pcdata_impl
{
- assert(*s);
-
- const bool opt_eol = opt2::o1;
- const bool opt_escape = opt2::o2;
-
- gap g;
-
- while (true)
+ static char_t* parse(char_t* s)
{
- while (!is_chartype(*s, ct_parse_pcdata)) ++s;
-
- if (*s == '<') // PCDATA ends here
- {
- *g.flush(s) = 0;
-
- return s + 1;
- }
- else if (opt_eol && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
- {
- *s++ = '\n'; // replace first one with 0x0a
-
- if (*s == '\n') g.push(s, 1);
- }
- else if (opt_escape && *s == '&')
- {
- s = strconv_escape(s, g);
- }
- else if (*s == 0)
+ const bool opt_eol = opt2::o1;
+ const bool opt_escape = opt2::o2;
+
+ gap g;
+
+ while (true)
{
- return s;
+ while (!is_chartype(*s, ct_parse_pcdata)) ++s;
+
+ if (*s == '<') // PCDATA ends here
+ {
+ *g.flush(s) = 0;
+
+ return s + 1;
+ }
+ else if (opt_eol && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
+ {
+ *s++ = '\n'; // replace first one with 0x0a
+
+ if (*s == '\n') g.push(s, 1);
+ }
+ else if (opt_escape && *s == '&')
+ {
+ s = strconv_escape(s, g);
+ }
+ else if (*s == 0)
+ {
+ return s;
+ }
+ else ++s;
}
- else ++s;
}
- }
-
- char* strconv_pcdata(char* s, unsigned int optmask)
+ };
+
+ strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
{
STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20);
switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes)
{
- case 0: return strconv_pcdata_t(s, opt2_to_type<0, 0>());
- case 1: return strconv_pcdata_t(s, opt2_to_type<0, 1>());
- case 2: return strconv_pcdata_t(s, opt2_to_type<1, 0>());
- case 3: return strconv_pcdata_t(s, opt2_to_type<1, 1>());
+ case 0: return strconv_pcdata_impl<opt2_to_type<0, 0> >::parse;
+ case 1: return strconv_pcdata_impl<opt2_to_type<0, 1> >::parse;
+ case 2: return strconv_pcdata_impl<opt2_to_type<1, 0> >::parse;
+ case 3: return strconv_pcdata_impl<opt2_to_type<1, 1> >::parse;
default: return 0; // should not get here
}
}
- template <typename opt4> char* strconv_attribute_t(char* s, char end_quote, opt4)
+ typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
+
+ template <typename opt4> struct strconv_attribute_impl
{
- const bool opt_wconv = opt4::o1;
- const bool opt_wnorm = opt4::o2;
- const bool opt_eol = opt4::o3;
- const bool opt_escape = opt4::o4;
-
- if (!*s) return 0;
-
- gap g;
-
- // trim leading whitespaces
- if (opt_wnorm && is_chartype(*s, ct_space))
+ static char_t* parse(char_t* s, char_t end_quote)
{
- char* str = s;
-
- do ++str;
- while (is_chartype(*str, ct_space));
-
- g.push(s, str - s);
- }
+ const bool opt_wconv = opt4::o1;
+ const bool opt_wnorm = opt4::o2;
+ const bool opt_eol = opt4::o3;
+ const bool opt_escape = opt4::o4;
- while (true)
- {
- while (!is_chartype(*s, (opt_wnorm || opt_wconv) ? ct_parse_attr_ws : ct_parse_attr)) ++s;
-
- if (*s == end_quote)
+ gap g;
+
+ // trim leading whitespaces
+ if (opt_wnorm && is_chartype(*s, ct_space))
{
- char* str = g.flush(s);
+ char_t* str = s;
- if (opt_wnorm)
- {
- do *str-- = 0;
- while (is_chartype(*str, ct_space));
- }
- else *str = 0;
-
- return s + 1;
+ do ++str;
+ while (is_chartype(*str, ct_space));
+
+ g.push(s, str - s);
}
- else if (opt_wnorm && is_chartype(*s, ct_space))
+
+ while (true)
{
- *s++ = ' ';
-
- if (is_chartype(*s, ct_space))
+ while (!is_chartype(*s, (opt_wnorm || opt_wconv) ? ct_parse_attr_ws : ct_parse_attr)) ++s;
+
+ if (*s == end_quote)
{
- char* str = s + 1;
- while (is_chartype(*str, ct_space)) ++str;
+ char_t* str = g.flush(s);
- g.push(s, str - s);
+ if (opt_wnorm)
+ {
+ do *str-- = 0;
+ while (is_chartype(*str, ct_space));
+ }
+ else *str = 0;
+
+ return s + 1;
}
- }
- else if (opt_wconv && is_chartype(*s, ct_space))
- {
- if (opt_eol)
+ else if (opt_wnorm && is_chartype(*s, ct_space))
{
- if (*s == '\r')
+ *s++ = ' ';
+
+ if (is_chartype(*s, ct_space))
{
- *s++ = ' ';
-
- if (*s == '\n') g.push(s, 1);
+ char_t* str = s + 1;
+ while (is_chartype(*str, ct_space)) ++str;
+
+ g.push(s, str - s);
+ }
+ }
+ else if (opt_wconv && is_chartype(*s, ct_space))
+ {
+ if (opt_eol)
+ {
+ if (*s == '\r')
+ {
+ *s++ = ' ';
+
+ if (*s == '\n') g.push(s, 1);
+ }
+ else *s++ = ' ';
}
else *s++ = ' ';
}
- else *s++ = ' ';
- }
- else if (opt_eol && *s == '\r')
- {
- *s++ = '\n';
-
- if (*s == '\n') g.push(s, 1);
- }
- else if (opt_escape && *s == '&')
- {
- s = strconv_escape(s, g);
- }
- else if (!*s)
- {
- return 0;
+ else if (opt_eol && *s == '\r')
+ {
+ *s++ = '\n';
+
+ if (*s == '\n') g.push(s, 1);
+ }
+ else if (opt_escape && *s == '&')
+ {
+ s = strconv_escape(s, g);
+ }
+ else if (!*s)
+ {
+ return 0;
+ }
+ else ++s;
}
- else ++s;
}
- }
+ };
- char* strconv_attribute(char* s, char end_quote, unsigned int optmask)
+ strconv_attribute_t get_strconv_attribute(unsigned int optmask)
{
STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wnorm_attribute == 0x40 && parse_wconv_attribute == 0x80);
switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes)
{
- case 0: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 0, 0, 0>());
- case 1: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 0, 0, 1>());
- case 2: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 0, 1, 0>());
- case 3: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 0, 1, 1>());
- case 4: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 1, 0, 0>());
- case 5: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 1, 0, 1>());
- case 6: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 1, 1, 0>());
- case 7: return strconv_attribute_t(s, end_quote, opt4_to_type<0, 1, 1, 1>());
- case 8: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 0, 0, 0>());
- case 9: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 0, 0, 1>());
- case 10: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 0, 1, 0>());
- case 11: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 0, 1, 1>());
- case 12: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 1, 0, 0>());
- case 13: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 1, 0, 1>());
- case 14: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 1, 1, 0>());
- case 15: return strconv_attribute_t(s, end_quote, opt4_to_type<1, 1, 1, 1>());
+ case 0: return strconv_attribute_impl<opt4_to_type<0, 0, 0, 0> >::parse;
+ case 1: return strconv_attribute_impl<opt4_to_type<0, 0, 0, 1> >::parse;
+ case 2: return strconv_attribute_impl<opt4_to_type<0, 0, 1, 0> >::parse;
+ case 3: return strconv_attribute_impl<opt4_to_type<0, 0, 1, 1> >::parse;
+ case 4: return strconv_attribute_impl<opt4_to_type<0, 1, 0, 0> >::parse;
+ case 5: return strconv_attribute_impl<opt4_to_type<0, 1, 0, 1> >::parse;
+ case 6: return strconv_attribute_impl<opt4_to_type<0, 1, 1, 0> >::parse;
+ case 7: return strconv_attribute_impl<opt4_to_type<0, 1, 1, 1> >::parse;
+ case 8: return strconv_attribute_impl<opt4_to_type<1, 0, 0, 0> >::parse;
+ case 9: return strconv_attribute_impl<opt4_to_type<1, 0, 0, 1> >::parse;
+ case 10: return strconv_attribute_impl<opt4_to_type<1, 0, 1, 0> >::parse;
+ case 11: return strconv_attribute_impl<opt4_to_type<1, 0, 1, 1> >::parse;
+ case 12: return strconv_attribute_impl<opt4_to_type<1, 1, 0, 0> >::parse;
+ case 13: return strconv_attribute_impl<opt4_to_type<1, 1, 0, 1> >::parse;
+ case 14: return strconv_attribute_impl<opt4_to_type<1, 1, 1, 0> >::parse;
+ case 15: return strconv_attribute_impl<opt4_to_type<1, 1, 1, 1> >::parse;
default: return 0; // should not get here
}
}
inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset, unsigned int line)
{
- xml_parse_result result = {status, offset, line};
+ xml_parse_result result = {status, offset, line, encoding_auto};
return result;
}
@@ -866,11 +1240,11 @@ namespace
{
}
- xml_parse_result parse_exclamation(char*& ref_s, xml_node_struct* cursor, unsigned int optmsk, char* buffer_start)
+ xml_parse_result parse_exclamation(char_t*& ref_s, xml_node_struct* cursor, unsigned int optmsk, char_t* buffer_start, char_t endch)
{
// load into registers
- char* s = ref_s;
- char ch = 0;
+ char_t* s = ref_s;
+ char_t ch = 0;
// parse node contents, starting with exclamation mark
++s;
@@ -891,20 +1265,20 @@ namespace
if (OPTSET(parse_eol) && OPTSET(parse_comments))
{
- s = strconv_comment(s);
+ s = strconv_comment(s, endch);
if (!s) THROW_ERROR(status_bad_comment, cursor->value);
}
else
{
// Scan for terminating '-->'.
- SCANFOR(*s == '-' && *(s+1) == '-' && *(s+2) == '>');
+ SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>'));
CHECK_ERROR(status_bad_comment, s);
if (OPTSET(parse_comments))
*s = 0; // Zero-terminate this segment at the first terminating '-'.
- s += 3; // Step over the '\0->'.
+ s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
}
if (OPTSET(parse_comments))
@@ -928,18 +1302,17 @@ namespace
if (OPTSET(parse_eol))
{
- s = strconv_cdata(s);
+ s = strconv_cdata(s, endch);
if (!s) THROW_ERROR(status_bad_cdata, cursor->value);
}
else
{
// Scan for terminating ']]>'.
- SCANFOR(*s == ']' && *(s+1) == ']' && *(s+2) == '>');
+ SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
CHECK_ERROR(status_bad_cdata, s);
ENDSEG(); // Zero-terminate this segment.
- CHECK_ERROR(status_bad_cdata, s);
}
POPNODE(); // Pop since this is a standalone.
@@ -947,34 +1320,31 @@ namespace
else // Flagged for discard, but we still have to scan for the terminator.
{
// Scan for terminating ']]>'.
- SCANFOR(*s == ']' && *(s+1) == ']' && *(s+2) == '>');
+ SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
CHECK_ERROR(status_bad_cdata, s);
++s;
}
- s += 2; // Step over the last ']>'.
+ s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
}
else THROW_ERROR(status_bad_cdata, s);
}
- else if (*s=='D' && *++s=='O' && *++s=='C' && *++s=='T' && *++s=='Y' && *++s=='P' && *++s=='E')
+ else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E'))
{
- ++s;
-
- SKIPWS(); // Eat any whitespace.
- CHECK_ERROR(status_bad_doctype, s);
+ if (s[6] != 'E') THROW_ERROR(status_bad_doctype, s);
LOC_DOCTYPE:
SCANFOR(*s == '\'' || *s == '"' || *s == '[' || *s == '>');
- CHECK_ERROR(status_bad_doctype, s);
+ if (*s == 0 && endch != '>') THROW_ERROR(status_bad_doctype, s);
if (*s == '\'' || *s == '"') // '...SYSTEM "..."
{
ch = *s++;
SCANFOR(*s == ch);
- CHECK_ERROR(status_bad_doctype, s);
+ if (*s == 0 && endch != '>') THROW_ERROR(status_bad_doctype, s);
- ++s;
+ s += (*s != 0);
goto LOC_DOCTYPE;
}
@@ -989,13 +1359,23 @@ namespace
if (bd == 0) break;
++s;
}
+
+ if (bd != 0) THROW_ERROR(status_bad_doctype, s);
}
SCANFOR(*s == '>');
- CHECK_ERROR(status_bad_doctype, s);
- ++s;
+ if (*s == 0)
+ {
+ if (endch != '>') THROW_ERROR(status_bad_doctype, s);
+ }
+ else
+ {
+ ++s;
+ }
}
+ else if (*s == 0 && endch == '-') THROW_ERROR(status_bad_comment, s);
+ else if (*s == 0 && endch == '[') THROW_ERROR(status_bad_cdata, s);
else THROW_ERROR(status_unrecognized_tag, s);
// store from registers
@@ -1004,12 +1384,12 @@ namespace
THROW_ERROR(status_ok, s);
}
- xml_parse_result parse_question(char*& ref_s, xml_node_struct*& ref_cursor, unsigned int optmsk, char* buffer_start)
+ xml_parse_result parse_question(char_t*& ref_s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t* buffer_start, char_t endch)
{
// load into registers
- char* s = ref_s;
+ char_t* s = ref_s;
xml_node_struct* cursor = ref_cursor;
- char ch = 0;
+ char_t ch = 0;
// parse node contents, starting with question mark
++s;
@@ -1018,7 +1398,7 @@ namespace
THROW_ERROR(status_bad_pi, s);
else if (OPTSET(parse_pi) || OPTSET(parse_declaration))
{
- char* mark = s;
+ char_t* mark = s;
SCANWHILE(is_chartype(*s, ct_symbol)); // Read PI target
CHECK_ERROR(status_bad_pi, s);
@@ -1026,12 +1406,12 @@ namespace
THROW_ERROR(status_bad_pi, s);
ENDSEG();
- CHECK_ERROR(status_bad_pi, s);
+ if (*s == 0 && endch != '>') THROW_ERROR(status_bad_pi, s);
if (ch == '?') // nothing except target present
{
- if (*s != '>') THROW_ERROR(status_bad_pi, s);
- ++s;
+ if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_pi, s);
+ s += (*s == '>');
// stricmp / strcasecmp is not portable
if ((mark[0] == 'x' || mark[0] == 'X') && (mark[1] == 'm' || mark[1] == 'M')
@@ -1068,7 +1448,7 @@ namespace
// scan for tag end
mark = s;
- SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
+ SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); // Look for '?>'.
CHECK_ERROR(status_bad_pi, s);
// replace ending ? with / to terminate properly
@@ -1095,13 +1475,12 @@ namespace
mark = s;
- SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
+ SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); // Look for '?>'.
CHECK_ERROR(status_bad_pi, s);
ENDSEG();
- CHECK_ERROR(status_bad_pi, s);
- ++s; // Step over >
+ s += (*s == '>'); // Step over >
if (OPTSET(parse_pi))
{
@@ -1113,10 +1492,10 @@ namespace
}
else // not parsing PI
{
- SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
+ SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); // Look for '?>'.
CHECK_ERROR(status_bad_pi, s);
- s += 2;
+ s += (s[1] == '>' ? 2 : 1);
}
// store from registers
@@ -1126,19 +1505,16 @@ namespace
THROW_ERROR(status_ok, s);
}
- xml_parse_result parse(char* s, xml_node_struct* xmldoc, unsigned int optmsk = parse_default)
+ xml_parse_result parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch)
{
- if (!s || !xmldoc) return MAKE_PARSE_RESULT(status_internal_error);
-
- char* buffer_start = s;
+ strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
+ strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
+
+ char_t* buffer_start = s;
- // UTF-8 BOM
- if ((unsigned char)*s == 0xEF && (unsigned char)*(s+1) == 0xBB && (unsigned char)*(s+2) == 0xBF)
- s += 3;
-
- char ch = 0;
+ char_t ch = 0;
xml_node_struct* cursor = xmldoc;
- char* mark = s;
+ char_t* mark = s;
while (*s != 0)
{
@@ -1154,8 +1530,6 @@ namespace
cursor->name = s;
SCANWHILE(is_chartype(*s, ct_symbol)); // Scan for a terminator.
- CHECK_ERROR(status_bad_start_element, s);
-
ENDSEG(); // Save char in 'ch', terminate & step over.
if (ch == '>')
@@ -1199,7 +1573,7 @@ namespace
++s; // Step over the quote.
a->value = s; // Save the offset.
- s = strconv_attribute(s, ch, optmsk);
+ s = strconv_attribute(s, ch);
if (!s) THROW_ERROR(status_bad_attribute, a->value);
@@ -1215,14 +1589,19 @@ namespace
else if (*s == '/')
{
++s;
-
- if (*s != '>') THROW_ERROR(status_bad_start_element, s);
-
- POPNODE(); // Pop.
-
- ++s;
-
- break;
+
+ if (*s == '>')
+ {
+ POPNODE();
+ s++;
+ break;
+ }
+ else if (*s == 0 && endch == '>')
+ {
+ POPNODE();
+ break;
+ }
+ else THROW_ERROR(status_bad_start_element, s);
}
else if (*s == '>')
{
@@ -1230,6 +1609,10 @@ namespace
break;
}
+ else if (*s == 0 && endch == '>')
+ {
+ break;
+ }
else THROW_ERROR(status_bad_start_element, s);
}
@@ -1237,11 +1620,18 @@ namespace
}
else if (ch == '/') // '<#.../'
{
- if (*s != '>') THROW_ERROR(status_bad_start_element, s);
+ if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_start_element, s);
POPNODE(); // Pop.
- ++s;
+ s += (*s == '>');
+ }
+ else if (ch == 0)
+ {
+ // we stepped over null terminator, backtrack & handle closing tag
+ --s;
+
+ if (endch != '>') THROW_ERROR(status_bad_start_element, s);
}
else THROW_ERROR(status_bad_start_element, s);
}
@@ -1249,9 +1639,7 @@ namespace
{
++s;
- if (!cursor) THROW_ERROR(status_bad_end_element, s);
-
- char* name = cursor->name;
+ char_t* name = cursor->name;
if (!name) THROW_ERROR(status_end_element_mismatch, s);
while (is_chartype(*s, ct_symbol))
@@ -1259,19 +1647,29 @@ namespace
if (*s++ != *name++) THROW_ERROR(status_end_element_mismatch, s);
}
- if (*name) THROW_ERROR(status_end_element_mismatch, s);
+ if (*name)
+ {
+ if (*s == 0 && name[0] == endch && name[1] == 0) THROW_ERROR(status_bad_end_element, s);
+ else THROW_ERROR(status_end_element_mismatch, s);
+ }
POPNODE(); // Pop.
SKIPWS();
- CHECK_ERROR(status_bad_end_element, s);
- if (*s != '>') THROW_ERROR(status_bad_end_element, s);
- ++s;
+ if (*s == 0)
+ {
+ if (endch != '>') THROW_ERROR(status_bad_end_element, s);
+ }
+ else
+ {
+ if (*s != '>') THROW_ERROR(status_bad_end_element, s);
+ ++s;
+ }
}
else if (*s == '?') // '<?...'
{
- xml_parse_result quest_result = parse_question(s, cursor, optmsk, buffer_start);
+ xml_parse_result quest_result = parse_question(s, cursor, optmsk, buffer_start, endch);
if (!quest_result) return quest_result;
@@ -1279,10 +1677,11 @@ namespace
}
else if (*s == '!') // '<!...'
{
- xml_parse_result excl_result = parse_exclamation(s, cursor, optmsk, buffer_start);
+ xml_parse_result excl_result = parse_exclamation(s, cursor, optmsk, buffer_start, endch);
if (!excl_result) return excl_result;
}
+ else if (*s == 0 && endch == '?') THROW_ERROR(status_bad_pi, s);
else THROW_ERROR(status_unrecognized_tag, s);
}
else
@@ -1291,7 +1690,7 @@ namespace
SKIPWS(); // Eat whitespace if no genuine PCDATA here.
- if ((mark == s || !OPTSET(parse_ws_pcdata)) && (!*s || *s == '<'))
+ if ((!OPTSET(parse_ws_pcdata) || mark == s) && (*s == '<' || !*s))
{
continue;
}
@@ -1303,9 +1702,7 @@ namespace
PUSHNODE(node_pcdata); // Append a new node on the tree.
cursor->value = s; // Save the offset.
- s = strconv_pcdata(s, optmsk);
-
- if (!s) THROW_ERROR(status_bad_pcdata, cursor->value);
+ s = strconv_pcdata(s);
POPNODE(); // Pop since this is a standalone.
@@ -1324,101 +1721,208 @@ namespace
}
}
+ // check that last tag is closed
if (cursor != xmldoc) THROW_ERROR(status_end_element_mismatch, s);
THROW_ERROR(status_ok, s);
}
+
+ static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* xmldoc, unsigned int optmsk)
+ {
+ // store buffer for offset_debug
+ static_cast<xml_document_struct*>(xmldoc)->buffer = buffer;
+
+ // early-out for empty documents
+ if (length == 0) return MAKE_PARSE_RESULT(status_ok);
+
+ // create parser on stack
+ xml_allocator& alloc = static_cast<xml_document_struct*>(xmldoc)->allocator;
+
+ xml_parser parser(alloc);
+
+ // save last character and make buffer zero-terminated (speeds up parsing)
+ char_t endch = buffer[length - 1];
+ buffer[length - 1] = 0;
+
+ // perform actual parsing
+ xml_parse_result result = parser.parse(buffer, xmldoc, optmsk, endch);
+
+ // since we removed last character, we have to handle the only possible false positive
+ if (result && endch == '<')
+ {
+ char_t* buffer_start = buffer;
+
+ // there's no possible well-formed document with < at the end
+ THROW_ERROR(status_unrecognized_tag, buffer_start + length);
+ }
+
+ return result;
+ }
private:
xml_parser(const xml_parser&);
const xml_parser& operator=(const xml_parser&);
};
- // Compare lhs with [rhs_begin, rhs_end)
- int strcmprange(const char* lhs, const char* rhs_begin, const char* rhs_end)
+ // Output facilities
+ encoding_t get_write_native_encoding()
+ {
+ #ifdef PUGIXML_WCHAR_MODE
+ return get_wchar_encoding();
+ #else
+ return encoding_utf8;
+ #endif
+ }
+
+ encoding_t get_write_encoding(encoding_t encoding)
+ {
+ // replace wchar encoding with utf implementation
+ if (encoding == encoding_wchar) return get_wchar_encoding();
+
+ // replace utf16 encoding with utf16 with specific endianness
+ if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+ // replace utf32 encoding with utf32 with specific endianness
+ if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+ // only do autodetection if no explicit encoding is requested
+ if (encoding != encoding_auto) return encoding;
+
+ // assume utf8 encoding
+ return encoding_utf8;
+ }
+
+#ifdef PUGIXML_WCHAR_MODE
+ size_t get_valid_length(const char_t* data, size_t length)
{
- while (*lhs && rhs_begin != rhs_end && *lhs == *rhs_begin)
+ assert(length > 0);
+
+ // discard last character if it's the lead of a surrogate pair
+ return (sizeof(wchar_t) == 2 && (unsigned)(static_cast<impl::char16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
+ }
+
+ size_t convert_buffer(char* result, const char_t* data, size_t length, encoding_t encoding)
+ {
+ // only endian-swapping is required
+ if (need_endian_swap_utf(encoding, get_wchar_encoding()))
{
- ++lhs;
- ++rhs_begin;
+ impl::convert_wchar_endian_swap(reinterpret_cast<char_t*>(result), data, length);
+
+ return length * sizeof(char_t);
}
-
- if (rhs_begin == rhs_end && *lhs == 0) return 0;
- else return 1;
- }
- // Character set pattern match.
- int strcmpwild_cset(const char** src, const char** dst)
- {
- int find = 0, excl = 0, star = 0;
-
- if (**src == '!')
+ // convert to utf8
+ if (encoding == encoding_utf8)
{
- excl = 1;
- ++(*src);
+ impl::char8_t* dest = reinterpret_cast<impl::char8_t*>(result);
+
+ impl::char8_t* end = sizeof(wchar_t) == 2 ?
+ impl::decode_utf16_block<impl::utf8_writer>(reinterpret_cast<const impl::char16_t*>(data), length, dest, opt1_to_type<false>()) :
+ impl::decode_utf32_block<impl::utf8_writer>(reinterpret_cast<const impl::char32_t*>(data), length, dest, opt1_to_type<false>());
+
+ return static_cast<size_t>(end - dest);
}
-
- while (**src != ']' || star == 1)
+
+ // convert to utf16
+ if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
{
- if (find == 0)
- {
- if (**src == '-' && *(*src-1) < *(*src+1) && *(*src+1) != ']' && star == 0)
- {
- if (**dst >= *(*src-1) && **dst <= *(*src+1))
- {
- find = 1;
- ++(*src);
- }
- }
- else if (**src == **dst) find = 1;
- }
- ++(*src);
- star = 0;
+ impl::char16_t* dest = reinterpret_cast<impl::char16_t*>(result);
+
+ // convert to native utf16
+ impl::char16_t* end = impl::decode_utf32_block<impl::utf16_writer>(reinterpret_cast<const impl::char32_t*>(data), length, dest, opt1_to_type<false>());
+
+ // swap if necessary
+ encoding_t native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+ if (native_encoding != encoding) impl::convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+ return static_cast<size_t>(end - dest) * sizeof(impl::char16_t);
}
- if (excl == 1) find = (1 - find);
- if (find == 1) ++(*dst);
-
- return find;
+ // convert to utf32
+ if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
+ {
+ impl::char32_t* dest = reinterpret_cast<impl::char32_t*>(result);
+
+ // convert to native utf32
+ impl::char32_t* end = impl::decode_utf16_block<impl::utf32_writer>(reinterpret_cast<const impl::char16_t*>(data), length, dest, opt1_to_type<false>());
+
+ // swap if necessary
+ encoding_t native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+ if (native_encoding != encoding) impl::convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+ return static_cast<size_t>(end - dest) * sizeof(impl::char32_t);
+ }
+
+ // invalid encoding combination (this can't happen)
+ assert(false);
+
+ return 0;
+ }
+#else
+ size_t get_valid_length(const char_t* data, size_t length)
+ {
+ assert(length > 4);
+
+ for (size_t i = 1; i <= 4; ++i)
+ {
+ impl::char8_t ch = static_cast<impl::char8_t>(data[length - i]);
+
+ // either a standalone character or a leading one
+ if ((ch & 0xc0) != 0x80) return length - i;
+ }
+
+ // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk
+ return length;
}
- // Wildcard pattern match.
- int strcmpwild_astr(const char** src, const char** dst)
+ size_t convert_buffer(char* result, const char_t* data, size_t length, encoding_t encoding)
{
- int find = 1;
- ++(*src);
- while ((**dst != 0 && **src == '?') || **src == '*')
+ if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
{
- if(**src == '?') ++(*dst);
- ++(*src);
+ impl::char16_t* dest = reinterpret_cast<impl::char16_t*>(result);
+
+ // convert to native utf16
+ impl::char16_t* end = impl::decode_utf8_block<impl::utf16_writer>(reinterpret_cast<const impl::char8_t*>(data), length, dest);
+
+ // swap if necessary
+ encoding_t native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+ if (native_encoding != encoding) impl::convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+ return static_cast<size_t>(end - dest) * sizeof(impl::char16_t);
}
- while (**src == '*') ++(*src);
- if (**dst == 0 && **src != 0) return 0;
- if (**dst == 0 && **src == 0) return 1;
- else
+
+ if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
{
- if (impl::strcmpwild(*src,*dst))
- {
- do
- {
- ++(*dst);
- while(**src != **dst && **src != '[' && **dst != 0)
- ++(*dst);
- }
- while ((**dst != 0) ? impl::strcmpwild(*src,*dst) : 0 != (find=0));
- }
- if (**dst == 0 && **src == 0) find = 1;
- return find;
+ impl::char32_t* dest = reinterpret_cast<impl::char32_t*>(result);
+
+ // convert to native utf32
+ impl::char32_t* end = impl::decode_utf8_block<impl::utf32_writer>(reinterpret_cast<const impl::char8_t*>(data), length, dest);
+
+ // swap if necessary
+ encoding_t native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+ if (native_encoding != encoding) impl::convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+ return static_cast<size_t>(end - dest) * sizeof(impl::char32_t);
}
+
+ // invalid encoding combination (this can't happen)
+ assert(false);
+
+ return 0;
}
+#endif
- // Output facilities
- struct xml_buffered_writer
+ class xml_buffered_writer
{
xml_buffered_writer(const xml_buffered_writer&);
xml_buffered_writer& operator=(const xml_buffered_writer&);
- xml_buffered_writer(xml_writer& writer): writer(writer), bufsize(0)
+ public:
+ xml_buffered_writer(xml_writer& writer, encoding_t user_encoding): writer(writer), bufsize(0), encoding(get_write_encoding(user_encoding))
{
}
@@ -1429,56 +1933,188 @@ namespace
void flush()
{
- if (bufsize > 0) writer.write(buffer, bufsize);
+ flush(buffer, bufsize);
bufsize = 0;
}
- void write(const void* data, size_t size)
+ void flush(const char_t* data, size_t size)
{
- if (bufsize + size > sizeof(buffer))
+ if (size == 0) return;
+
+ // fast path, just write data
+ if (encoding == get_write_native_encoding())
+ writer.write(data, size * sizeof(char_t));
+ else
{
+ // convert chunk
+ size_t result = convert_buffer(scratch, data, size, encoding);
+ assert(result <= sizeof(scratch));
+
+ // write data
+ writer.write(scratch, result);
+ }
+ }
+
+ void write(const char_t* data, size_t length)
+ {
+ if (bufsize + length > bufcapacity)
+ {
+ // flush the remaining buffer contents
flush();
- if (size > sizeof(buffer))
+ // handle large chunks
+ if (length > bufcapacity)
{
- writer.write(data, size);
- return;
+ if (encoding == get_write_native_encoding())
+ {
+ // fast path, can just write data chunk
+ writer.write(data, length * sizeof(char_t));
+ return;
+ }
+
+ // need to convert in suitable chunks
+ while (length > bufcapacity)
+ {
+ // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
+ // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
+ size_t chunk_size = get_valid_length(data, bufcapacity);
+
+ // convert chunk and write
+ flush(data, chunk_size);
+
+ // iterate
+ data += chunk_size;
+ length -= chunk_size;
+ }
+
+ // small tail is copied below
+ bufsize = 0;
}
}
- memcpy(buffer + bufsize, data, size);
- bufsize += size;
+ memcpy(buffer + bufsize, data, length * sizeof(char_t));
+ bufsize += length;
+ }
+
+ void write(const char_t* data)
+ {
+ write(data, impl::strlen(data));
+ }
+
+ void write(char_t d0)
+ {
+ if (bufsize + 1 > bufcapacity) flush();
+
+ buffer[bufsize + 0] = d0;
+ bufsize += 1;
+ }
+
+ void write(char_t d0, char_t d1)
+ {
+ if (bufsize + 2 > bufcapacity) flush();
+
+ buffer[bufsize + 0] = d0;
+ buffer[bufsize + 1] = d1;
+ bufsize += 2;
+ }
+
+ void write(char_t d0, char_t d1, char_t d2)
+ {
+ if (bufsize + 3 > bufcapacity) flush();
+
+ buffer[bufsize + 0] = d0;
+ buffer[bufsize + 1] = d1;
+ buffer[bufsize + 2] = d2;
+ bufsize += 3;
}
- void write(const char* data)
+ void write(char_t d0, char_t d1, char_t d2, char_t d3)
{
- write(data, strlen(data));
+ if (bufsize + 4 > bufcapacity) flush();
+
+ buffer[bufsize + 0] = d0;
+ buffer[bufsize + 1] = d1;
+ buffer[bufsize + 2] = d2;
+ buffer[bufsize + 3] = d3;
+ bufsize += 4;
+ }
+
+ void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
+ {
+ if (bufsize + 5 > bufcapacity) flush();
+
+ buffer[bufsize + 0] = d0;
+ buffer[bufsize + 1] = d1;
+ buffer[bufsize + 2] = d2;
+ buffer[bufsize + 3] = d3;
+ buffer[bufsize + 4] = d4;
+ bufsize += 5;
}
- void write(char data)
+ void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
{
- if (bufsize + 1 > sizeof(buffer)) flush();
+ if (bufsize + 6 > bufcapacity) flush();
- buffer[bufsize++] = data;
+ buffer[bufsize + 0] = d0;
+ buffer[bufsize + 1] = d1;
+ buffer[bufsize + 2] = d2;
+ buffer[bufsize + 3] = d3;
+ buffer[bufsize + 4] = d4;
+ buffer[bufsize + 5] = d5;
+ bufsize += 6;
}
+ // utf8 maximum expansion: x4 (-> utf32)
+ // utf16 maximum expansion: x2 (-> utf32)
+ // utf32 maximum expansion: x1
+ enum { bufcapacity = 2048 };
+
+ char_t buffer[bufcapacity];
+ char scratch[4 * bufcapacity];
+
xml_writer& writer;
- char buffer[8192];
size_t bufsize;
+ encoding_t encoding;
};
- template <typename opt1> void text_output_escaped(xml_buffered_writer& writer, const char* s, opt1)
+ void write_bom(xml_writer& writer, encoding_t encoding)
{
- const bool attribute = opt1::o1;
+ switch (encoding)
+ {
+ case encoding_utf8:
+ writer.write("\xef\xbb\xbf", 3);
+ break;
+ case encoding_utf16_be:
+ writer.write("\xfe\xff", 2);
+ break;
+
+ case encoding_utf16_le:
+ writer.write("\xff\xfe", 2);
+ break;
+
+ case encoding_utf32_be:
+ writer.write("\x00\x00\xfe\xff", 4);
+ break;
+
+ case encoding_utf32_le:
+ writer.write("\xff\xfe\x00\x00", 4);
+ break;
+
+ default:
+ // invalid encoding (this should not happen)
+ assert(false);
+ }
+ }
+
+ void text_output_escaped(xml_buffered_writer& writer, const char_t* s, output_chartype_t type)
+ {
while (*s)
{
- const char* prev = s;
+ const char_t* prev = s;
// While *s is a usual symbol
- while (*s && *s != '&' && *s != '<' && *s != '>' && (*s != '"' || !attribute)
- && ((unsigned char)*s >= 32 || (*s == '\r' && !attribute) || (*s == '\n' && !attribute) || *s == '\t'))
- ++s;
+ while (!is_output_chartype(*s, type)) ++s;
writer.write(prev, static_cast<size_t>(s - prev));
@@ -1486,43 +2122,33 @@ namespace
{
case 0: break;
case '&':
- writer.write("&amp;");
+ writer.write('&', 'a', 'm', 'p', ';');
++s;
break;
case '<':
- writer.write("&lt;");
+ writer.write('&', 'l', 't', ';');
++s;
break;
case '>':
- writer.write("&gt;");
+ writer.write('&', 'g', 't', ';');
++s;
break;
case '"':
- writer.write("&quot;");
- ++s;
- break;
- case '\r':
- writer.write("&#13;");
- ++s;
- break;
- case '\n':
- writer.write("&#10;");
+ writer.write('&', 'q', 'u', 'o', 't', ';');
++s;
break;
default: // s is not a usual symbol
{
- unsigned int ch = (unsigned char)*s++;
-
- char buf[8];
- sprintf(buf, "&#%u;", ch);
+ unsigned int ch = static_cast<unsigned int>(*s++);
+ assert(ch < 32);
- writer.write(buf);
+ writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
}
}
}
}
- void node_output(xml_buffered_writer& writer, const xml_node& node, const char* indent, unsigned int flags, unsigned int depth)
+ void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth)
{
if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
@@ -1545,10 +2171,9 @@ namespace
{
writer.write(' ');
writer.write(a.name());
- writer.write('=');
- writer.write('"');
+ writer.write('=', '"');
- text_output_escaped(writer, a.value(), opt1_to_type<1>());
+ text_output_escaped(writer, a.value(), oct_special_attr);
writer.write('"');
}
@@ -1556,7 +2181,7 @@ namespace
if (flags & format_raw)
{
if (!node.first_child())
- writer.write(" />");
+ writer.write(' ', '/', '>');
else
{
writer.write('>');
@@ -1564,30 +2189,26 @@ namespace
for (xml_node n = node.first_child(); n; n = n.next_sibling())
node_output(writer, n, indent, flags, depth + 1);
- writer.write('<');
- writer.write('/');
+ writer.write('<', '/');
writer.write(node.name());
writer.write('>');
}
}
else if (!node.first_child())
- writer.write(" />\n");
+ writer.write(' ', '/', '>', '\n');
else if (node.first_child() == node.last_child() && node.first_child().type() == node_pcdata)
{
writer.write('>');
- text_output_escaped(writer, node.first_child().value(), opt1_to_type<0>());
+ text_output_escaped(writer, node.first_child().value(), oct_special_pcdata);
- writer.write('<');
- writer.write('/');
+ writer.write('<', '/');
writer.write(node.name());
- writer.write('>');
- writer.write('\n');
+ writer.write('>', '\n');
}
else
{
- writer.write('>');
- writer.write('\n');
+ writer.write('>', '\n');
for (xml_node n = node.first_child(); n; n = n.next_sibling())
node_output(writer, n, indent, flags, depth + 1);
@@ -1595,65 +2216,63 @@ namespace
if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
- writer.write('<');
- writer.write('/');
+ writer.write('<', '/');
writer.write(node.name());
- writer.write('>');
- writer.write('\n');
+ writer.write('>', '\n');
}
break;
}
case node_pcdata:
- text_output_escaped(writer, node.value(), opt1_to_type<0>());
+ text_output_escaped(writer, node.value(), oct_special_pcdata);
if ((flags & format_raw) == 0) writer.write('\n');
break;
case node_cdata:
- writer.write("<![CDATA[");
+ writer.write('<', '!', '[', 'C', 'D');
+ writer.write('A', 'T', 'A', '[');
writer.write(node.value());
- writer.write("]]>");
+ writer.write(']', ']', '>');
if ((flags & format_raw) == 0) writer.write('\n');
break;
case node_comment:
- writer.write("<!--");
+ writer.write('<', '!', '-', '-');
writer.write(node.value());
- writer.write("-->");
+ writer.write('-', '-', '>');
if ((flags & format_raw) == 0) writer.write('\n');
break;
case node_pi:
- writer.write("<?");
+ writer.write('<', '?');
writer.write(node.name());
if (node.value()[0])
{
writer.write(' ');
writer.write(node.value());
}
- writer.write("?>");
+ writer.write('?', '>');
if ((flags & format_raw) == 0) writer.write('\n');
break;
case node_declaration:
{
- writer.write("<?");
+ writer.write('<', '?');
writer.write(node.name());
for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute())
{
writer.write(' ');
writer.write(a.name());
- writer.write('=');
- writer.write('"');
+ writer.write('=', '"');
- text_output_escaped(writer, a.value(), opt1_to_type<1>());
+ text_output_escaped(writer, a.value(), oct_special_attr);
writer.write('"');
}
- writer.write("?>");
+ writer.write('?', '>');
if ((flags & format_raw) == 0) writer.write('\n');
break;
}
@@ -1718,33 +2337,6 @@ namespace
namespace pugi
{
- namespace impl
- {
- // Compare two strings
- int PUGIXML_FUNCTION strcmp(const char* src, const char* dst)
- {
- return ::strcmp(src, dst);
- }
-
- // Compare two strings, with globbing, and character sets.
- int PUGIXML_FUNCTION strcmpwild(const char* src, const char* dst)
- {
- int find = 1;
- for(; *src != 0 && find == 1 && *dst != 0; ++src)
- {
- switch (*src)
- {
- case '?': ++dst; break;
- case '[': ++src; find = strcmpwild_cset(&src,&dst); break;
- case '*': find = strcmpwild_astr(&src,&dst); --src; break;
- default : find = (int) (*src == *dst); ++dst;
- }
- }
- while (*src == '*' && find == 1) ++src;
- return (find == 1 && *dst == 0 && *src == 0) ? 0 : 1;
- }
- }
-
xml_writer_file::xml_writer_file(void* file): file(file)
{
}
@@ -1755,13 +2347,28 @@ namespace pugi
}
#ifndef PUGIXML_NO_STL
- xml_writer_stream::xml_writer_stream(std::ostream& stream): stream(&stream)
+ xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
+ {
+ }
+
+ xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
{
}
void xml_writer_stream::write(const void* data, size_t size)
{
- stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
+ if (narrow_stream)
+ {
+ assert(!wide_stream);
+ narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
+ }
+ else
+ {
+ assert(wide_stream);
+ assert(size % sizeof(wchar_t) == 0);
+
+ wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t)));
+ }
}
#endif
@@ -1796,17 +2403,14 @@ namespace pugi
{
}
-#ifdef __MWERKS__
xml_attribute::operator xml_attribute::unspecified_bool_type() const
{
+#ifdef __MWERKS__
return _attr ? &xml_attribute::empty : 0;
- }
#else
- xml_attribute::operator xml_attribute::unspecified_bool_type() const
- {
return _attr ? &xml_attribute::_attr : 0;
- }
#endif
+ }
bool xml_attribute::operator!() const
{
@@ -1855,29 +2459,56 @@ namespace pugi
int xml_attribute::as_int() const
{
- return (_attr && _attr->value) ? atoi(_attr->value) : 0;
+ if (!_attr || !_attr->value) return 0;
+
+ #ifdef PUGIXML_WCHAR_MODE
+ return (int)wcstol(_attr->value, 0, 10);
+ #else
+ return atoi(_attr->value);
+ #endif
}
unsigned int xml_attribute::as_uint() const
{
- int result = (_attr && _attr->value) ? atoi(_attr->value) : 0;
+ if (!_attr || !_attr->value) return 0;
+
+ #ifdef PUGIXML_WCHAR_MODE
+ int result = (int)wcstol(_attr->value, 0, 10);
+ #else
+ int result = atoi(_attr->value);
+ #endif
+
return result < 0 ? 0 : static_cast<unsigned int>(result);
}
double xml_attribute::as_double() const
{
- return (_attr && _attr->value) ? atof(_attr->value) : 0;
+ if (!_attr || !_attr->value) return 0;
+
+ #ifdef PUGIXML_WCHAR_MODE
+ return wcstod(_attr->value, 0);
+ #else
+ return atof(_attr->value);
+ #endif
}
float xml_attribute::as_float() const
{
- return (_attr && _attr->value) ? (float)atof(_attr->value) : 0;
+ if (!_attr || !_attr->value) return 0;
+
+ #ifdef PUGIXML_WCHAR_MODE
+ return (float)wcstod(_attr->value, 0);
+ #else
+ return (float)atof(_attr->value);
+ #endif
}
bool xml_attribute::as_bool() const
{
+ if (!_attr || !_attr->value) return false;
+
// only look at first char
- char first = (_attr && _attr->value) ? *_attr->value : '\0';
+ char_t first = *_attr->value;
// 1*, t* (true), T* (True), y* (yes), Y* (YES)
return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
@@ -1888,14 +2519,14 @@ namespace pugi
return !_attr;
}
- const char* xml_attribute::name() const
+ const char_t* xml_attribute::name() const
{
- return (_attr && _attr->name) ? _attr->name : "";
+ return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");
}
- const char* xml_attribute::value() const
+ const char_t* xml_attribute::value() const
{
- return (_attr && _attr->value) ? _attr->value : "";
+ return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
}
unsigned int xml_attribute::document_order() const
@@ -1903,7 +2534,7 @@ namespace pugi
return _attr ? _attr->document_order : 0;
}
- xml_attribute& xml_attribute::operator=(const char* rhs)
+ xml_attribute& xml_attribute::operator=(const char_t* rhs)
{
set_value(rhs);
return *this;
@@ -1933,7 +2564,7 @@ namespace pugi
return *this;
}
- bool xml_attribute::set_name(const char* rhs)
+ bool xml_attribute::set_name(const char_t* rhs)
{
if (!_attr) return false;
@@ -1944,7 +2575,7 @@ namespace pugi
return res;
}
- bool xml_attribute::set_value(const char* rhs)
+ bool xml_attribute::set_value(const char_t* rhs)
{
if (!_attr) return false;
@@ -1959,26 +2590,50 @@ namespace pugi
{
char buf[128];
sprintf(buf, "%d", rhs);
+
+ #ifdef PUGIXML_WCHAR_MODE
+ char_t wbuf[128];
+ impl::widen_ascii(wbuf, buf);
+
+ return set_value(wbuf);
+ #else
return set_value(buf);
+ #endif
}
bool xml_attribute::set_value(unsigned int rhs)
{
char buf[128];
sprintf(buf, "%u", rhs);
+
+ #ifdef PUGIXML_WCHAR_MODE
+ char_t wbuf[128];
+ impl::widen_ascii(wbuf, buf);
+
+ return set_value(wbuf);
+ #else
return set_value(buf);
+ #endif
}
bool xml_attribute::set_value(double rhs)
{
char buf[128];
sprintf(buf, "%g", rhs);
+
+ #ifdef PUGIXML_WCHAR_MODE
+ char_t wbuf[128];
+ impl::widen_ascii(wbuf, buf);
+
+ return set_value(wbuf);
+ #else
return set_value(buf);
+ #endif
}
bool xml_attribute::set_value(bool rhs)
{
- return set_value(rhs ? "true" : "false");
+ return set_value(rhs ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
}
#ifdef __BORLANDC__
@@ -2001,17 +2656,14 @@ namespace pugi
{
}
-#ifdef __MWERKS__
xml_node::operator xml_node::unspecified_bool_type() const
{
+#ifdef __MWERKS__
return _root ? &xml_node::empty : 0;
- }
#else
- xml_node::operator xml_node::unspecified_bool_type() const
- {
return _root ? &xml_node::_root : 0;
- }
#endif
+ }
bool xml_node::operator!() const
{
@@ -2080,9 +2732,9 @@ namespace pugi
return static_cast<xml_document_struct*>(r)->allocator;
}
- const char* xml_node::name() const
+ const char_t* xml_node::name() const
{
- return (_root && _root->name) ? _root->name : "";
+ return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");
}
xml_node_type xml_node::type() const
@@ -2090,69 +2742,69 @@ namespace pugi
return _root ? static_cast<xml_node_type>(_root->type) : node_null;
}
- const char* xml_node::value() const
+ const char_t* xml_node::value() const
{
- return (_root && _root->value) ? _root->value : "";
+ return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");
}
- xml_node xml_node::child(const char* name) const
+ xml_node xml_node::child(const char_t* name) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
- if (i->name && !strcmp(name, i->name)) return xml_node(i);
+ if (i->name && impl::strequal(name, i->name)) return xml_node(i);
return xml_node();
}
- xml_node xml_node::child_w(const char* name) const
+ xml_node xml_node::child_w(const char_t* name) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
- if (i->name && !impl::strcmpwild(name, i->name)) return xml_node(i);
+ if (i->name && impl::strequalwild(name, i->name)) return xml_node(i);
return xml_node();
}
- xml_attribute xml_node::attribute(const char* name) const
+ xml_attribute xml_node::attribute(const char_t* name) const
{
if (!_root) return xml_attribute();
for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
- if (i->name && !strcmp(name, i->name))
+ if (i->name && impl::strequal(name, i->name))
return xml_attribute(i);
return xml_attribute();
}
- xml_attribute xml_node::attribute_w(const char* name) const
+ xml_attribute xml_node::attribute_w(const char_t* name) const
{
if (!_root) return xml_attribute();
for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
- if (i->name && !impl::strcmpwild(name, i->name))
+ if (i->name && impl::strequalwild(name, i->name))
return xml_attribute(i);
return xml_attribute();
}
- xml_node xml_node::next_sibling(const char* name) const
+ xml_node xml_node::next_sibling(const char_t* name) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
- if (i->name && !strcmp(name, i->name)) return xml_node(i);
+ if (i->name && impl::strequal(name, i->name)) return xml_node(i);
return xml_node();
}
- xml_node xml_node::next_sibling_w(const char* name) const
+ xml_node xml_node::next_sibling_w(const char_t* name) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
- if (i->name && !impl::strcmpwild(name, i->name)) return xml_node(i);
+ if (i->name && impl::strequalwild(name, i->name)) return xml_node(i);
return xml_node();
}
@@ -2165,22 +2817,22 @@ namespace pugi
else return xml_node();
}
- xml_node xml_node::previous_sibling(const char* name) const
+ xml_node xml_node::previous_sibling(const char_t* name) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->prev_sibling; i; i = i->prev_sibling)
- if (i->name && !strcmp(name, i->name)) return xml_node(i);
+ if (i->name && impl::strequal(name, i->name)) return xml_node(i);
return xml_node();
}
- xml_node xml_node::previous_sibling_w(const char* name) const
+ xml_node xml_node::previous_sibling_w(const char_t* name) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->prev_sibling; i; i = i->prev_sibling)
- if (i->name && !impl::strcmpwild(name, i->name)) return xml_node(i);
+ if (i->name && impl::strequalwild(name, i->name)) return xml_node(i);
return xml_node();
}
@@ -2205,23 +2857,23 @@ namespace pugi
return r;
}
- const char* xml_node::child_value() const
+ const char_t* xml_node::child_value() const
{
- if (!_root) return "";
+ if (!_root) return PUGIXML_TEXT("");
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
if ((static_cast<xml_node_type>(i->type) == node_pcdata || static_cast<xml_node_type>(i->type) == node_cdata) && i->value)
return i->value;
- return "";
+ return PUGIXML_TEXT("");
}
- const char* xml_node::child_value(const char* name) const
+ const char_t* xml_node::child_value(const char_t* name) const
{
return child(name).child_value();
}
- const char* xml_node::child_value_w(const char* name) const
+ const char_t* xml_node::child_value_w(const char_t* name) const
{
return child_w(name).child_value();
}
@@ -2246,7 +2898,7 @@ namespace pugi
return _root ? xml_node(_root->last_child) : xml_node();
}
- bool xml_node::set_name(const char* rhs)
+ bool xml_node::set_name(const char_t* rhs)
{
switch (type())
{
@@ -2266,7 +2918,7 @@ namespace pugi
}
}
- bool xml_node::set_value(const char* rhs)
+ bool xml_node::set_value(const char_t* rhs)
{
switch (type())
{
@@ -2287,7 +2939,7 @@ namespace pugi
}
}
- xml_attribute xml_node::append_attribute(const char* name)
+ xml_attribute xml_node::append_attribute(const char_t* name)
{
if (type() != node_element && type() != node_declaration) return xml_attribute();
@@ -2297,7 +2949,7 @@ namespace pugi
return a;
}
- xml_attribute xml_node::insert_attribute_before(const char* name, const xml_attribute& attr)
+ xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr)
{
if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
@@ -2323,7 +2975,7 @@ namespace pugi
return a;
}
- xml_attribute xml_node::insert_attribute_after(const char* name, const xml_attribute& attr)
+ xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr)
{
if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
@@ -2453,7 +3105,7 @@ namespace pugi
return result;
}
- void xml_node::remove_attribute(const char* name)
+ void xml_node::remove_attribute(const char_t* name)
{
remove_attribute(attribute(name));
}
@@ -2478,7 +3130,7 @@ namespace pugi
a._attr->destroy();
}
- void xml_node::remove_child(const char* name)
+ void xml_node::remove_child(const char_t* name)
{
remove_child(child(name));
}
@@ -2496,64 +3148,64 @@ namespace pugi
n._root->destroy();
}
- xml_node xml_node::find_child_by_attribute(const char* name, const char* attr_name, const char* attr_value) const
+ xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
- if (i->name && !strcmp(name, i->name))
+ if (i->name && impl::strequal(name, i->name))
{
for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
- if (!strcmp(attr_name, a->name) && !strcmp(attr_value, a->value))
+ if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
return xml_node(i);
}
return xml_node();
}
- xml_node xml_node::find_child_by_attribute_w(const char* name, const char* attr_name, const char* attr_value) const
+ xml_node xml_node::find_child_by_attribute_w(const char_t* name, const char_t* attr_name, const char_t* attr_value) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
- if (i->name && !impl::strcmpwild(name, i->name))
+ if (i->name && impl::strequalwild(name, i->name))
{
for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
- if (!impl::strcmpwild(attr_name, a->name) && !impl::strcmpwild(attr_value, a->value))
+ if (impl::strequalwild(attr_name, a->name) && impl::strequalwild(attr_value, a->value))
return xml_node(i);
}
return xml_node();
}
- xml_node xml_node::find_child_by_attribute(const char* attr_name, const char* attr_value) const
+ xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
- if (!strcmp(attr_name, a->name) && !strcmp(attr_value, a->value))
+ if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
return xml_node(i);
return xml_node();
}
- xml_node xml_node::find_child_by_attribute_w(const char* attr_name, const char* attr_value) const
+ xml_node xml_node::find_child_by_attribute_w(const char_t* attr_name, const char_t* attr_value) const
{
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
- if (!impl::strcmpwild(attr_name, a->name) && !impl::strcmpwild(attr_value, a->value))
+ if (impl::strequalwild(attr_name, a->name) && impl::strequalwild(attr_value, a->value))
return xml_node(i);
return xml_node();
}
#ifndef PUGIXML_NO_STL
- std::string xml_node::path(char delimiter) const
+ string_t xml_node::path(char_t delimiter) const
{
- std::string path;
+ string_t path;
xml_node cursor = *this; // Make a copy.
@@ -2563,7 +3215,7 @@ namespace pugi
{
cursor = cursor.parent();
- std::string temp = cursor.name();
+ string_t temp = cursor.name();
temp += delimiter;
temp += path;
path.swap(temp);
@@ -2573,7 +3225,7 @@ namespace pugi
}
#endif
- xml_node xml_node::first_element_by_path(const char* path, char delimiter) const
+ xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter) const
{
xml_node found = *this; // Current search context.
@@ -2586,17 +3238,17 @@ namespace pugi
++path;
}
- const char* path_segment = path;
+ const char_t* path_segment = path;
while (*path_segment == delimiter) ++path_segment;
- const char* path_segment_end = path_segment;
+ const char_t* path_segment_end = path_segment;
while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
if (path_segment == path_segment_end) return found;
- const char* next_segment = path_segment_end;
+ const char_t* next_segment = path_segment_end;
while (*next_segment == delimiter) ++next_segment;
@@ -2608,7 +3260,7 @@ namespace pugi
{
for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling)
{
- if (j->name && !strcmprange(j->name, path_segment, path_segment_end))
+ if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
{
xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
@@ -2698,23 +3350,32 @@ namespace pugi
}
}
- void xml_node::print(xml_writer& writer, const char* indent, unsigned int flags, unsigned int depth) const
+ void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, encoding_t encoding, unsigned int depth) const
{
if (!_root) return;
- xml_buffered_writer buffered_writer(writer);
+ xml_buffered_writer buffered_writer(writer, encoding);
node_output(buffered_writer, *this, indent, flags, depth);
}
#ifndef PUGIXML_NO_STL
- void xml_node::print(std::ostream& stream, const char* indent, unsigned int flags, unsigned int depth) const
+ void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, encoding_t encoding, unsigned int depth) const
{
if (!_root) return;
xml_writer_stream writer(stream);
- print(writer, indent, flags, depth);
+ print(writer, indent, flags, encoding, depth);
+ }
+
+ void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const
+ {
+ if (!_root) return;
+
+ xml_writer_stream writer(stream);
+
+ print(writer, indent, flags, encoding_wchar, depth);
}
#endif
@@ -2724,7 +3385,7 @@ namespace pugi
if (!r) return -1;
- const char* buffer = static_cast<xml_document_struct*>(r)->buffer;
+ const char_t* buffer = static_cast<xml_document_struct*>(r)->buffer;
if (!buffer) return -1;
@@ -2964,7 +3625,7 @@ namespace pugi
}
#ifndef PUGIXML_NO_STL
- xml_parse_result xml_document::load(std::istream& stream, unsigned int options)
+ xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, encoding_t encoding)
{
destroy();
@@ -2977,36 +3638,63 @@ namespace pugi
if (!stream.good()) return MAKE_PARSE_RESULT(status_io_error);
- char* s = static_cast<char*>(global_allocate(length + 1));
+ char* s = static_cast<char*>(global_allocate(length > 0 ? length : 1));
if (!s) return MAKE_PARSE_RESULT(status_out_of_memory);
stream.read(s, length);
- if (stream.gcount() > length || stream.gcount() == 0)
+ if (stream.gcount() > length || (length > 0 && stream.gcount() == 0))
{
global_deallocate(s);
return MAKE_PARSE_RESULT(status_io_error);
}
- s[stream.gcount()] = 0;
-
- return parse(transfer_ownership_tag(), s, options); // Parse the input string.
+ return load_buffer_inplace_own(s, stream.gcount(), options, encoding); // Parse the input string.
}
-#endif
- xml_parse_result xml_document::load(const char* contents, unsigned int options)
+ xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
{
destroy();
- char* s = static_cast<char*>(global_allocate(strlen(contents) + 1));
+ if (!stream.good()) return MAKE_PARSE_RESULT(status_io_error);
+
+ std::streamoff length, pos = stream.tellg();
+ stream.seekg(0, std::ios::end);
+ length = stream.tellg();
+ stream.seekg(pos, std::ios::beg);
+
+ if (!stream.good()) return MAKE_PARSE_RESULT(status_io_error);
+
+ wchar_t* s = static_cast<wchar_t*>(global_allocate((length > 0 ? length : 1) * sizeof(wchar_t)));
if (!s) return MAKE_PARSE_RESULT(status_out_of_memory);
- strcpy(s, contents);
+ stream.read(s, length);
+
+ if (stream.gcount() > length || (length > 0 && stream.gcount() == 0))
+ {
+ global_deallocate(s);
+ return MAKE_PARSE_RESULT(status_io_error);
+ }
+
+ return load_buffer_inplace_own(s, stream.gcount() * sizeof(wchar_t), options, encoding_wchar); // Parse the input string.
+ }
+#endif
- return parse(transfer_ownership_tag(), s, options); // Parse the input string.
+ xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
+ {
+ destroy();
+
+ // Force native encoding (skip autodetection)
+ #ifdef PUGIXML_WCHAR_MODE
+ encoding_t encoding = encoding_wchar;
+ #else
+ encoding_t encoding = encoding_utf8;
+ #endif
+
+ return load_buffer(contents, impl::strlen(contents) * sizeof(char_t), options, encoding);
}
- xml_parse_result xml_document::load_file(const char* name, unsigned int options)
+ xml_parse_result xml_document::load_file(const char* name, unsigned int options, encoding_t encoding)
{
destroy();
@@ -3023,7 +3711,7 @@ namespace pugi
return MAKE_PARSE_RESULT(status_io_error);
}
- char* s = static_cast<char*>(global_allocate(length + 1));
+ char* s = static_cast<char*>(global_allocate(length > 0 ? length : 1));
if (!s)
{
@@ -3031,69 +3719,134 @@ namespace pugi
return MAKE_PARSE_RESULT(status_out_of_memory);
}
- size_t read = fread(s, (size_t)length, 1, file);
+ size_t read = fread(s, 1, (size_t)length, file);
fclose(file);
- if (read != 1)
+ if (read != (size_t)length)
{
global_deallocate(s);
return MAKE_PARSE_RESULT(status_io_error);
}
-
- s[length] = 0;
- return parse(transfer_ownership_tag(), s, options); // Parse the input string.
+ return load_buffer_inplace_own(s, length, options, encoding);
}
- xml_parse_result xml_document::parse(char* xmlstr, unsigned int options)
+ xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, encoding_t encoding)
{
destroy();
- // for offset_debug
- static_cast<xml_document_struct*>(_root)->buffer = xmlstr;
+ // get actual encoding
+ encoding_t buffer_encoding = get_buffer_encoding(encoding, contents, size);
- xml_allocator& alloc = static_cast<xml_document_struct*>(_root)->allocator;
+ // get private buffer
+ char_t* buffer;
+ size_t length;
+
+ if (!convert_buffer(buffer, length, buffer_encoding, contents, size, false)) return MAKE_PARSE_RESULT(status_out_of_memory);
- xml_parser parser(alloc);
+ // parse
+ xml_parse_result res = xml_parser::parse(buffer, length, _root, options);
+
+ // remember encoding
+ res.encoding = buffer_encoding;
+
+ // grab onto buffer
+ _buffer = buffer;
+
+ return res;
+ }
+
+ xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, encoding_t encoding)
+ {
+ destroy();
+
+ // get actual encoding
+ encoding_t buffer_encoding = get_buffer_encoding(encoding, contents, size);
+
+ // get private buffer
+ char_t* buffer;
+ size_t length;
+
+ if (!convert_buffer(buffer, length, buffer_encoding, contents, size, true)) return MAKE_PARSE_RESULT(status_out_of_memory);
- return parser.parse(xmlstr, _root, options); // Parse the input string.
+ // parse
+ xml_parse_result res = xml_parser::parse(buffer, length, _root, options);
+
+ // remember encoding
+ res.encoding = buffer_encoding;
+
+ // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself
+ if (buffer != contents) _buffer = buffer;
+
+ return res;
}
- xml_parse_result xml_document::parse(const transfer_ownership_tag&, char* xmlstr, unsigned int options)
+ xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, encoding_t encoding)
{
- xml_parse_result res = parse(xmlstr, options);
+ destroy();
+
+ // get actual encoding
+ encoding_t buffer_encoding = get_buffer_encoding(encoding, contents, size);
+
+ // get private buffer
+ char_t* buffer;
+ size_t length;
+
+ if (!convert_buffer(buffer, length, buffer_encoding, contents, size, true)) return MAKE_PARSE_RESULT(status_out_of_memory);
+
+ // delete original buffer if we performed a conversion
+ if (buffer != contents) global_deallocate(contents);
+
+ // parse
+ xml_parse_result res = xml_parser::parse(buffer, length, _root, options);
- _buffer = xmlstr;
+ // remember encoding
+ res.encoding = buffer_encoding;
+
+ // grab onto buffer
+ _buffer = buffer;
return res;
}
- void xml_document::save(xml_writer& writer, const char* indent, unsigned int flags) const
+ void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, encoding_t encoding) const
{
- xml_buffered_writer buffered_writer(writer);
+ if (flags & format_write_bom) write_bom(writer, get_write_encoding(encoding));
- if (flags & format_write_bom_utf8)
- {
- static const unsigned char utf8_bom[] = {0xEF, 0xBB, 0xBF};
- buffered_writer.write(utf8_bom, 3);
- }
+ xml_buffered_writer buffered_writer(writer, encoding);
if (!(flags & format_no_declaration))
{
- buffered_writer.write("<?xml version=\"1.0\"?>");
- if (!(flags & format_raw)) buffered_writer.write("\n");
+ buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\"?>"));
+ if (!(flags & format_raw)) buffered_writer.write('\n');
}
node_output(buffered_writer, *this, indent, flags, 0);
}
- bool xml_document::save_file(const char* name, const char* indent, unsigned int flags) const
+#ifndef PUGIXML_NO_STL
+ void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, encoding_t encoding) const
+ {
+ xml_writer_stream writer(stream);
+
+ save(writer, indent, flags, encoding);
+ }
+
+ void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
+ {
+ xml_writer_stream writer(stream);
+
+ save(writer, indent, flags, encoding_wchar);
+ }
+#endif
+
+ bool xml_document::save_file(const char* name, const char_t* indent, unsigned int flags, encoding_t encoding) const
{
FILE* file = fopen(name, "wb");
if (!file) return false;
xml_writer_file writer(file);
- save(writer, indent, flags);
+ save(writer, indent, flags, encoding);
fclose(file);
@@ -3108,29 +3861,56 @@ namespace pugi
#ifndef PUGIXML_NO_STL
std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
{
+ STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
+
+ size_t length = wcslen(str);
+
+ // first pass: get length in utf8 characters
+ size_t size = sizeof(wchar_t) == 2 ?
+ impl::decode_utf16_block<impl::utf8_counter>(reinterpret_cast<const impl::char16_t*>(str), length, 0, opt1_to_type<false>()) :
+ impl::decode_utf32_block<impl::utf8_counter>(reinterpret_cast<const impl::char32_t*>(str), length, 0, opt1_to_type<false>());
+
+ // allocate resulting string
std::string result;
- result.reserve(strutf16_utf8_size(str));
-
- for (; *str; ++str)
+ result.resize(size);
+
+ // second pass: convert to utf8
+ if (size > 0)
{
- char buffer[6];
+ impl::char8_t* begin = reinterpret_cast<impl::char8_t*>(&result[0]);
+ impl::char8_t* end = sizeof(wchar_t) == 2 ?
+ impl::decode_utf16_block<impl::utf8_writer>(reinterpret_cast<const impl::char16_t*>(str), length, begin, opt1_to_type<false>()) :
+ impl::decode_utf32_block<impl::utf8_writer>(reinterpret_cast<const impl::char32_t*>(str), length, begin, opt1_to_type<false>());
- result.append(buffer, strutf16_utf8(buffer, *str));
+ // truncate invalid output
+ assert(begin <= end && static_cast<size_t>(end - begin) <= result.size());
+ result.resize(static_cast<size_t>(end - begin));
}
-
+
return result;
}
- std::wstring PUGIXML_FUNCTION as_utf16(const char* str)
+ std::wstring PUGIXML_FUNCTION as_wide(const char* str)
{
+ const impl::char8_t* data = reinterpret_cast<const impl::char8_t*>(str);
+ size_t size = strlen(str);
+
+ // first pass: get length in wchar_t
+ size_t length = impl::decode_utf8_block<impl::wchar_counter>(data, size, 0);
+
+ // allocate resulting string
std::wstring result;
- result.reserve(strutf8_utf16_size(str));
+ result.resize(length);
- for (; *str;)
+ // second pass: convert to wchar_t
+ if (length > 0)
{
- unsigned int ch = 0;
- str = strutf8_utf16(str, ch);
- result += (wchar_t)ch;
+ impl::wchar_writer::value_type begin = reinterpret_cast<impl::wchar_writer::value_type>(&result[0]);
+ impl::wchar_writer::value_type end = impl::decode_utf8_block<impl::wchar_writer>(data, size, begin);
+
+ // truncate invalid output
+ assert(begin <= end && static_cast<size_t>(end - begin) <= result.size());
+ result.resize(static_cast<size_t>(end - begin));
}
return result;
@@ -3154,6 +3934,22 @@ namespace pugi
}
}
+#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
+namespace std
+{
+ // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
+ std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
+ {
+ return std::bidirectional_iterator_tag();
+ }
+
+ std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
+ {
+ return std::bidirectional_iterator_tag();
+ }
+}
+#endif
+
/**
* Copyright (c) 2006-2009 Arseny Kapoulkine
*
diff --git a/src/pugixml.hpp b/src/pugixml.hpp
index 0a4d9fd..f2cb3d1 100644
--- a/src/pugixml.hpp
+++ b/src/pugixml.hpp
@@ -17,8 +17,25 @@
#include "pugiconfig.hpp"
#ifndef PUGIXML_NO_STL
-# include <string>
-# include <iosfwd>
+#include <exception>
+
+namespace std
+{
+ struct bidirectional_iterator_tag;
+
+ // Borland C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions
+ template <class _Ty> class allocator;
+ template <class _Ty> struct char_traits;
+ template <class _Elem, class _Traits> class basic_istream;
+ template <class _Elem, class _Traits> class basic_ostream;
+ template <class _Elem, class _Traits, class _Ax> class basic_string;
+
+ // Digital Mars compiler has a bug which requires a forward declaration for explicit instantiation (otherwise type selection is messed up later, producing link errors)
+ // Also note that we have to declare char_traits as a class here, since it's defined that way
+#ifdef __DMC__
+ template <> class char_traits<char>;
+#endif
+}
#endif
// No XPath without STL
@@ -45,13 +62,39 @@
#include <stddef.h>
+// Character interface macros
+#ifdef PUGIXML_WCHAR_MODE
+# define PUGIXML_TEXT(t) L ## t
+
+namespace pugi
+{
+ typedef wchar_t char_t;
+
+#ifndef PUGIXML_NO_STL
+ typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > string_t;
+#endif
+}
+#else
+# define PUGIXML_TEXT(t) t
+
+namespace pugi
+{
+ typedef char char_t;
+
+# ifndef PUGIXML_NO_STL
+ // gcc3.4 has a bug which prevents string_t instantiation using char_t, so we have to use char type explicitly
+ typedef std::basic_string<char, std::char_traits<char>, std::allocator<char> > string_t;
+# endif
+}
+#endif
+
// Helpers for inline implementation
namespace pugi
{
namespace impl
{
- int PUGIXML_FUNCTION strcmp(const char*, const char*);
- int PUGIXML_FUNCTION strcmpwild(const char*, const char*);
+ bool PUGIXML_FUNCTION strequal(const char_t*, const char_t*);
+ bool PUGIXML_FUNCTION strequalwild(const char_t*, const char_t*);
}
}
@@ -199,6 +242,24 @@ namespace pugi
*/
const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol;
+ /**
+ * These flags determine the encoding of input data for XML document. Default mode is encoding_auto,
+ * which means that document encoding is autodetected from BOM and necessary encoding conversions are
+ * applied. You can override this mode by using any of the specific encodings.
+ */
+ enum encoding_t
+ {
+ encoding_auto, //!< Auto-detect input encoding using BOM or </<? detection; use UTF8 if BOM is not found
+ encoding_utf8, //!< UTF8 encoding
+ encoding_utf16_le, //!< Little-endian UTF16
+ encoding_utf16_be, //!< Big-endian UTF16
+ encoding_utf16, //!< UTF16 with native endianness
+ encoding_utf32_le, //!< Little-endian UTF32
+ encoding_utf32_be, //!< Big-endian UTF32
+ encoding_utf32, //!< UTF32 with native endianness
+ encoding_wchar //!< The same encoding wchar_t has (either UTF16 or UTF32)
+ };
+
// Formatting flags
/**
@@ -210,11 +271,11 @@ namespace pugi
const unsigned int format_indent = 0x01;
/**
- * This flag determines if UTF-8 BOM is to be written to output stream.
+ * This flag determines if encoding-specific BOM is to be written to output stream.
*
* This flag is off by default.
*/
- const unsigned int format_write_bom_utf8 = 0x02;
+ const unsigned int format_write_bom = 0x02;
/**
* If this flag is on, no indentation is performed and no line breaks are written to output file.
@@ -281,7 +342,7 @@ namespace pugi
xpath_allocator* m_alloc;
xpath_ast_node* m_root;
- void compile(const char* query);
+ void compile(const char_t* query);
public:
/**
@@ -290,7 +351,7 @@ namespace pugi
*
* \param query - string with XPath expression
*/
- explicit xpath_query(const char* query);
+ explicit xpath_query(const char_t* query);
/**
* Dtor
@@ -335,7 +396,7 @@ namespace pugi
* \param n - context node
* \return evaluation result
*/
- std::string evaluate_string(const xml_node& n) const;
+ string_t evaluate_string(const xml_node& n) const;
/**
* Evaluate expression as node set for the context node \a n.
@@ -401,12 +462,20 @@ namespace pugi
*
* \param stream - output stream object
*/
- xml_writer_stream(std::ostream& stream);
+ xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream);
+
+ /**
+ * Construct writer instance
+ *
+ * \param stream - output stream object
+ */
+ xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream);
virtual void write(const void* data, size_t size);
private:
- std::ostream* stream;
+ std::basic_ostream<char, std::char_traits<char> >* narrow_stream;
+ std::basic_ostream<wchar_t, std::char_traits<wchar_t> >* wide_stream;
};
#endif
@@ -559,7 +628,7 @@ namespace pugi
* \param rhs - new attribute value
* \return self
*/
- xml_attribute& operator=(const char* rhs);
+ xml_attribute& operator=(const char_t* rhs);
/**
* Set attribute value to \a rhs.
@@ -599,7 +668,7 @@ namespace pugi
* \param rhs - new attribute name
* \return success flag (call fails if attribute is empty or there is not enough memory)
*/
- bool set_name(const char* rhs);
+ bool set_name(const char_t* rhs);
/**
* Set attribute value to \a rhs.
@@ -607,7 +676,7 @@ namespace pugi
* \param rhs - new attribute value
* \return success flag (call fails if attribute is empty or there is not enough memory)
*/
- bool set_value(const char* rhs);
+ bool set_value(const char_t* rhs);
/**
* Set attribute value to \a rhs.
@@ -655,14 +724,14 @@ namespace pugi
*
* \return attribute name, or "" if attribute is empty
*/
- const char* name() const;
+ const char_t* name() const;
/**
* Get attribute value.
*
* \return attribute value, or "" if attribute is empty
*/
- const char* value() const;
+ const char_t* value() const;
};
#ifdef __BORLANDC__
@@ -825,14 +894,14 @@ namespace pugi
*
* \return node name, if any; "" otherwise
*/
- const char* name() const;
+ const char_t* name() const;
/**
* Get node value (comment/PI/PCDATA/CDATA contents, depending on node type)
*
* \return node value, if any; "" otherwise
*/
- const char* value() const;
+ const char_t* value() const;
/**
* Get child with the specified name
@@ -840,7 +909,7 @@ namespace pugi
* \param name - child name
* \return child with the specified name, if any; empty node otherwise
*/
- xml_node child(const char* name) const;
+ xml_node child(const char_t* name) const;
/**
* Get child with the name that matches specified pattern
@@ -848,7 +917,7 @@ namespace pugi
* \param name - child name pattern
* \return child with the name that matches pattern, if any; empty node otherwise
*/
- xml_node child_w(const char* name) const;
+ xml_node child_w(const char_t* name) const;
/**
* Get attribute with the specified name
@@ -856,7 +925,7 @@ namespace pugi
* \param name - attribute name
* \return attribute with the specified name, if any; empty attribute otherwise
*/
- xml_attribute attribute(const char* name) const;
+ xml_attribute attribute(const char_t* name) const;
/**
* Get attribute with the name that matches specified pattern
@@ -864,7 +933,7 @@ namespace pugi
* \param name - attribute name pattern
* \return attribute with the name that matches pattern, if any; empty attribute otherwise
*/
- xml_attribute attribute_w(const char* name) const;
+ xml_attribute attribute_w(const char_t* name) const;
/**
* Get first of following sibling nodes with the specified name
@@ -872,7 +941,7 @@ namespace pugi
* \param name - sibling name
* \return node with the specified name, if any; empty node otherwise
*/
- xml_node next_sibling(const char* name) const;
+ xml_node next_sibling(const char_t* name) const;
/**
* Get first of the following sibling nodes with the name that matches specified pattern
@@ -880,7 +949,7 @@ namespace pugi
* \param name - sibling name pattern
* \return node with the name that matches pattern, if any; empty node otherwise
*/
- xml_node next_sibling_w(const char* name) const;
+ xml_node next_sibling_w(const char_t* name) const;
/**
* Get following sibling
@@ -895,7 +964,7 @@ namespace pugi
* \param name - sibling name
* \return node with the specified name, if any; empty node otherwise
*/
- xml_node previous_sibling(const char* name) const;
+ xml_node previous_sibling(const char_t* name) const;
/**
* Get first of the preceding sibling nodes with the name that matches specified pattern
@@ -903,7 +972,7 @@ namespace pugi
* \param name - sibling name pattern
* \return node with the name that matches pattern, if any; empty node otherwise
*/
- xml_node previous_sibling_w(const char* name) const;
+ xml_node previous_sibling_w(const char_t* name) const;
/**
* Get preceding sibling
@@ -931,7 +1000,7 @@ namespace pugi
*
* \return child value of current node, if any; "" otherwise
*/
- const char* child_value() const;
+ const char_t* child_value() const;
/**
* Get child value of child with specified name. \see child_value
@@ -940,7 +1009,7 @@ namespace pugi
* \param name - child name
* \return child value of specified child node, if any; "" otherwise
*/
- const char* child_value(const char* name) const;
+ const char_t* child_value(const char_t* name) const;
/**
* Get child value of child with name that matches the specified pattern. \see child_value
@@ -949,7 +1018,7 @@ namespace pugi
* \param name - child name pattern
* \return child value of specified child node, if any; "" otherwise
*/
- const char* child_value_w(const char* name) const;
+ const char_t* child_value_w(const char_t* name) const;
public:
/**
@@ -958,7 +1027,7 @@ namespace pugi
* \param rhs - new node name
* \return success flag (call fails if node is of the wrong type or there is not enough memory)
*/
- bool set_name(const char* rhs);
+ bool set_name(const char_t* rhs);
/**
* Set node value to \a rhs (for PI/PCDATA/CDATA/comment nodes). \see value
@@ -966,7 +1035,7 @@ namespace pugi
* \param rhs - new node value
* \return success flag (call fails if node is of the wrong type or there is not enough memory)
*/
- bool set_value(const char* rhs);
+ bool set_value(const char_t* rhs);
/**
* Add attribute with specified name (for element nodes)
@@ -974,7 +1043,7 @@ namespace pugi
* \param name - attribute name
* \return added attribute, or empty attribute if there was an error (wrong node type)
*/
- xml_attribute append_attribute(const char* name);
+ xml_attribute append_attribute(const char_t* name);
/**
* Insert attribute with specified name after \a attr (for element nodes)
@@ -983,7 +1052,7 @@ namespace pugi
* \param attr - attribute to insert a new one after
* \return inserted attribute, or empty attribute if there was an error (wrong node type, or attr does not belong to node)
*/
- xml_attribute insert_attribute_after(const char* name, const xml_attribute& attr);
+ xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);
/**
* Insert attribute with specified name before \a attr (for element nodes)
@@ -992,7 +1061,7 @@ namespace pugi
* \param attr - attribute to insert a new one before
* \return inserted attribute, or empty attribute if there was an error (wrong node type, or attr does not belong to node)
*/
- xml_attribute insert_attribute_before(const char* name, const xml_attribute& attr);
+ xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);
/**
* Add a copy of the specified attribute (for element nodes)
@@ -1084,7 +1153,7 @@ namespace pugi
*
* \param name - attribute name
*/
- void remove_attribute(const char* name);
+ void remove_attribute(const char_t* name);
/**
* Remove specified child
@@ -1098,7 +1167,7 @@ namespace pugi
*
* \param name - child name
*/
- void remove_child(const char* name);
+ void remove_child(const char_t* name);
public:
/**
@@ -1121,7 +1190,7 @@ namespace pugi
* \param name - node name
* \param it - output iterator (for example, std::back_insert_iterator (result of std::back_inserter))
*/
- template <typename OutputIterator> void all_elements_by_name(const char* name, OutputIterator it) const
+ template <typename OutputIterator> void all_elements_by_name(const char_t* name, OutputIterator it) const
{
if (!_root) return;
@@ -1129,7 +1198,7 @@ namespace pugi
{
if (node.type() == node_element)
{
- if (!impl::strcmp(name, node.name()))
+ if (impl::strequal(name, node.name()))
{
*it = node;
++it;
@@ -1146,7 +1215,7 @@ namespace pugi
* \param name - node name pattern
* \param it - output iterator (for example, std::back_insert_iterator (result of std::back_inserter))
*/
- template <typename OutputIterator> void all_elements_by_name_w(const char* name, OutputIterator it) const
+ template <typename OutputIterator> void all_elements_by_name_w(const char_t* name, OutputIterator it) const
{
if (!_root) return;
@@ -1154,7 +1223,7 @@ namespace pugi
{
if (node.type() == node_element)
{
- if (!impl::strcmpwild(name, node.name()))
+ if (impl::strequalwild(name, node.name()))
{
*it = node;
++it;
@@ -1246,7 +1315,7 @@ namespace pugi
* \param attr_value - attribute value of child node
* \return first matching child node, or empty node
*/
- xml_node find_child_by_attribute(const char* name, const char* attr_name, const char* attr_value) const;
+ xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
/**
* Find child node with the specified name that has specified attribute (use pattern matching for node name and attribute name/value)
@@ -1256,7 +1325,7 @@ namespace pugi
* \param attr_value - pattern for attribute value of child node
* \return first matching child node, or empty node
*/
- xml_node find_child_by_attribute_w(const char* name, const char* attr_name, const char* attr_value) const;
+ xml_node find_child_by_attribute_w(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
/**
* Find child node that has specified attribute
@@ -1265,7 +1334,7 @@ namespace pugi
* \param attr_value - attribute value of child node
* \return first matching child node, or empty node
*/
- xml_node find_child_by_attribute(const char* attr_name, const char* attr_value) const;
+ xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;
/**
* Find child node that has specified attribute (use pattern matching for attribute name/value)
@@ -1274,7 +1343,7 @@ namespace pugi
* \param attr_value - pattern for attribute value of child node
* \return first matching child node, or empty node
*/
- xml_node find_child_by_attribute_w(const char* attr_name, const char* attr_value) const;
+ xml_node find_child_by_attribute_w(const char_t* attr_name, const char_t* attr_value) const;
#ifndef PUGIXML_NO_STL
/**
@@ -1283,7 +1352,7 @@ namespace pugi
* \param delimiter - delimiter character to insert between element names
* \return path string (e.g. '/bookstore/book/author').
*/
- std::string path(char delimiter = '/') const;
+ string_t path(char_t delimiter = '/') const;
#endif
/**
@@ -1293,7 +1362,7 @@ namespace pugi
* \param delimiter - delimiter character to use while tokenizing path
* \return matching node, if any; empty node otherwise
*/
- xml_node first_element_by_path(const char* path, char delimiter = '/') const;
+ xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const;
/**
* Recursively traverse subtree with xml_tree_walker
@@ -1313,7 +1382,7 @@ namespace pugi
* \param query - query string
* \return first node from the resulting node set by document order, or empty node if none found
*/
- xpath_node select_single_node(const char* query) const;
+ xpath_node select_single_node(const char_t* query) const;
/**
* Select single node by evaluating XPath query
@@ -1329,7 +1398,7 @@ namespace pugi
* \param query - query string
* \return resulting node set
*/
- xpath_node_set select_nodes(const char* query) const;
+ xpath_node_set select_nodes(const char_t* query) const;
/**
* Select node set by evaluating XPath query
@@ -1351,7 +1420,7 @@ namespace pugi
* \param flags - formatting flags
* \param depth - starting depth (used for indentation)
*/
- void print(xml_writer& writer, const char* indent = "\t", unsigned int flags = format_default, unsigned int depth = 0) const;
+ void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, encoding_t encoding = encoding_auto, unsigned int depth = 0) const;
#ifndef PUGIXML_NO_STL
/**
@@ -1363,7 +1432,18 @@ namespace pugi
* \param depth - starting depth (used for indentation)
* \deprecated Use print() with xml_writer_stream instead
*/
- void print(std::ostream& os, const char* indent = "\t", unsigned int flags = format_default, unsigned int depth = 0) const;
+ void print(std::basic_ostream<char, std::char_traits<char> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, encoding_t encoding = encoding_auto, unsigned int depth = 0) const;
+
+ /**
+ * Print subtree to stream
+ *
+ * \param os - output stream
+ * \param indent - indentation string
+ * \param flags - formatting flags
+ * \param depth - starting depth (used for indentation)
+ * \deprecated Use print() with xml_writer_stream instead
+ */
+ void print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const;
#endif
/**
@@ -1388,17 +1468,7 @@ namespace pugi
* It's a bidirectional iterator with value type 'xml_node'.
*/
class PUGIXML_CLASS xml_node_iterator
-#ifndef PUGIXML_NO_STL
- : public std::iterator<std::bidirectional_iterator_tag, xml_node>
-#endif
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4251 4275) // C4251 and C4275 can be ignored for _Container_base, as per MSDN
-#endif
{
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
friend class xml_node;
private:
@@ -1410,6 +1480,18 @@ namespace pugi
public:
/**
+ * Iterator traits
+ */
+ typedef ptrdiff_t difference_type;
+ typedef xml_node value_type;
+ typedef xml_node* pointer;
+ typedef xml_node& reference;
+
+ #ifndef PUGIXML_NO_STL
+ typedef std::bidirectional_iterator_tag iterator_category;
+ #endif
+
+ /**
* Default ctor
*/
xml_node_iterator();
@@ -1493,17 +1575,7 @@ namespace pugi
* It's a bidirectional iterator with value type 'xml_attribute'.
*/
class PUGIXML_CLASS xml_attribute_iterator
-#ifndef PUGIXML_NO_STL
- : public std::iterator<std::bidirectional_iterator_tag, xml_attribute>
-#endif
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4251 4275) // C4251 and C4275 can be ignored for _Container_base, as per MSDN
-#endif
{
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
friend class xml_node;
private:
@@ -1515,6 +1587,18 @@ namespace pugi
public:
/**
+ * Iterator traits
+ */
+ typedef ptrdiff_t difference_type;
+ typedef xml_attribute value_type;
+ typedef xml_attribute* pointer;
+ typedef xml_attribute& reference;
+
+ #ifndef PUGIXML_NO_STL
+ typedef std::bidirectional_iterator_tag iterator_category;
+ #endif
+
+ /**
* Default ctor
*/
xml_attribute_iterator();
@@ -1658,12 +1742,6 @@ namespace pugi
};
/**
- * Struct used to distinguish parsing with ownership transfer from parsing without it.
- * \see xml_document::parse
- */
- struct transfer_ownership_tag {};
-
- /**
* Parsing status enumeration, returned as part of xml_parse_result struct
*/
enum xml_parse_status
@@ -1702,6 +1780,9 @@ namespace pugi
/// Line in parser source which reported this
unsigned int line;
+ /// Source document encoding
+ encoding_t encoding;
+
/// Cast to bool operator
operator bool() const
{
@@ -1719,7 +1800,7 @@ namespace pugi
class PUGIXML_CLASS xml_document: public xml_node
{
private:
- char* _buffer;
+ char_t* _buffer;
xml_memory_block _memory;
@@ -1749,17 +1830,26 @@ namespace pugi
* \param options - parsing options
* \return parsing result
*/
- xml_parse_result load(std::istream& stream, unsigned int options = parse_default);
+
+ xml_parse_result load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options = parse_default, encoding_t encoding = encoding_auto);
+ /**
+ * Load document from stream.
+ *
+ * \param stream - stream with xml data
+ * \param options - parsing options
+ * \return parsing result
+ */
+ xml_parse_result load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options = parse_default);
#endif
/**
- * Load document from string.
+ * Load document from string. String has to be zero-terminated. No encoding conversions are applied.
*
* \param contents - input string
* \param options - parsing options
* \return parsing result
*/
- xml_parse_result load(const char* contents, unsigned int options = parse_default);
+ xml_parse_result load(const char_t* contents, unsigned int options = parse_default);
/**
* Load document from file
@@ -1768,32 +1858,43 @@ namespace pugi
* \param options - parsing options
* \return parsing result
*/
- xml_parse_result load_file(const char* name, unsigned int options = parse_default);
+ xml_parse_result load_file(const char* name, unsigned int options = parse_default, encoding_t encoding = encoding_auto);
/**
- * Parse the given XML string in-situ.
- * The string is modified; you should ensure that string data will persist throughout the
- * document's lifetime. Although, document does not gain ownership over the string, so you
- * should free the memory occupied by it manually.
+ * Load document from buffer
*
- * \param xmlstr - readwrite string with xml data
+ * \param contents - buffer contents
+ * \param size - buffer size in bytes
* \param options - parsing options
* \return parsing result
*/
- xml_parse_result parse(char* xmlstr, unsigned int options = parse_default);
-
+ xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, encoding_t encoding = encoding_auto);
+
/**
- * Parse the given XML string in-situ (gains ownership).
- * The string is modified; document gains ownership over the string, so you don't have to worry
- * about it's lifetime.
- * Call example: doc.parse(transfer_ownership_tag(), string, options);
+ * Load document from buffer in-situ.
+ * The buffer is modified; you should ensure that buffer data will persist throughout the document's
+ * lifetime. Document does not gain ownership over the buffer, so you should free the buffer memory manually.
*
- * \param xmlstr - readwrite string with xml data
+ * \param contents - buffer contents
+ * \param size - buffer size in bytes
* \param options - parsing options
* \return parsing result
*/
- xml_parse_result parse(const transfer_ownership_tag&, char* xmlstr, unsigned int options = parse_default);
-
+ xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, encoding_t encoding = encoding_auto);
+
+ /**
+ * Load document from buffer in-situ (gains buffer ownership).
+ * The buffer is modified; you should ensure that buffer data will persist throughout the document's
+ * lifetime. Document gains ownership over the buffer, so you should allocate the buffer with pugixml
+ * allocation function.
+ *
+ * \param contents - buffer contents
+ * \param size - buffer size in bytes
+ * \param options - parsing options
+ * \return parsing result
+ */
+ xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, encoding_t encoding = encoding_auto);
+
/**
* Save XML to writer
*
@@ -1801,7 +1902,27 @@ namespace pugi
* \param indent - indentation string
* \param flags - formatting flags
*/
- void save(xml_writer& writer, const char* indent = "\t", unsigned int flags = format_default) const;
+ void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, encoding_t encoding = encoding_auto) const;
+
+ #ifndef PUGIXML_NO_STL
+ /**
+ * Save XML to stream
+ *
+ * \param stream - output stream
+ * \param indent - indentation string
+ * \param flags - formatting flags
+ */
+ void save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, encoding_t encoding = encoding_auto) const;
+
+ /**
+ * Save XML to stream
+ *
+ * \param stream - output stream
+ * \param indent - indentation string
+ * \param flags - formatting flags
+ */
+ void save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const;
+ #endif
/**
* Save XML to file
@@ -1811,7 +1932,7 @@ namespace pugi
* \param flags - formatting flags
* \return success flag
*/
- bool save_file(const char* name, const char* indent = "\t", unsigned int flags = format_default) const;
+ bool save_file(const char* name, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, encoding_t encoding = encoding_auto) const;
/**
* Compute document order for the whole tree
@@ -2063,20 +2184,20 @@ namespace pugi
#ifndef PUGIXML_NO_STL
/**
- * Convert utf16 to utf8
+ * Convert wide string to utf8
*
- * \param str - input UTF16 string
+ * \param str - input wide string string
* \return output UTF8 string
*/
- std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str);
+ std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const wchar_t* str);
/**
- * Convert utf8 to utf16
+ * Convert utf8 to wide string
*
* \param str - input UTF8 string
- * \return output UTF16 string
+ * \return output wide string string
*/
- std::wstring PUGIXML_FUNCTION as_utf16(const char* str);
+ std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const char* str);
#endif
/**
@@ -2104,7 +2225,7 @@ namespace pugi
* \param allocate - allocation function
* \param deallocate - deallocation function
*
- * \note XPath-related allocations, as well as allocations in functions that return std::string (xml_node::path, as_utf8, as_utf16)
+ * \note XPath-related allocations, as well as allocations in functions that return std::string (xml_node::path, as_utf8, as_wide)
* are not performed via these functions.
* \note If you're using parse() with ownership transfer, you have to allocate the buffer you pass to parse() with allocation
* function you set via this function.
@@ -2128,6 +2249,15 @@ namespace pugi
deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function();
}
+#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
+namespace std
+{
+ // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
+ std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&);
+ std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&);
+}
+#endif
+
#endif
/**
diff --git a/src/pugixpath.cpp b/src/pugixpath.cpp
index fce7459..0dc66e6 100644
--- a/src/pugixpath.cpp
+++ b/src/pugixpath.cpp
@@ -16,21 +16,39 @@
#ifndef PUGIXML_NO_XPATH
#include <algorithm>
+#include <string>
#include <assert.h>
#include <stdio.h>
+#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <ctype.h>
#include <string.h>
+#ifdef PUGIXML_WCHAR_MODE
+# include <wchar.h>
+#endif
+
#if defined(_MSC_VER)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
# pragma warning(disable: 4996) // this function or variable may be unsafe
#endif
+// String utilities prototypes
+namespace pugi
+{
+ namespace impl
+ {
+ size_t strlen(const char_t* s);
+ void strcpy(char_t* dst, const char_t* src);
+ bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count);
+ void widen_ascii(wchar_t* dest, const char* source);
+ }
+}
+
namespace
{
using namespace pugi;
@@ -64,17 +82,32 @@ namespace
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
};
- inline bool is_chartypex(char c, chartypex ct)
+ inline bool is_chartypex(char_t c, chartypex ct)
{
+ #ifdef PUGIXML_WCHAR_MODE
+ unsigned int ch = static_cast<unsigned int>(c);
+
+ return !!((ch < 128 ? chartypex_table[ch] : chartypex_table[128]) & ct);
+ #else
return !!(chartypex_table[static_cast<unsigned char>(c)] & ct);
+ #endif
}
- bool starts_with(const std::string& s, const char* pattern)
+ bool starts_with(const string_t& s, const char_t* pattern)
{
- return s.compare(0, strlen(pattern), pattern) == 0;
+ return s.compare(0, impl::strlen(pattern), pattern) == 0;
}
- std::string string_value(const xpath_node& na)
+ const char_t* find_char(const char_t* s, char_t c)
+ {
+ #ifdef PUGIXML_WCHAR_MODE
+ return wcschr(s, c);
+ #else
+ return ::strchr(s, c);
+ #endif
+ }
+
+ string_t string_value(const xpath_node& na)
{
if (na.attribute())
return na.attribute().value();
@@ -93,7 +126,7 @@ namespace
case node_document:
case node_element:
{
- std::string result;
+ string_t result;
xml_node cur = n.first_child();
@@ -125,7 +158,7 @@ namespace
}
default:
- return "";
+ return string_t();
}
}
}
@@ -334,78 +367,78 @@ namespace
return (value != 0 && !is_nan(value));
}
- std::string convert_number_to_string(double value)
+ string_t convert_number_to_string(double value)
{
- if (is_nan(value)) return "NaN";
- else if (is_inf(value)) return value < 0 ? "-Infinity" : "Infinity";
-
- char buf[100];
+ if (is_nan(value)) return PUGIXML_TEXT("NaN");
+ else if (is_inf(value)) return value < 0 ? PUGIXML_TEXT("-Infinity") : PUGIXML_TEXT("Infinity");
+ else if (value == 0) return PUGIXML_TEXT("0");
- if (value == (int)value) sprintf(buf, "%d", (int)value);
- else
- {
- sprintf(buf, "%f", value);
+ char buf[512];
+ sprintf(buf, "%f", value);
- // trim trailing zeros after decimal point
- if (strchr(buf, '.'))
- {
- char* ptr = buf + strlen(buf) - 1;
- for (; *ptr == '0'; --ptr) ;
- *(ptr+1) = 0;
- }
+ // trim trailing zeros after decimal point
+ if (strchr(buf, '.'))
+ {
+ char* ptr = buf + strlen(buf) - 1;
+ for (; *ptr == '0'; --ptr) ;
+
+ // trim leftover decimal point (for integer numbers)
+ if (*ptr == '.') --ptr;
+
+ *(ptr+1) = 0;
}
+
+ #ifdef PUGIXML_WCHAR_MODE
+ wchar_t wbuf[512];
+ impl::widen_ascii(wbuf, buf);
- return std::string(buf);
+ return string_t(wbuf);
+ #else
+ return string_t(buf);
+ #endif
}
- double convert_string_to_number(const char* string)
+ bool check_string_to_number_format(const char_t* string)
{
+ // parse leading whitespace
while (is_chartypex(*string, ctx_space)) ++string;
-
- double sign = 1;
-
- if (*string == '-')
- {
- sign = -1;
- ++string;
- }
-
- double r = 0;
-
- if (!*string) return gen_nan();
-
- while (is_chartypex(*string, ctx_digit))
- {
- r = r * 10 + (*string - '0');
- ++string;
- }
-
- if (*string)
+
+ // parse sign
+ if (*string == '-') ++string;
+
+ if (!*string) return false;
+
+ // if there is no integer part, there should be a decimal part with at least one digit
+ if (!is_chartypex(string[0], ctx_digit) && (string[0] != '.' || !is_chartypex(string[1], ctx_digit))) return false;
+
+ // parse integer part
+ while (is_chartypex(*string, ctx_digit)) ++string;
+
+ // parse decimal part
+ if (*string == '.')
{
- if (is_chartypex(*string, ctx_space))
- {
- while (is_chartypex(*string, ctx_space)) ++string;
- return *string ? gen_nan() : r;
- }
-
- if (*string != '.') return gen_nan();
-
++string;
-
- double power = 0.1;
-
- while (is_chartypex(*string, ctx_digit))
- {
- r += power * (*string - '0');
- power /= 10;
- ++string;
- }
-
- while (is_chartypex(*string, ctx_space)) ++string;
- if (*string) return gen_nan();
+
+ while (is_chartypex(*string, ctx_digit)) ++string;
}
-
- return r * sign;
+
+ // parse trailing whitespace
+ while (is_chartypex(*string, ctx_space)) ++string;
+
+ return *string == 0;
+ }
+
+ double convert_string_to_number(const char_t* string)
+ {
+ // check string format
+ if (!check_string_to_number_format(string)) return gen_nan();
+
+ // parse string
+ #ifdef PUGIXML_WCHAR_MODE
+ return wcstod(string, 0);
+ #else
+ return atof(string);
+ #endif
}
double ieee754_round(double value)
@@ -413,18 +446,18 @@ namespace
return is_nan(value) ? value : floor(value + 0.5);
}
- const char* local_name(const char* name)
+ const char_t* local_name(const char_t* name)
{
- const char* p = strchr(name, ':');
+ const char_t* p = find_char(name, ':');
return p ? p + 1 : name;
}
- const char* namespace_uri(const xml_node& node)
+ const char_t* namespace_uri(const xml_node& node)
{
- const char* pos = strchr(node.name(), ':');
+ const char_t* pos = find_char(node.name(), ':');
- std::string ns = "xmlns";
+ string_t ns = PUGIXML_TEXT("xmlns");
if (pos)
{
@@ -443,17 +476,17 @@ namespace
p = p.parent();
}
- return "";
+ return PUGIXML_TEXT("");
}
- const char* namespace_uri(const xml_attribute& attr, const xml_node& parent)
+ const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent)
{
- const char* pos = strchr(attr.name(), ':');
+ const char_t* pos = find_char(attr.name(), ':');
// Default namespace does not apply to attributes
- if (!pos) return "";
+ if (!pos) return PUGIXML_TEXT("");
- std::string ns = "xmlns:";
+ string_t ns = PUGIXML_TEXT("xmlns:");
ns.append(attr.name(), pos);
xml_node p = parent;
@@ -467,7 +500,7 @@ namespace
p = p.parent();
}
- return "";
+ return PUGIXML_TEXT("");
}
template <class T> struct equal_to
@@ -850,9 +883,9 @@ namespace pugi
xpath_lexer& operator=(const xpath_lexer&);
private:
- const char* m_cur;
+ const char_t* m_cur;
- char* m_cur_lexeme_contents;
+ char_t* m_cur_lexeme_contents;
size_t m_clc_size;
size_t m_clc_capacity;
@@ -864,15 +897,15 @@ namespace pugi
m_clc_size = 0;
}
- void contents_push(char c)
+ void contents_push(char_t c)
{
if (m_clc_size == m_clc_capacity)
{
if (!m_clc_capacity) m_clc_capacity = 16;
else m_clc_capacity *= 2;
- char* s = new char[m_clc_capacity + 1];
- if (m_cur_lexeme_contents) strcpy(s, m_cur_lexeme_contents);
+ char_t* s = new char_t[m_clc_capacity + 1];
+ if (m_cur_lexeme_contents) impl::strcpy(s, m_cur_lexeme_contents);
delete[] m_cur_lexeme_contents;
m_cur_lexeme_contents = s;
@@ -883,7 +916,7 @@ namespace pugi
}
public:
- explicit xpath_lexer(const char* query): m_cur(query)
+ explicit xpath_lexer(const char_t* query): m_cur(query)
{
m_clc_capacity = m_clc_size = 0;
m_cur_lexeme_contents = 0;
@@ -896,12 +929,12 @@ namespace pugi
delete[] m_cur_lexeme_contents;
}
- const char* state() const
+ const char_t* state() const
{
return m_cur;
}
- void reset(const char* state)
+ void reset(const char_t* state)
{
m_cur = state;
next();
@@ -1070,7 +1103,7 @@ namespace pugi
case '"':
case '\'':
{
- char terminator = *m_cur;
+ char_t terminator = *m_cur;
++m_cur;
@@ -1153,9 +1186,9 @@ namespace pugi
return m_cur_lexeme;
}
- const char* contents() const
+ const char_t* contents() const
{
- return m_cur_lexeme_contents ? m_cur_lexeme_contents : "";
+ return m_cur_lexeme_contents ? m_cur_lexeme_contents : PUGIXML_TEXT("");
}
};
@@ -1275,7 +1308,7 @@ namespace pugi
// variable name for ast_variable
// string value for ast_constant
// node test for ast_step (node name/namespace/node type/pi target)
- const char* m_contents;
+ const char_t* m_contents;
// for t_step / t_predicate
axis_t m_axis;
@@ -1330,7 +1363,7 @@ namespace pugi
}
else if (lhs->rettype() == xpath_type_string)
{
- std::string l = lhs->eval_string(c);
+ string_t l = lhs->eval_string(c);
xpath_node_set rs = rhs->eval_node_set(c);
for (xpath_node_set::const_iterator ri = rs.begin(); ri != rs.end(); ++ri)
@@ -1362,7 +1395,7 @@ namespace pugi
else if (rhs->rettype() == xpath_type_string)
{
xpath_node_set ls = lhs->eval_node_set(c);
- std::string r = rhs->eval_string(c);
+ string_t r = rhs->eval_string(c);
for (xpath_node_set::const_iterator li = ls.begin(); li != ls.end(); ++li)
{
@@ -1482,12 +1515,12 @@ namespace pugi
// There are no attribute nodes corresponding to attributes that declare namespaces
// That is, "xmlns:..." or "xmlns"
- if (!strncmp(a.name(), "xmlns", 5) && (a.name()[5] == 0 || a.name()[5] == ':')) return;
+ if (impl::strequalrange(a.name(), PUGIXML_TEXT("xmlns"), 5) && (a.name()[5] == 0 || a.name()[5] == ':')) return;
switch (m_test)
{
case nodetest_name:
- if (!strcmp(a.name(), m_contents)) ns.push_back(xpath_node(a, parent));
+ if (impl::strequal(a.name(), m_contents)) ns.push_back(xpath_node(a, parent));
break;
case nodetest_type_node:
@@ -1496,7 +1529,7 @@ namespace pugi
break;
case nodetest_all_in_namespace:
- if (!strncmp(a.name(), m_contents, strlen(m_contents)))
+ if (impl::strequalrange(a.name(), m_contents, impl::strlen(m_contents)))
ns.push_back(xpath_node(a, parent));
break;
@@ -1512,7 +1545,7 @@ namespace pugi
switch (m_test)
{
case nodetest_name:
- if (n.type() == node_element && !strcmp(n.name(), m_contents)) ns.push_back(n);
+ if (n.type() == node_element && impl::strequal(n.name(), m_contents)) ns.push_back(n);
break;
case nodetest_type_node:
@@ -1535,7 +1568,7 @@ namespace pugi
break;
case nodetest_pi:
- if (n.type() == node_pi && !strcmp(n.name(), m_contents))
+ if (n.type() == node_pi && impl::strequal(n.name(), m_contents))
ns.push_back(n);
break;
@@ -1545,7 +1578,7 @@ namespace pugi
break;
case nodetest_all_in_namespace:
- if (n.type() == node_element && !strncmp(n.name(), m_contents, strlen(m_contents)))
+ if (n.type() == node_element && impl::strequalrange(n.name(), m_contents, impl::strlen(m_contents)))
ns.push_back(n);
break;
@@ -1898,18 +1931,18 @@ namespace pugi
}
}
- void set_contents(const char* value, xpath_allocator& a)
+ void set_contents(const char_t* value, xpath_allocator& a)
{
if (value)
{
- char* c = static_cast<char*>(a.alloc(strlen(value) + 1));
- strcpy(c, value);
+ char_t* c = static_cast<char_t*>(a.alloc((impl::strlen(value) + 1) * sizeof(char_t)));
+ impl::strcpy(c, value);
m_contents = c;
}
else m_contents = 0;
}
public:
- xpath_ast_node(ast_type_t type, const char* contents, xpath_allocator& a): m_type(type),
+ xpath_ast_node(ast_type_t type, const char_t* contents, xpath_allocator& a): m_type(type),
m_rettype(xpath_type_none), m_left(0), m_right(0), m_third(0), m_next(0), m_contents(0),
m_axis(axis_self), m_test(nodetest_none)
{
@@ -1928,7 +1961,7 @@ namespace pugi
{
}
- xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char* contents, xpath_allocator& a):
+ xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents, xpath_allocator& a):
m_type(type), m_rettype(xpath_type_none), m_left(left), m_right(0), m_third(0), m_next(0), m_contents(0),
m_axis(axis), m_test(test)
{
@@ -1958,10 +1991,10 @@ namespace pugi
else return m_right->eval_boolean(c);
case ast_op_equal:
- return compare_eq<equal_to<bool>, equal_to<double>, equal_to<std::string> >::run(m_left, m_right, c);
+ return compare_eq<equal_to<bool>, equal_to<double>, equal_to<string_t> >::run(m_left, m_right, c);
case ast_op_not_equal:
- return compare_eq<not_equal_to<bool>, not_equal_to<double>, not_equal_to<std::string> >::run(m_left, m_right, c);
+ return compare_eq<not_equal_to<bool>, not_equal_to<double>, not_equal_to<string_t> >::run(m_left, m_right, c);
case ast_op_less:
return compare_rel<less<double> >::run(m_left, m_right, c);
@@ -1980,10 +2013,10 @@ namespace pugi
case ast_func_contains:
{
- std::string lr = m_left->eval_string(c);
- std::string rr = m_right->eval_string(c);
+ string_t lr = m_left->eval_string(c);
+ string_t rr = m_right->eval_string(c);
- return rr.empty() || lr.find(rr) != std::string::npos;
+ return rr.empty() || lr.find(rr) != string_t::npos;
}
case ast_func_boolean:
@@ -2002,18 +2035,18 @@ namespace pugi
{
if (c.n.attribute()) return false;
- std::string lang = m_left->eval_string(c);
+ string_t lang = m_left->eval_string(c);
for (xml_node n = c.n.node(); n; n = n.parent())
{
- xml_attribute a = n.attribute("xml:lang");
+ xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
if (a)
{
- const char* value = a.value();
+ const char_t* value = a.value();
// strnicmp / strncasecmp is not portable
- for (const char* lit = lang.c_str(); *lit; ++lit)
+ for (const char_t* lit = lang.c_str(); *lit; ++lit)
{
if (tolower(*lit) != tolower(*value)) return false;
++value;
@@ -2145,7 +2178,7 @@ namespace pugi
}
}
- std::string eval_string(xpath_context& c)
+ string_t eval_string(xpath_context& c)
{
switch (m_type)
{
@@ -2163,7 +2196,7 @@ namespace pugi
case ast_func_local_name_1:
{
xpath_node_set ns = m_left->eval_node_set(c);
- if (ns.empty()) return "";
+ if (ns.empty()) return string_t();
xpath_node na = ns.first();
@@ -2182,7 +2215,7 @@ namespace pugi
case ast_func_name_1:
{
xpath_node_set ns = m_left->eval_node_set(c);
- if (ns.empty()) return "";
+ if (ns.empty()) return string_t();
xpath_node na = ns.first();
@@ -2201,7 +2234,7 @@ namespace pugi
case ast_func_namespace_uri_1:
{
xpath_node_set ns = m_left->eval_node_set(c);
- if (ns.empty()) return "";
+ if (ns.empty()) return string_t();
xpath_node na = ns.first();
@@ -2217,7 +2250,7 @@ namespace pugi
case ast_func_concat:
{
- std::string r = m_left->eval_string(c);
+ string_t r = m_left->eval_string(c);
for (xpath_ast_node* n = m_right; n; n = n->m_next)
r += n->eval_string(c);
@@ -2227,31 +2260,31 @@ namespace pugi
case ast_func_substring_before:
{
- std::string s = m_left->eval_string(c);
- std::string::size_type pos = s.find(m_right->eval_string(c));
+ string_t s = m_left->eval_string(c);
+ string_t::size_type pos = s.find(m_right->eval_string(c));
- if (pos == std::string::npos) return "";
- else return std::string(s.begin(), s.begin() + pos);
+ if (pos == string_t::npos) return string_t();
+ else return string_t(s.begin(), s.begin() + pos);
}
case ast_func_substring_after:
{
- std::string s = m_left->eval_string(c);
- std::string p = m_right->eval_string(c);
+ string_t s = m_left->eval_string(c);
+ string_t p = m_right->eval_string(c);
- std::string::size_type pos = s.find(p);
+ string_t::size_type pos = s.find(p);
- if (pos == std::string::npos) return "";
- else return std::string(s.begin() + pos + p.length(), s.end());
+ if (pos == string_t::npos) return string_t();
+ else return string_t(s.begin() + pos + p.length(), s.end());
}
case ast_func_substring_2:
{
- std::string s = m_left->eval_string(c);
+ string_t s = m_left->eval_string(c);
double first = ieee754_round(m_right->eval_number(c));
- if (is_nan(first)) return ""; // NaN
- else if (first >= s.length() + 1) return "";
+ if (is_nan(first)) return string_t(); // NaN
+ else if (first >= s.length() + 1) return string_t();
size_t pos = first < 1 ? 1 : (size_t)first;
@@ -2260,13 +2293,13 @@ namespace pugi
case ast_func_substring_3:
{
- std::string s = m_left->eval_string(c);
+ string_t s = m_left->eval_string(c);
double first = ieee754_round(m_right->eval_number(c));
double last = first + ieee754_round(m_third->eval_number(c));
- if (is_nan(first) || is_nan(last)) return "";
- else if (first >= s.length() + 1) return "";
- else if (first >= last) return "";
+ if (is_nan(first) || is_nan(last)) return string_t();
+ else if (first >= s.length() + 1) return string_t();
+ else if (first >= last) return string_t();
size_t pos = first < 1 ? 1 : (size_t)first;
size_t end = last >= s.length() + 1 ? s.length() + 1 : (size_t)last;
@@ -2280,12 +2313,12 @@ namespace pugi
case ast_func_normalize_space_0:
case ast_func_normalize_space_1:
{
- std::string s = m_type == ast_func_normalize_space_0 ? string_value(c.n) : m_left->eval_string(c);
+ string_t s = m_type == ast_func_normalize_space_0 ? string_value(c.n) : m_left->eval_string(c);
- std::string r;
+ string_t r;
r.reserve(s.size());
- for (std::string::const_iterator it = s.begin(); it != s.end(); ++it)
+ for (string_t::const_iterator it = s.begin(); it != s.end(); ++it)
{
if (is_chartypex(*it, ctx_space))
{
@@ -2295,8 +2328,8 @@ namespace pugi
else r += *it;
}
- std::string::size_type pos = r.find_last_not_of(' ');
- if (pos == std::string::npos) r = "";
+ string_t::size_type pos = r.find_last_not_of(' ');
+ if (pos == string_t::npos) r = string_t();
else r.erase(r.begin() + pos + 1, r.end());
return r;
@@ -2304,15 +2337,15 @@ namespace pugi
case ast_func_translate:
{
- std::string s = m_left->eval_string(c);
- std::string from = m_right->eval_string(c);
- std::string to = m_third->eval_string(c);
+ string_t s = m_left->eval_string(c);
+ string_t from = m_right->eval_string(c);
+ string_t to = m_third->eval_string(c);
- for (std::string::iterator it = s.begin(); it != s.end(); )
+ for (string_t::iterator it = s.begin(); it != s.end(); )
{
- std::string::size_type pos = from.find(*it);
+ string_t::size_type pos = from.find(*it);
- if (pos == std::string::npos)
+ if (pos == string_t::npos)
++it;
else if (pos >= to.length())
it = s.erase(it);
@@ -2328,7 +2361,7 @@ namespace pugi
switch (m_rettype)
{
case xpath_type_boolean:
- return eval_boolean(c) ? "true" : "false";
+ return eval_boolean(c) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false");
case xpath_type_number:
return convert_number_to_string(eval_number(c));
@@ -2336,12 +2369,12 @@ namespace pugi
case xpath_type_node_set:
{
xpath_node_set ns = eval_node_set(c);
- return ns.empty() ? std::string("") : string_value(ns.first());
+ return ns.empty() ? string_t() : string_value(ns.first());
}
default:
assert(!"Wrong expression for ret type string");
- return "";
+ return string_t();
}
}
}
@@ -2835,100 +2868,100 @@ namespace pugi
xpath_parser(const xpath_parser&);
xpath_parser& operator=(const xpath_parser&);
- ast_type_t parse_function_name(const std::string& name, size_t argc)
+ ast_type_t parse_function_name(const string_t& name, size_t argc)
{
switch (name[0])
{
case 'b':
- if (name == "boolean" && argc == 1)
+ if (name == PUGIXML_TEXT("boolean") && argc == 1)
return ast_func_boolean;
break;
case 'c':
- if (name == "count" && argc == 1)
+ if (name == PUGIXML_TEXT("count") && argc == 1)
return ast_func_count;
- else if (name == "contains" && argc == 2)
+ else if (name == PUGIXML_TEXT("contains") && argc == 2)
return ast_func_contains;
- else if (name == "concat" && argc == 2)
+ else if (name == PUGIXML_TEXT("concat") && argc == 2)
return ast_func_concat;
- else if (name == "ceiling" && argc == 1)
+ else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
return ast_func_ceiling;
break;
case 'f':
- if (name == "false" && argc == 0)
+ if (name == PUGIXML_TEXT("false") && argc == 0)
return ast_func_false;
- else if (name == "floor" && argc == 1)
+ else if (name == PUGIXML_TEXT("floor") && argc == 1)
return ast_func_floor;
break;
case 'i':
- if (name == "id" && argc == 1)
+ if (name == PUGIXML_TEXT("id") && argc == 1)
return ast_func_id;
break;
case 'l':
- if (name == "last" && argc == 0)
+ if (name == PUGIXML_TEXT("last") && argc == 0)
return ast_func_last;
- else if (name == "lang" && argc == 1)
+ else if (name == PUGIXML_TEXT("lang") && argc == 1)
return ast_func_lang;
- else if (name == "local-name" && argc <= 1)
+ else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
return argc == 0 ? ast_func_local_name_0 : ast_func_local_name_1;
break;
case 'n':
- if (name == "name" && argc <= 1)
+ if (name == PUGIXML_TEXT("name") && argc <= 1)
return argc == 0 ? ast_func_name_0 : ast_func_name_1;
- else if (name == "namespace-uri" && argc <= 1)
+ else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
return argc == 0 ? ast_func_namespace_uri_0 : ast_func_namespace_uri_1;
- else if (name == "normalize-space" && argc <= 1)
+ else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
return argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1;
- else if (name == "not" && argc == 1)
+ else if (name == PUGIXML_TEXT("not") && argc == 1)
return ast_func_not;
- else if (name == "number" && argc <= 1)
+ else if (name == PUGIXML_TEXT("number") && argc <= 1)
return argc == 0 ? ast_func_number_0 : ast_func_number_1;
break;
case 'p':
- if (name == "position" && argc == 0)
+ if (name == PUGIXML_TEXT("position") && argc == 0)
return ast_func_position;
break;
case 'r':
- if (name == "round" && argc == 1)
+ if (name == PUGIXML_TEXT("round") && argc == 1)
return ast_func_round;
break;
case 's':
- if (name == "string" && argc <= 1)
+ if (name == PUGIXML_TEXT("string") && argc <= 1)
return argc == 0 ? ast_func_string_0 : ast_func_string_1;
- else if (name == "string-length" && argc <= 1)
+ else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
return argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1;
- else if (name == "starts-with" && argc == 2)
+ else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
return ast_func_starts_with;
- else if (name == "substring-before" && argc == 2)
+ else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
return ast_func_substring_before;
- else if (name == "substring-after" && argc == 2)
+ else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
return ast_func_substring_after;
- else if (name == "substring" && (argc == 2 || argc == 3))
+ else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
return argc == 2 ? ast_func_substring_2 : ast_func_substring_3;
- else if (name == "sum" && argc == 1)
+ else if (name == PUGIXML_TEXT("sum") && argc == 1)
return ast_func_sum;
break;
case 't':
- if (name == "translate" && argc == 3)
+ if (name == PUGIXML_TEXT("translate") && argc == 3)
return ast_func_translate;
- else if (name == "true" && argc == 0)
+ else if (name == PUGIXML_TEXT("true") && argc == 0)
return ast_func_true;
break;
@@ -2937,62 +2970,62 @@ namespace pugi
return ast_none;
}
- axis_t parse_axis_name(const std::string& name, bool& specified)
+ axis_t parse_axis_name(const string_t& name, bool& specified)
{
specified = true;
switch (name[0])
{
case 'a':
- if (name == "ancestor")
+ if (name == PUGIXML_TEXT("ancestor"))
return axis_ancestor;
- else if (name == "ancestor-or-self")
+ else if (name == PUGIXML_TEXT("ancestor-or-self"))
return axis_ancestor_or_self;
- else if (name == "attribute")
+ else if (name == PUGIXML_TEXT("attribute"))
return axis_attribute;
break;
case 'c':
- if (name == "child")
+ if (name == PUGIXML_TEXT("child"))
return axis_child;
break;
case 'd':
- if (name == "descendant")
+ if (name == PUGIXML_TEXT("descendant"))
return axis_descendant;
- else if (name == "descendant-or-self")
+ else if (name == PUGIXML_TEXT("descendant-or-self"))
return axis_descendant_or_self;
break;
case 'f':
- if (name == "following")
+ if (name == PUGIXML_TEXT("following"))
return axis_following;
- else if (name == "following-sibling")
+ else if (name == PUGIXML_TEXT("following-sibling"))
return axis_following_sibling;
break;
case 'n':
- if (name == "namespace")
+ if (name == PUGIXML_TEXT("namespace"))
return axis_namespace;
break;
case 'p':
- if (name == "parent")
+ if (name == PUGIXML_TEXT("parent"))
return axis_parent;
- else if (name == "preceding")
+ else if (name == PUGIXML_TEXT("preceding"))
return axis_preceding;
- else if (name == "preceding-sibling")
+ else if (name == PUGIXML_TEXT("preceding-sibling"))
return axis_preceding_sibling;
break;
case 's':
- if (name == "self")
+ if (name == PUGIXML_TEXT("self"))
return axis_self;
break;
@@ -3002,30 +3035,30 @@ namespace pugi
return axis_child;
}
- nodetest_t parse_node_test_type(const char* name)
+ nodetest_t parse_node_test_type(const char_t* name)
{
switch (name[0])
{
case 'c':
- if (!strcmp(name, "comment"))
+ if (impl::strequal(name, PUGIXML_TEXT("comment")))
return nodetest_type_comment;
break;
case 'n':
- if (!strcmp(name, "node"))
+ if (impl::strequal(name, PUGIXML_TEXT("node")))
return nodetest_type_node;
break;
case 'p':
- if (!strcmp(name, "processing-instruction"))
+ if (impl::strequal(name, PUGIXML_TEXT("processing-instruction")))
return nodetest_type_pi;
break;
case 't':
- if (!strcmp(name, "text"))
+ if (impl::strequal(name, PUGIXML_TEXT("text")))
return nodetest_type_text;
break;
@@ -3087,10 +3120,10 @@ namespace pugi
xpath_ast_node* args[4];
size_t argc = 0;
- std::string function = m_lexer.contents();
+ string_t function = m_lexer.contents();
m_lexer.next();
- bool func_concat = (function == "concat");
+ bool func_concat = (function == PUGIXML_TEXT("concat"));
xpath_ast_node* last_concat = 0;
if (m_lexer.current() != lex_open_brace)
@@ -3160,7 +3193,9 @@ namespace pugi
{
m_lexer.next();
- n = new (m_alloc.node()) xpath_ast_node(ast_filter, n, parse_expression(), axis_child);
+ xpath_ast_node* expr = parse_expression();
+
+ n = new (m_alloc.node()) xpath_ast_node(ast_filter, n, expr, axis_child);
if (m_lexer.current() != lex_close_square_brace)
throw xpath_exception("Unmatched square brace");
@@ -3202,7 +3237,7 @@ namespace pugi
}
nodetest_t nt_type = nodetest_none;
- std::string nt_name;
+ string_t nt_name;
if (m_lexer.current() == lex_string)
{
@@ -3251,9 +3286,9 @@ namespace pugi
if (nt_type == nodetest_none) throw xpath_exception("Unrecognized node type");
- nt_name = "";
+ nt_name = string_t();
}
- else if (nt_name == "processing-instruction")
+ else if (nt_name == PUGIXML_TEXT("processing-instruction"))
{
if (m_lexer.current() != lex_quoted_string)
throw xpath_exception("Only literals are allowed as arguments to processing-instruction()");
@@ -3273,7 +3308,7 @@ namespace pugi
// QName or NCName:*
else
{
- std::string::size_type colon_pos = nt_name.find(':');
+ string_t::size_type colon_pos = nt_name.find(':');
if (nt_name.size() > 2 && colon_pos == nt_name.size() - 2 && nt_name[nt_name.size() - 1] == '*') // NCName:*
{
@@ -3300,7 +3335,9 @@ namespace pugi
{
m_lexer.next();
- xpath_ast_node* pred = new (m_alloc.node()) xpath_ast_node(ast_predicate, parse_expression(), 0, axis);
+ xpath_ast_node* expr = parse_expression();
+
+ xpath_ast_node* pred = new (m_alloc.node()) xpath_ast_node(ast_predicate, expr, 0, axis);
if (m_lexer.current() != lex_close_square_brace)
throw xpath_exception("unmatched square brace");
@@ -3341,7 +3378,7 @@ namespace pugi
if (m_lexer.current() == lex_slash)
{
// Save state for next lexeme - that is, whatever follows '/'
- const char* state = 0; // gcc3 "variable might be used uninitialized in this function" bug workaround
+ const char_t* state = 0; // gcc3 "variable might be used uninitialized in this function" bug workaround
state = m_lexer.state();
m_lexer.next();
@@ -3395,7 +3432,7 @@ namespace pugi
if (m_lexer.current() == lex_string)
{
// This is either a function call, or not - if not, we shall proceed with location path
- const char* state = m_lexer.state();
+ const char_t* state = m_lexer.state();
while (is_chartypex(*state, ctx_space)) ++state;
@@ -3433,7 +3470,9 @@ namespace pugi
{
m_lexer.next();
- n = new (m_alloc.node()) xpath_ast_node(ast_op_union, n, parse_union_expression());
+ xpath_ast_node* expr = parse_union_expression();
+
+ n = new (m_alloc.node()) xpath_ast_node(ast_op_union, n, expr);
}
return n;
@@ -3446,7 +3485,9 @@ namespace pugi
{
m_lexer.next();
- return new (m_alloc.node()) xpath_ast_node(ast_op_negate, parse_unary_expression());
+ xpath_ast_node* expr = parse_unary_expression();
+
+ return new (m_alloc.node()) xpath_ast_node(ast_op_negate, expr);
}
else return parse_union_expression();
}
@@ -3460,13 +3501,15 @@ namespace pugi
xpath_ast_node* n = parse_unary_expression();
while (m_lexer.current() == lex_multiply || (m_lexer.current() == lex_string &&
- (!strcmp(m_lexer.contents(), "mod") || !strcmp(m_lexer.contents(), "div"))))
+ (impl::strequal(m_lexer.contents(), PUGIXML_TEXT("mod")) || impl::strequal(m_lexer.contents(), PUGIXML_TEXT("div")))))
{
ast_type_t op = m_lexer.current() == lex_multiply ? ast_op_multiply :
- !strcmp(m_lexer.contents(), "div") ? ast_op_divide : ast_op_mod;
+ impl::strequal(m_lexer.contents(), PUGIXML_TEXT("div")) ? ast_op_divide : ast_op_mod;
m_lexer.next();
- n = new (m_alloc.node()) xpath_ast_node(op, n, parse_unary_expression());
+ xpath_ast_node* expr = parse_unary_expression();
+
+ n = new (m_alloc.node()) xpath_ast_node(op, n, expr);
}
return n;
@@ -3485,7 +3528,9 @@ namespace pugi
m_lexer.next();
- n = new (m_alloc.node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, n, parse_multiplicative_expression());
+ xpath_ast_node* expr = parse_multiplicative_expression();
+
+ n = new (m_alloc.node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, n, expr);
}
return n;
@@ -3506,9 +3551,10 @@ namespace pugi
lexeme_t l = m_lexer.current();
m_lexer.next();
+ xpath_ast_node* expr = parse_additive_expression();
+
n = new (m_alloc.node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater :
- l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal,
- n, parse_additive_expression());
+ l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, n, expr);
}
return n;
@@ -3527,7 +3573,9 @@ namespace pugi
m_lexer.next();
- n = new (m_alloc.node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, n, parse_relational_expression());
+ xpath_ast_node* expr = parse_relational_expression();
+
+ n = new (m_alloc.node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, n, expr);
}
return n;
@@ -3538,11 +3586,13 @@ namespace pugi
{
xpath_ast_node* n = parse_equality_expression();
- while (m_lexer.current() == lex_string && !strcmp(m_lexer.contents(), "and"))
+ while (m_lexer.current() == lex_string && impl::strequal(m_lexer.contents(), PUGIXML_TEXT("and")))
{
m_lexer.next();
- n = new (m_alloc.node()) xpath_ast_node(ast_op_and, n, parse_equality_expression());
+ xpath_ast_node* expr = parse_equality_expression();
+
+ n = new (m_alloc.node()) xpath_ast_node(ast_op_and, n, expr);
}
return n;
@@ -3553,11 +3603,13 @@ namespace pugi
{
xpath_ast_node* n = parse_and_expression();
- while (m_lexer.current() == lex_string && !strcmp(m_lexer.contents(), "or"))
+ while (m_lexer.current() == lex_string && impl::strequal(m_lexer.contents(), PUGIXML_TEXT("or")))
{
m_lexer.next();
- n = new (m_alloc.node()) xpath_ast_node(ast_op_or, n, parse_and_expression());
+ xpath_ast_node* expr = parse_and_expression();
+
+ n = new (m_alloc.node()) xpath_ast_node(ast_op_or, n, expr);
}
return n;
@@ -3570,7 +3622,7 @@ namespace pugi
}
public:
- explicit xpath_parser(const char* query, xpath_allocator& alloc): m_alloc(alloc), m_lexer(query)
+ explicit xpath_parser(const char_t* query, xpath_allocator& alloc): m_alloc(alloc), m_lexer(query)
{
}
@@ -3588,7 +3640,7 @@ namespace pugi
}
};
- xpath_query::xpath_query(const char* query): m_alloc(0), m_root(0)
+ xpath_query::xpath_query(const char_t* query): m_alloc(0), m_root(0)
{
compile(query);
}
@@ -3598,7 +3650,7 @@ namespace pugi
delete m_alloc;
}
- void xpath_query::compile(const char* query)
+ void xpath_query::compile(const char_t* query)
{
delete m_alloc;
m_alloc = new xpath_allocator;
@@ -3644,9 +3696,9 @@ namespace pugi
return m_root->eval_number(c);
}
- std::string xpath_query::evaluate_string(const xml_node& n) const
+ string_t xpath_query::evaluate_string(const xml_node& n) const
{
- if (!m_root) return std::string();
+ if (!m_root) return string_t();
xpath_context c;
@@ -3673,7 +3725,7 @@ namespace pugi
return m_root->eval_node_set(c);
}
- xpath_node xml_node::select_single_node(const char* query) const
+ xpath_node xml_node::select_single_node(const char_t* query) const
{
xpath_query q(query);
return select_single_node(q);
@@ -3685,7 +3737,7 @@ namespace pugi
return s.empty() ? xpath_node() : s.first();
}
- xpath_node_set xml_node::select_nodes(const char* query) const
+ xpath_node_set xml_node::select_nodes(const char_t* query) const
{
xpath_query q(query);
return select_nodes(q);
diff --git a/tests/allocator.cpp b/tests/allocator.cpp
new file mode 100644
index 0000000..7075194
--- /dev/null
+++ b/tests/allocator.cpp
@@ -0,0 +1,89 @@
+#include "allocator.hpp"
+
+#include <string.h>
+
+// Low-level allocation functions
+#if defined(_WIN32) || defined(_WIN64)
+# ifdef __MWERKS__
+# pragma ANSI_strict off // disable ANSI strictness to include windows.h
+# pragma cpp_extensions on // enable some extensions to include windows.h
+# endif
+
+# include <windows.h>
+
+namespace
+{
+ const size_t PAGE_SIZE = 4096;
+
+ void* allocate(size_t size)
+ {
+ size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+
+ void* ptr = VirtualAlloc(0, aligned_size + PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ if (!ptr) return 0;
+
+ void* end = (char*)ptr + aligned_size;
+
+ DWORD old_flags;
+ VirtualProtect(end, PAGE_SIZE, PAGE_NOACCESS, &old_flags);
+
+ return (char*)end - size;
+ }
+
+ void deallocate(void* ptr, size_t size)
+ {
+ size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+
+ void* rptr = (char*)ptr + size - aligned_size;
+
+ DWORD old_flags;
+ VirtualProtect(rptr, aligned_size + PAGE_SIZE, PAGE_NOACCESS, &old_flags);
+ }
+}
+#else
+# include <stdlib.h>
+
+namespace
+{
+ void* allocate(size_t size)
+ {
+ return malloc(size);
+ }
+
+ void deallocate(void* ptr, size_t size)
+ {
+ (void)size;
+
+ free(ptr);
+ }
+}
+#endif
+
+// High-level allocation functions
+void* memory_allocate(size_t size)
+{
+ void* result = allocate(size + sizeof(size_t));
+ if (!result) return 0;
+
+ memcpy(result, &size, sizeof(size_t));
+
+ return (size_t*)result + 1;
+}
+
+size_t memory_size(void* ptr)
+{
+ size_t result;
+ memcpy(&result, (size_t*)ptr - 1, sizeof(size_t));
+
+ return result;
+}
+
+void memory_deallocate(void* ptr)
+{
+ if (!ptr) return;
+
+ size_t size = memory_size(ptr);
+
+ deallocate((size_t*)ptr - 1, size + sizeof(size_t));
+}
+
diff --git a/tests/allocator.hpp b/tests/allocator.hpp
new file mode 100644
index 0000000..a2022fe
--- /dev/null
+++ b/tests/allocator.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <stddef.h>
+
+void* memory_allocate(size_t size);
+size_t memory_size(void* ptr);
+void memory_deallocate(void* ptr);
diff --git a/tests/autotest.pl b/tests/autotest.pl
new file mode 100644
index 0000000..683d4c3
--- /dev/null
+++ b/tests/autotest.pl
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+
+sub permute
+{
+ my @defines = @_;
+ my @result = ('');
+
+ foreach $define (@defines)
+ {
+ push @result, map { length($_) == 0 ? $define : "$_,$define" } @result;
+ }
+
+ @result;
+}
+
+$fast = (shift eq 'fast');
+@toolsets = ($^O =~ /win/i) ? (bcc, cw, dmc, ic8, mingw34, mingw44, mingw45, msvc6, msvc7, msvc71, msvc8, msvc9, msvc9_x64, msvc10) : (gcc);
+@configurations = (debug, release);
+@defines = (PUGIXML_NO_XPATH, PUGIXML_NO_EXCEPTIONS, PUGIXML_NO_STL, PUGIXML_WCHAR_MODE);
+@definesabbr = (noxpath, noexcept, nostl, wchar);
+
+if ($fast)
+{
+ @defines = (PUGIXML_WCHAR_MODE);
+ @definesabbr = (wchar);
+}
+
+@definesets = permute(@defines);
+
+$fail = 0;
+
+system("echo ### autotest begin >autotest.log");
+
+%results = ();
+
+foreach $toolset (@toolsets)
+{
+ foreach $configuration (@configurations)
+ {
+ foreach $defineset (@definesets)
+ {
+ $defineabbr = $defineset;
+ $defineabbr =~ s/,/ /g;
+
+ for ($i = 0; $i < $#definesabbr + 1; ++$i)
+ {
+ $defineabbr =~ s/$defines[$i]/$definesabbr[$i]/;
+ }
+
+ if ($defineabbr !~ /noxpath/ && $defineabbr =~ /noexcept/) { next; }
+ if ($defineabbr !~ /noxpath/ && $defineabbr =~ /nostl/) { next; }
+
+ print "*** testing $toolset/$configuration ($defineabbr) ... ***\n";
+
+ my $cmdline = "jam toolset=$toolset configuration=$configuration defines=$defineset";
+ my $coverage_pugixml = 0;
+ my $coverage_pugixpath = 0;
+
+ system("echo ^# $cmdline run_tests >>autotest.log");
+ $result = system("$cmdline run_tests >>autotest.log");
+
+ # get coverage
+ if ($result == 0 && $toolset =~ /mingw|gcc/)
+ {
+ $coverage = `$cmdline coverage`;
+
+ $coverage_pugixml = $1 if ($coverage =~ /pugixml\.cpp' executed:([^%]+)%/);
+ $coverage_pugixpath = $1 if ($coverage =~ /pugixpath\.cpp' executed:([^%]+)%/);
+ }
+
+ # record failures
+ $fail = 1 if ($result != 0);
+
+ # print build report
+ my $report = "";
+
+ if ($result == 0)
+ {
+ my $align = ($coverage_pugixml > 0 || $coverage_pugixpath > 0) ? 'left' : 'center';
+
+ $report .= "<td bgcolor='#00ff00' align='$align'>passed";
+
+ if ($coverage_pugixml > 0 || $coverage_pugixpath > 0)
+ {
+ $report .= " <font size='-2'>$coverage_pugixml% / $coverage_pugixpath%</font>";
+ }
+
+ $report .= "</td>"
+
+ }
+ else
+ {
+ $report .= "<td bgcolor='#ff0000' align='center'>failed</td>"
+ }
+
+ $results{"$configuration $defineabbr"}{$toolset} = $report;
+ }
+
+ last if ($fast);
+ }
+}
+
+system("echo ### autotest end >>autotest.log");
+
+$date = scalar localtime;
+
+$report = <<END;
+<html><head><title>pugixml autotest report</title></head><body>
+<h3>pugixml autotest report</h3>
+<table border=0 cellspacing=0 cellpadding=4>
+<tr><td></td>
+END
+
+foreach $toolset (@toolsets)
+{
+ $report .= "<th>$toolset</th>";
+}
+
+$report .= "</tr>\n";
+
+foreach $k (sort {$a cmp $b} keys %results)
+{
+ $report .= "<tr><td>$k</td>";
+
+ foreach $toolset (@toolsets)
+ {
+ $report .= $results{$k}{$toolset};
+ }
+
+ $report .= "</tr>\n";
+}
+
+$report .= <<END;
+</table><br>
+Generated on $date
+</body></html>
+END
+
+open FILE, ">autotest.html";
+print FILE $report;
+close FILE;
diff --git a/tests/data/empty.xml b/tests/data/empty.xml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/data/empty.xml
diff --git a/tests/data/multiline.xml b/tests/data/multiline.xml
new file mode 100644
index 0000000..3607e7f
--- /dev/null
+++ b/tests/data/multiline.xml
@@ -0,0 +1,3 @@
+<node1 />
+<node2 />
+<node3 />
diff --git a/tests/data/utftest_utf16_be.xml b/tests/data/utftest_utf16_be.xml
new file mode 100644
index 0000000..025d079
--- /dev/null
+++ b/tests/data/utftest_utf16_be.xml
Binary files differ
diff --git a/tests/data/utftest_utf16_be_bom.xml b/tests/data/utftest_utf16_be_bom.xml
new file mode 100644
index 0000000..080f4e2
--- /dev/null
+++ b/tests/data/utftest_utf16_be_bom.xml
Binary files differ
diff --git a/tests/data/utftest_utf16_be_clean.xml b/tests/data/utftest_utf16_be_clean.xml
new file mode 100644
index 0000000..545af02
--- /dev/null
+++ b/tests/data/utftest_utf16_be_clean.xml
Binary files differ
diff --git a/tests/data/utftest_utf16_be_nodecl.xml b/tests/data/utftest_utf16_be_nodecl.xml
new file mode 100644
index 0000000..450f705
--- /dev/null
+++ b/tests/data/utftest_utf16_be_nodecl.xml
Binary files differ
diff --git a/tests/data/utftest_utf16_le.xml b/tests/data/utftest_utf16_le.xml
new file mode 100644
index 0000000..df5a8f7
--- /dev/null
+++ b/tests/data/utftest_utf16_le.xml
Binary files differ
diff --git a/tests/data/utftest_utf16_le_bom.xml b/tests/data/utftest_utf16_le_bom.xml
new file mode 100644
index 0000000..420f62a
--- /dev/null
+++ b/tests/data/utftest_utf16_le_bom.xml
Binary files differ
diff --git a/tests/data/utftest_utf16_le_clean.xml b/tests/data/utftest_utf16_le_clean.xml
new file mode 100644
index 0000000..79563c5
--- /dev/null
+++ b/tests/data/utftest_utf16_le_clean.xml
Binary files differ
diff --git a/tests/data/utftest_utf16_le_nodecl.xml b/tests/data/utftest_utf16_le_nodecl.xml
new file mode 100644
index 0000000..b52865b
--- /dev/null
+++ b/tests/data/utftest_utf16_le_nodecl.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_be.xml b/tests/data/utftest_utf32_be.xml
new file mode 100644
index 0000000..ac7da09
--- /dev/null
+++ b/tests/data/utftest_utf32_be.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_be_bom.xml b/tests/data/utftest_utf32_be_bom.xml
new file mode 100644
index 0000000..a242003
--- /dev/null
+++ b/tests/data/utftest_utf32_be_bom.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_be_clean.xml b/tests/data/utftest_utf32_be_clean.xml
new file mode 100644
index 0000000..df9fe01
--- /dev/null
+++ b/tests/data/utftest_utf32_be_clean.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_be_nodecl.xml b/tests/data/utftest_utf32_be_nodecl.xml
new file mode 100644
index 0000000..b450b48
--- /dev/null
+++ b/tests/data/utftest_utf32_be_nodecl.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_le.xml b/tests/data/utftest_utf32_le.xml
new file mode 100644
index 0000000..79fd27a
--- /dev/null
+++ b/tests/data/utftest_utf32_le.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_le_bom.xml b/tests/data/utftest_utf32_le_bom.xml
new file mode 100644
index 0000000..995e02c
--- /dev/null
+++ b/tests/data/utftest_utf32_le_bom.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_le_clean.xml b/tests/data/utftest_utf32_le_clean.xml
new file mode 100644
index 0000000..70d1c75
--- /dev/null
+++ b/tests/data/utftest_utf32_le_clean.xml
Binary files differ
diff --git a/tests/data/utftest_utf32_le_nodecl.xml b/tests/data/utftest_utf32_le_nodecl.xml
new file mode 100644
index 0000000..c3c0329
--- /dev/null
+++ b/tests/data/utftest_utf32_le_nodecl.xml
Binary files differ
diff --git a/tests/data/utftest_utf8.xml b/tests/data/utftest_utf8.xml
new file mode 100644
index 0000000..81f9059
--- /dev/null
+++ b/tests/data/utftest_utf8.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!DOCTYPE 週報 SYSTEM "weekly-utf-8.dtd">
+<!-- 週報サンプル -->
+<週報>
+ <English name="name" value="value">The world has many languages</English>
+ <Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
+ <Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
+ <SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
+ <Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
+ <汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
+ <Heavy>&quot;Mëtæl!&quot;</Heavy>
+ <ä>Umlaut Element</ä>
+
+ <年月週>
+ <年度>1997</年度>
+ <月度>1</月度>
+ <週>1</週>
+ </年月週>
+
+ <氏名>
+ <氏>山田</氏>
+ <名>太郎</名>
+ </氏名>
+
+ <業務報告リスト>
+ <業務報告>
+ <業務名>XMLエディターの作成</業務名>
+ <業務コード>X3355-23</業務コード>
+ <工数管理>
+ <見積もり工数>1600</見積もり工数>
+ <実績工数>320</実績工数>
+ <当月見積もり工数>160</当月見積もり工数>
+ <当月実績工数>24</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P>XMLエディターの基本仕様の作成</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>XMLエディターの基本仕様の作成</P>
+ </実施事項>
+ <実施事項>
+ <P>競合他社製品の機能調査</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>特になし</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>XMLとは何かわからない。</P>
+ </問題点対策>
+ </業務報告>
+
+ <業務報告>
+ <業務名>検索エンジンの開発</業務名>
+ <業務コード>S8821-76</業務コード>
+ <工数管理>
+ <見積もり工数>120</見積もり工数>
+ <実績工数>6</実績工数>
+ <当月見積もり工数>32</当月見積もり工数>
+ <当月実績工数>2</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>更に、どういう検索エンジンがあるか調査する</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>検索エンジンで車を走らせることができない。(要調査)</P>
+ </問題点対策>
+ </業務報告>
+ </業務報告リスト>
+</週報>
diff --git a/tests/data/utftest_utf8_bom.xml b/tests/data/utftest_utf8_bom.xml
new file mode 100644
index 0000000..d34cdb8
--- /dev/null
+++ b/tests/data/utftest_utf8_bom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!DOCTYPE 週報 SYSTEM "weekly-utf-8.dtd">
+<!-- 週報サンプル -->
+<週報>
+ <English name="name" value="value">The world has many languages</English>
+ <Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
+ <Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
+ <SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
+ <Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
+ <汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
+ <Heavy>&quot;Mëtæl!&quot;</Heavy>
+ <ä>Umlaut Element</ä>
+
+ <年月週>
+ <年度>1997</年度>
+ <月度>1</月度>
+ <週>1</週>
+ </年月週>
+
+ <氏名>
+ <氏>山田</氏>
+ <名>太郎</名>
+ </氏名>
+
+ <業務報告リスト>
+ <業務報告>
+ <業務名>XMLエディターの作成</業務名>
+ <業務コード>X3355-23</業務コード>
+ <工数管理>
+ <見積もり工数>1600</見積もり工数>
+ <実績工数>320</実績工数>
+ <当月見積もり工数>160</当月見積もり工数>
+ <当月実績工数>24</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P>XMLエディターの基本仕様の作成</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>XMLエディターの基本仕様の作成</P>
+ </実施事項>
+ <実施事項>
+ <P>競合他社製品の機能調査</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>特になし</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>XMLとは何かわからない。</P>
+ </問題点対策>
+ </業務報告>
+
+ <業務報告>
+ <業務名>検索エンジンの開発</業務名>
+ <業務コード>S8821-76</業務コード>
+ <工数管理>
+ <見積もり工数>120</見積もり工数>
+ <実績工数>6</実績工数>
+ <当月見積もり工数>32</当月見積もり工数>
+ <当月実績工数>2</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>更に、どういう検索エンジンがあるか調査する</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>検索エンジンで車を走らせることができない。(要調査)</P>
+ </問題点対策>
+ </業務報告>
+ </業務報告リスト>
+</週報>
diff --git a/tests/data/utftest_utf8_clean.xml b/tests/data/utftest_utf8_clean.xml
new file mode 100644
index 0000000..160807a
--- /dev/null
+++ b/tests/data/utftest_utf8_clean.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?><!-- 週報サンプル --><週報>
+ <English name="name" value="value">The world has many languages</English>
+ <Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
+ <Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
+ <SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
+ <Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
+ <汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
+ <Heavy>quot;Mëtæl!quot;</Heavy>
+ <ä>Umlaut Element</ä>
+
+ <年月週>
+ <年度>1997</年度>
+ <月度>1</月度>
+ <週>1</週>
+ </年月週>
+
+ <氏名>
+ <氏>山田</氏>
+ <名>太郎</名>
+ </氏名>
+
+ <業務報告リスト>
+ <業務報告>
+ <業務名>XMLエディターの作成</業務名>
+ <業務コード>X3355-23</業務コード>
+ <工数管理>
+ <見積もり工数>1600</見積もり工数>
+ <実績工数>320</実績工数>
+ <当月見積もり工数>160</当月見積もり工数>
+ <当月実績工数>24</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P>XMLエディターの基本仕様の作成</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>XMLエディターの基本仕様の作成</P>
+ </実施事項>
+ <実施事項>
+ <P>競合他社製品の機能調査</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>特になし</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>XMLとは何かわからない。</P>
+ </問題点対策>
+ </業務報告>
+
+ <業務報告>
+ <業務名>検索エンジンの開発</業務名>
+ <業務コード>S8821-76</業務コード>
+ <工数管理>
+ <見積もり工数>120</見積もり工数>
+ <実績工数>6</実績工数>
+ <当月見積もり工数>32</当月見積もり工数>
+ <当月実績工数>2</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>更に、どういう検索エンジンがあるか調査する</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>検索エンジンで車を走らせることができない。(要調査)</P>
+ </問題点対策>
+ </業務報告>
+ </業務報告リスト>
+</週報> \ No newline at end of file
diff --git a/tests/data/utftest_utf8_nodecl.xml b/tests/data/utftest_utf8_nodecl.xml
new file mode 100644
index 0000000..b908c5d
--- /dev/null
+++ b/tests/data/utftest_utf8_nodecl.xml
@@ -0,0 +1,86 @@
+<!DOCTYPE 週報 SYSTEM "weekly-utf-8.dtd">
+<!-- 週報サンプル -->
+<週報>
+ <English name="name" value="value">The world has many languages</English>
+ <Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
+ <Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
+ <SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
+ <Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
+ <汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
+ <Heavy>&quot;Mëtæl!&quot;</Heavy>
+ <ä>Umlaut Element</ä>
+
+ <年月週>
+ <年度>1997</年度>
+ <月度>1</月度>
+ <週>1</週>
+ </年月週>
+
+ <氏名>
+ <氏>山田</氏>
+ <名>太郎</名>
+ </氏名>
+
+ <業務報告リスト>
+ <業務報告>
+ <業務名>XMLエディターの作成</業務名>
+ <業務コード>X3355-23</業務コード>
+ <工数管理>
+ <見積もり工数>1600</見積もり工数>
+ <実績工数>320</実績工数>
+ <当月見積もり工数>160</当月見積もり工数>
+ <当月実績工数>24</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P>XMLエディターの基本仕様の作成</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>XMLエディターの基本仕様の作成</P>
+ </実施事項>
+ <実施事項>
+ <P>競合他社製品の機能調査</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>特になし</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>XMLとは何かわからない。</P>
+ </問題点対策>
+ </業務報告>
+
+ <業務報告>
+ <業務名>検索エンジンの開発</業務名>
+ <業務コード>S8821-76</業務コード>
+ <工数管理>
+ <見積もり工数>120</見積もり工数>
+ <実績工数>6</実績工数>
+ <当月見積もり工数>32</当月見積もり工数>
+ <当月実績工数>2</当月実績工数>
+ </工数管理>
+ <予定項目リスト>
+ <予定項目>
+ <P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
+ </予定項目>
+ </予定項目リスト>
+ <実施事項リスト>
+ <実施事項>
+ <P>更に、どういう検索エンジンがあるか調査する</P>
+ </実施事項>
+ </実施事項リスト>
+ <上長への要請事項リスト>
+ <上長への要請事項>
+ <P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
+ </上長への要請事項>
+ </上長への要請事項リスト>
+ <問題点対策>
+ <P>検索エンジンで車を走らせることができない。(要調査)</P>
+ </問題点対策>
+ </業務報告>
+ </業務報告リスト>
+</週報>
diff --git a/tests/helpers.hpp b/tests/helpers.hpp
index e7ed873..6648806 100644
--- a/tests/helpers.hpp
+++ b/tests/helpers.hpp
@@ -49,7 +49,12 @@ template <typename T> static void generic_rel_ops_test(T obj1, T obj2)
T null = T();
// obj1 < obj2 (we use operator<, but there is no other choice
- if (obj1 > obj2) std::swap(obj1, obj2);
+ if (obj1 > obj2)
+ {
+ T temp = obj1;
+ obj1 = obj2;
+ obj2 = temp;
+ }
// operator<
CHECK(null < obj1);
diff --git a/tests/main.cpp b/tests/main.cpp
index f283dcf..1aeafd2 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -1,33 +1,26 @@
#include "test.hpp"
+#include "allocator.hpp"
#include <exception>
#include <stdio.h>
-
-#include <stdlib.h>
-#include <malloc.h>
+#include <float.h>
test_runner* test_runner::_tests = 0;
size_t test_runner::_memory_fail_threshold = 0;
-jmp_buf test_runner::_failure;
+jmp_buf test_runner::_failure_buffer;
+const char* test_runner::_failure_message;
static size_t g_memory_total_size = 0;
-#ifdef __linux
-size_t _msize(void* ptr)
-{
- return malloc_usable_size(ptr);
-}
-#endif
-
static void* custom_allocate(size_t size)
{
if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < size)
return 0;
else
{
- void* ptr = malloc(size);
+ void* ptr = memory_allocate(size);
- g_memory_total_size += _msize(ptr);
+ g_memory_total_size += memory_size(ptr);
return ptr;
}
@@ -37,9 +30,9 @@ static void custom_deallocate(void* ptr)
{
if (ptr)
{
- g_memory_total_size -= _msize(ptr);
+ g_memory_total_size -= memory_size(ptr);
- free(ptr);
+ memory_deallocate(ptr);
}
}
@@ -48,7 +41,7 @@ static void replace_memory_management()
// create some document to touch original functions
{
pugi::xml_document doc;
- doc.append_child().set_name("node");
+ doc.append_child().set_name(STR("node"));
}
// replace functions
@@ -77,7 +70,7 @@ static bool run_test(test_runner* test)
# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable
#endif
- volatile int result = setjmp(test_runner::_failure);
+ volatile int result = setjmp(test_runner::_failure_buffer);
#ifdef _MSC_VER
# pragma warning(pop)
@@ -85,13 +78,17 @@ static bool run_test(test_runner* test)
if (result)
{
- printf("Test %s failed: %s\n", test->_name, (const char*)(intptr_t)result);
+ printf("Test %s failed: %s\n", test->_name, test_runner::_failure_message);
return false;
}
test->run();
- if (g_memory_total_size != 0) longjmp(test_runner::_failure, (int)(intptr_t)"Memory leaks found");
+ if (g_memory_total_size != 0)
+ {
+ printf("Test %s failed: memory leaks found (%u bytes)\n", test->_name, (unsigned int)g_memory_total_size);
+ return false;
+ }
return true;
#ifndef PUGIXML_NO_EXCEPTIONS
diff --git a/tests/test.cpp b/tests/test.cpp
new file mode 100644
index 0000000..ebd4bf4
--- /dev/null
+++ b/tests/test.cpp
@@ -0,0 +1,134 @@
+#include "test.hpp"
+
+#include "writer_string.hpp"
+
+#include <math.h>
+#include <float.h>
+
+bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs)
+{
+ return (!lhs || !rhs) ? lhs == rhs : pugi::impl::strequal(lhs, rhs);
+}
+
+bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags)
+{
+ xml_writer_string writer;
+
+ node.print(writer, indent, flags, get_native_encoding());
+
+ return writer.as_string() == contents;
+}
+
+#ifndef PUGIXML_NO_XPATH
+bool test_xpath_string(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected)
+{
+ pugi::xpath_query q(query);
+
+ return q.evaluate_string(node) == expected;
+}
+
+bool test_xpath_boolean(const pugi::xml_node& node, const pugi::char_t* query, bool expected)
+{
+ pugi::xpath_query q(query);
+
+ return q.evaluate_boolean(node) == expected;
+}
+
+#include <stdio.h>
+
+bool test_xpath_number(const pugi::xml_node& node, const pugi::char_t* query, double expected)
+{
+ pugi::xpath_query q(query);
+
+ double value = q.evaluate_number(node);
+ double absolute_error = fabs(value - expected);
+
+ const double tolerance = 1e-15f;
+ return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance;
+}
+
+bool test_xpath_number_nan(const pugi::xml_node& node, const pugi::char_t* query)
+{
+ pugi::xpath_query q(query);
+
+ double r = q.evaluate_number(node);
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+ return _isnan(r) != 0;
+#else
+ return r != r;
+#endif
+}
+
+bool test_xpath_fail_compile(const pugi::char_t* query)
+{
+ try
+ {
+ pugi::xpath_query q(query);
+ return false;
+ }
+ catch (const pugi::xpath_exception&)
+ {
+ return true;
+ }
+}
+
+void xpath_node_set_tester::check(bool condition)
+{
+ if (!condition)
+ {
+ test_runner::_failure_message = message;
+ longjmp(test_runner::_failure_buffer, 1);
+ }
+}
+
+xpath_node_set_tester::xpath_node_set_tester(const pugi::xml_node& node, const pugi::char_t* query, const char* message): last(0), message(message)
+{
+ pugi::xpath_query q(query);
+ result = q.evaluate_node_set(node);
+}
+
+xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message): last(0), message(message)
+{
+ result = set;
+}
+
+xpath_node_set_tester::~xpath_node_set_tester()
+{
+ // check that we processed everything
+ check(last == result.size());
+}
+
+xpath_node_set_tester& xpath_node_set_tester::operator%(unsigned int expected)
+{
+ // check element count
+ check(last < result.size());
+
+ // check document order
+ pugi::xpath_node node = result.begin()[last];
+ unsigned int order = node.attribute() ? node.attribute().document_order() : node.node().document_order();
+
+ check(order == expected);
+
+ // continue to the next element
+ last++;
+
+ return *this;
+}
+
+#endif
+
+bool is_little_endian()
+{
+ unsigned int ui = 1;
+ return *reinterpret_cast<char*>(&ui) == 1;
+}
+
+pugi::encoding_t get_native_encoding()
+{
+#ifdef PUGIXML_WCHAR_MODE
+ return pugi::encoding_wchar;
+#else
+ return pugi::encoding_utf8;
+#endif
+}
diff --git a/tests/test.hpp b/tests/test.hpp
index 0d54e6d..be42b8b 100644
--- a/tests/test.hpp
+++ b/tests/test.hpp
@@ -3,21 +3,8 @@
#include "../src/pugixml.hpp"
-#if (defined(_MSC_VER) && _MSC_VER==1200) || defined(__DMC__)
-typedef int intptr_t;
-#endif
-
-#include <string.h>
-#include <math.h>
-#include <float.h>
#include <setjmp.h>
-#if defined(__MWERKS__) || defined(__BORLANDC__)
-#include <stdint.h> // intptr_t
-#endif
-
-#include <string>
-
struct test_runner
{
test_runner(const char* name)
@@ -36,84 +23,25 @@ struct test_runner
static test_runner* _tests;
static size_t _memory_fail_threshold;
- static jmp_buf _failure;
+ static jmp_buf _failure_buffer;
+ static const char* _failure_message;
};
-inline bool test_string_equal(const char* lhs, const char* rhs)
-{
- return (!lhs || !rhs) ? lhs == rhs : strcmp(lhs, rhs) == 0;
-}
+bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs);
-template <typename Node> inline bool test_node_name_value(const Node& node, const char* name, const char* value)
+template <typename Node> inline bool test_node_name_value(const Node& node, const pugi::char_t* name, const pugi::char_t* value)
{
return test_string_equal(node.name(), name) && test_string_equal(node.value(), value);
}
-struct xml_writer_string: public pugi::xml_writer
-{
- std::string result;
-
- virtual void write(const void* data, size_t size)
- {
- result += std::string(static_cast<const char*>(data), size);
- }
-};
-
-inline bool test_node(const pugi::xml_node& node, const char* contents, const char* indent, unsigned int flags)
-{
- xml_writer_string writer;
- node.print(writer, indent, flags);
-
- return writer.result == contents;
-}
+bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags);
#ifndef PUGIXML_NO_XPATH
-inline bool test_xpath_string(const pugi::xml_node& node, const char* query, const char* expected)
-{
- pugi::xpath_query q(query);
-
- return q.evaluate_string(node) == expected;
-}
-
-inline bool test_xpath_boolean(const pugi::xml_node& node, const char* query, bool expected)
-{
- pugi::xpath_query q(query);
-
- return q.evaluate_boolean(node) == expected;
-}
-
-inline bool test_xpath_number(const pugi::xml_node& node, const char* query, double expected)
-{
- pugi::xpath_query q(query);
-
- return fabs(q.evaluate_number(node) - expected) < 1e-16f;
-}
-
-inline bool test_xpath_number_nan(const pugi::xml_node& node, const char* query)
-{
- pugi::xpath_query q(query);
-
- double r = q.evaluate_number(node);
-
-#if defined(_MSC_VER) || defined(__BORLANDC__)
- return _isnan(r) != 0;
-#else
- return r != r;
-#endif
-}
-
-inline bool test_xpath_fail_compile(const char* query)
-{
- try
- {
- pugi::xpath_query q(query);
- return false;
- }
- catch (const pugi::xpath_exception&)
- {
- return true;
- }
-}
+bool test_xpath_string(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected);
+bool test_xpath_boolean(const pugi::xml_node& node, const pugi::char_t* query, bool expected);
+bool test_xpath_number(const pugi::xml_node& node, const pugi::char_t* query, double expected);
+bool test_xpath_number_nan(const pugi::xml_node& node, const pugi::char_t* query);
+bool test_xpath_fail_compile(const pugi::char_t* query);
struct xpath_node_set_tester
{
@@ -121,44 +49,13 @@ struct xpath_node_set_tester
unsigned int last;
const char* message;
- void check(bool condition)
- {
- if (!condition) longjmp(test_runner::_failure, (int)(intptr_t)message);
- }
-
- xpath_node_set_tester(const pugi::xml_node& node, const char* query, const char* message): last(0), message(message)
- {
- pugi::xpath_query q(query);
- result = q.evaluate_node_set(node);
- }
+ void check(bool condition);
- xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message): last(0), message(message)
- {
- result = set;
- }
+ xpath_node_set_tester(const pugi::xml_node& node, const pugi::char_t* query, const char* message);
+ xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message);
+ ~xpath_node_set_tester();
- ~xpath_node_set_tester()
- {
- // check that we processed everything
- check(last == result.size());
- }
-
- xpath_node_set_tester& operator%(unsigned int expected)
- {
- // check element count
- check(last < result.size());
-
- // check document order
- pugi::xpath_node node = result.begin()[last];
- unsigned int order = node.attribute() ? node.attribute().document_order() : node.node().document_order();
-
- check(order == expected);
-
- // continue to the next element
- last++;
-
- return *this;
- }
+ xpath_node_set_tester& operator%(unsigned int expected);
};
#endif
@@ -191,7 +88,7 @@ struct dummy_fixture {};
\
test_fixture_##name() \
{ \
- CHECK(doc.load(xml, flags)); \
+ CHECK(doc.load(PUGIXML_TEXT(xml), flags)); \
} \
\
private: \
@@ -205,28 +102,42 @@ struct dummy_fixture {};
#define CHECK_JOIN(text, file, line) text file #line
#define CHECK_JOIN2(text, file, line) CHECK_JOIN(text, file, line)
-#define CHECK_TEXT(condition, text) if (condition) ; else longjmp(test_runner::_failure, (int)(intptr_t)(CHECK_JOIN2(text, " at "__FILE__ ":", __LINE__)))
+#define CHECK_TEXT(condition, text) if (condition) ; else test_runner::_failure_message = CHECK_JOIN2(text, " at "__FILE__ ":", __LINE__), longjmp(test_runner::_failure_buffer, 1)
#if (defined(_MSC_VER) && _MSC_VER == 1200) || defined(__MWERKS__)
-# define STR(value) "??" // MSVC 6.0 and CodeWarrior have troubles stringizing stuff with strings w/escaping inside
+# define STRINGIZE(value) "??" // MSVC 6.0 and CodeWarrior have troubles stringizing stuff with strings w/escaping inside
#else
-# define STR(value) #value
+# define STRINGIZE(value) #value
#endif
-#define CHECK(condition) CHECK_TEXT(condition, STR(condition) " is false")
-#define CHECK_STRING(value, expected) CHECK_TEXT(test_string_equal(value, expected), STR(value) " is not equal to " STR(expected))
-#define CHECK_DOUBLE(value, expected) CHECK_TEXT(fabs(value - expected) < 1e-6, STR(value) " is not equal to " STR(expected))
-#define CHECK_NAME_VALUE(node, name, value) CHECK_TEXT(test_node_name_value(node, name, value), STR(node) " name/value do not match " STR(name) " and " STR(value))
-#define CHECK_NODE_EX(node, expected, indent, flags) CHECK_TEXT(test_node(node, expected, indent, flags), STR(node) " contents does not match " STR(expected))
-#define CHECK_NODE(node, expected) CHECK_NODE_EX(node, expected, "", pugi::format_raw)
+#define CHECK(condition) CHECK_TEXT(condition, STRINGIZE(condition) " is false")
+#define CHECK_STRING(value, expected) CHECK_TEXT(test_string_equal(value, expected), STRINGIZE(value) " is not equal to " STRINGIZE(expected))
+#define CHECK_DOUBLE(value, expected) CHECK_TEXT((value > expected ? value - expected : expected - value) < 1e-6, STRINGIZE(value) " is not equal to " STRINGIZE(expected))
+#define CHECK_NAME_VALUE(node, name, value) CHECK_TEXT(test_node_name_value(node, name, value), STRINGIZE(node) " name/value do not match " STRINGIZE(name) " and " STRINGIZE(value))
+#define CHECK_NODE_EX(node, expected, indent, flags) CHECK_TEXT(test_node(node, expected, indent, flags), STRINGIZE(node) " contents does not match " STRINGIZE(expected))
+#define CHECK_NODE(node, expected) CHECK_NODE_EX(node, expected, PUGIXML_TEXT(""), pugi::format_raw)
#ifndef PUGIXML_NO_XPATH
-#define CHECK_XPATH_STRING(node, query, expected) CHECK_TEXT(test_xpath_string(node, query, expected), STR(query) " does not evaluate to " STR(expected) " in context " STR(node))
-#define CHECK_XPATH_BOOLEAN(node, query, expected) CHECK_TEXT(test_xpath_boolean(node, query, expected), STR(query) " does not evaluate to " STR(expected) " in context " STR(node))
-#define CHECK_XPATH_NUMBER(node, query, expected) CHECK_TEXT(test_xpath_number(node, query, expected), STR(query) " does not evaluate to " STR(expected) " in context " STR(node))
-#define CHECK_XPATH_NUMBER_NAN(node, query) CHECK_TEXT(test_xpath_number_nan(node, query), STR(query) " does not evaluate to NaN in context " STR(node))
-#define CHECK_XPATH_FAIL(query) CHECK_TEXT(test_xpath_fail_compile(query), STR(query) " should not compile")
-#define CHECK_XPATH_NODESET(node, query) xpath_node_set_tester(node, query, CHECK_JOIN2(STR(query) " does not evaluate to expected set in context " STR(node), " at "__FILE__ ":", __LINE__))
+#define CHECK_XPATH_STRING(node, query, expected) CHECK_TEXT(test_xpath_string(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
+#define CHECK_XPATH_BOOLEAN(node, query, expected) CHECK_TEXT(test_xpath_boolean(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
+#define CHECK_XPATH_NUMBER(node, query, expected) CHECK_TEXT(test_xpath_number(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
+#define CHECK_XPATH_NUMBER_NAN(node, query) CHECK_TEXT(test_xpath_number_nan(node, query), STRINGIZE(query) " does not evaluate to NaN in context " STRINGIZE(node))
+#define CHECK_XPATH_FAIL(query) CHECK_TEXT(test_xpath_fail_compile(query), STRINGIZE(query) " should not compile")
+#define CHECK_XPATH_NODESET(node, query) xpath_node_set_tester(node, query, CHECK_JOIN2(STRINGIZE(query) " does not evaluate to expected set in context " STRINGIZE(node), " at "__FILE__ ":", __LINE__))
#endif
+#define STR(text) PUGIXML_TEXT(text)
+
+#ifdef __DMC__
+#define U_LITERALS // DMC does not understand \x01234 (it parses first three digits), but understands \u01234
+#endif
+
+inline wchar_t wchar_cast(unsigned int value)
+{
+ return static_cast<wchar_t>(value); // to avoid C4310 on MSVC
+}
+
+bool is_little_endian();
+pugi::encoding_t get_native_encoding();
+
#endif
diff --git a/tests/test_document.cpp b/tests/test_document.cpp
index 2ea0f84..46f0ff4 100644
--- a/tests/test_document.cpp
+++ b/tests/test_document.cpp
@@ -1,10 +1,16 @@
+#include <string.h> // because Borland's STL is braindead, we have to include <string.h> _before_ <string> in order to get memcpy
+
#include "common.hpp"
+#include "writer_string.hpp"
+
+#include <stdio.h>
+#include <stdlib.h>
+
#include <fstream>
#include <sstream>
-#include <string>
-#include <stdio.h>
+#include <string>
#ifdef _MSC_VER
#pragma warning(disable: 4996)
@@ -13,8 +19,8 @@
TEST(document_create)
{
pugi::xml_document doc;
- doc.append_child().set_name("node");
- CHECK_NODE(doc, "<node />");
+ doc.append_child().set_name(STR("node"));
+ CHECK_NODE(doc, STR("<node />"));
}
#ifndef PUGIXML_NO_STL
@@ -24,7 +30,29 @@ TEST(document_load_stream)
std::istringstream iss("<node/>");
CHECK(doc.load(iss));
- CHECK_NODE(doc, "<node />");
+ CHECK_NODE(doc, STR("<node />"));
+}
+
+TEST(document_load_stream_offset)
+{
+ pugi::xml_document doc;
+
+ std::istringstream iss("<foobar> <node/>");
+
+ std::string s;
+ iss >> s;
+
+ CHECK(doc.load(iss));
+ CHECK_NODE(doc, STR("<node />"));
+}
+
+TEST(document_load_stream_text)
+{
+ pugi::xml_document doc;
+
+ std::ifstream iss("tests/data/multiline.xml");
+ CHECK(doc.load(iss));
+ CHECK_NODE(doc, STR("<node1 /><node2 /><node3 />"));
}
TEST(document_load_stream_error)
@@ -39,21 +67,27 @@ TEST(document_load_stream_error)
CHECK(doc.load(fs2).status == status_io_error);
#endif
- std::ifstream fs3("nul");
- CHECK(doc.load(fs3).status == status_io_error);
-
test_runner::_memory_fail_threshold = 1;
std::istringstream iss("<node/>");
CHECK(doc.load(iss).status == status_out_of_memory);
}
+
+TEST(document_load_stream_wide)
+{
+ pugi::xml_document doc;
+
+ std::basic_istringstream<wchar_t> iss(L"<node/>");
+ CHECK(doc.load(iss));
+ CHECK_NODE(doc, STR("<node />"));
+}
#endif
TEST(document_load_string)
{
pugi::xml_document doc;
- CHECK(doc.load("<node/>"));
- CHECK_NODE(doc, "<node />");
+ CHECK(doc.load(STR("<node/>")));
+ CHECK_NODE(doc, STR("<node />"));
}
TEST(document_load_file)
@@ -61,7 +95,15 @@ TEST(document_load_file)
pugi::xml_document doc;
CHECK(doc.load_file("tests/data/small.xml"));
- CHECK_NODE(doc, "<node />");
+ CHECK_NODE(doc, STR("<node />"));
+}
+
+TEST(document_load_file_empty)
+{
+ pugi::xml_document doc;
+
+ CHECK(doc.load_file("tests/data/empty.xml"));
+ CHECK(!doc.first_child());
}
TEST(document_load_file_large)
@@ -70,10 +112,10 @@ TEST(document_load_file_large)
CHECK(doc.load_file("tests/data/large.xml"));
- std::string str;
- str += "<node>";
- for (int i = 0; i < 10000; ++i) str += "<node />";
- str += "</node>";
+ std::basic_string<pugi::char_t> str;
+ str += STR("<node>");
+ for (int i = 0; i < 10000; ++i) str += STR("<node />");
+ str += STR("</node>");
CHECK_NODE(doc, str.c_str());
}
@@ -84,14 +126,10 @@ TEST(document_load_file_error)
CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found);
-#ifdef __linux
- CHECK(doc.load_file("/dev/null").status == status_io_error);
-#else
+#ifdef _WIN32
#ifndef __DMC__ // Digital Mars CRT does not like 'con' pseudo-file
CHECK(doc.load_file("con").status == status_io_error);
#endif
-
- CHECK(doc.load_file("nul").status == status_io_error);
#endif
test_runner::_memory_fail_threshold = 1;
@@ -102,27 +140,57 @@ TEST_XML(document_save, "<node/>")
{
xml_writer_string writer;
- doc.save(writer, "", pugi::format_no_declaration | pugi::format_raw);
+ doc.save(writer, STR(""), pugi::format_no_declaration | pugi::format_raw, get_native_encoding());
- CHECK(writer.result == "<node />");
+ CHECK(writer.as_string() == STR("<node />"));
}
-TEST_XML(document_save_bom, "<node/>")
+#ifndef PUGIXML_NO_STL
+TEST_XML(document_save_stream, "<node/>")
{
- xml_writer_string writer;
+ std::ostringstream oss;
- doc.save(writer, "", pugi::format_no_declaration | pugi::format_raw | pugi::format_write_bom_utf8);
+ doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw);
- CHECK(writer.result == "\xef\xbb\xbf<node />");
+ CHECK(oss.str() == "<node />");
+}
+
+TEST_XML(document_save_stream_wide, "<node/>")
+{
+ std::basic_ostringstream<wchar_t> oss;
+
+ doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw);
+
+ CHECK(oss.str() == L"<node />");
+}
+#endif
+
+TEST_XML(document_save_bom, "<n/>")
+{
+ unsigned int flags = format_no_declaration | format_raw | format_write_bom;
+
+ // specific encodings
+ CHECK(test_save_narrow(doc, flags, encoding_utf8, "\xef\xbb\xbf<n />", 8));
+ CHECK(test_save_narrow(doc, flags, encoding_utf16_be, "\xfe\xff\x00<\x00n\x00 \x00/\x00>", 12));
+ CHECK(test_save_narrow(doc, flags, encoding_utf16_le, "\xff\xfe<\x00n\x00 \x00/\x00>\x00", 12));
+ CHECK(test_save_narrow(doc, flags, encoding_utf32_be, "\x00\x00\xfe\xff\x00\x00\x00<\x00\x00\x00n\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>", 24));
+ CHECK(test_save_narrow(doc, flags, encoding_utf32_le, "\xff\xfe\x00\x00<\x00\x00\x00n\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>\x00\x00\x00", 24));
+
+ // encodings synonyms
+ CHECK(save_narrow(doc, flags, encoding_utf16) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf16_le : encoding_utf16_be)));
+ CHECK(save_narrow(doc, flags, encoding_utf32) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf32_le : encoding_utf32_be)));
+
+ size_t wcharsize = sizeof(wchar_t);
+ CHECK(save_narrow(doc, flags, encoding_wchar) == save_narrow(doc, flags, (wcharsize == 2 ? encoding_utf16 : encoding_utf32)));
}
TEST_XML(document_save_declaration, "<node/>")
{
xml_writer_string writer;
- doc.save(writer);
+ doc.save(writer, STR(""), pugi::format_default, get_native_encoding());
- CHECK(writer.result == "<?xml version=\"1.0\"?>\n<node />\n");
+ CHECK(writer.as_string() == STR("<?xml version=\"1.0\"?>\n<node />\n"));
}
TEST_XML(document_save_file, "<node/>")
@@ -130,34 +198,46 @@ TEST_XML(document_save_file, "<node/>")
CHECK(doc.save_file("tests/data/output.xml"));
CHECK(doc.load_file("tests/data/output.xml", pugi::parse_default | pugi::parse_declaration));
- CHECK_NODE(doc, "<?xml version=\"1.0\"?><node />");
+ CHECK_NODE(doc, STR("<?xml version=\"1.0\"?><node />"));
unlink("tests/data/output.xml");
}
-TEST(document_parse)
+TEST(document_load_buffer)
{
- char text[] = "<node/>";
+ const pugi::char_t text[] = STR("<?xml?><node/>");
pugi::xml_document doc;
- CHECK(doc.parse(text));
- CHECK_NODE(doc, "<node />");
+ CHECK(doc.load_buffer(text, sizeof(text)));
+ CHECK_NODE(doc, STR("<node />"));
}
-TEST(document_parse_transfer_ownership)
+TEST(document_load_buffer_inplace)
+{
+ pugi::char_t text[] = STR("<?xml?><node/>");
+
+ pugi::xml_document doc;
+
+ CHECK(doc.load_buffer_inplace(text, sizeof(text)));
+ CHECK_NODE(doc, STR("<node />"));
+}
+
+TEST(document_load_buffer_inplace_own)
{
allocation_function alloc = get_memory_allocation_function();
- char* text = static_cast<char*>(alloc(strlen("<node/>") + 1));
+ size_t size = strlen("<?xml?><node/>") * sizeof(pugi::char_t);
+
+ pugi::char_t* text = static_cast<pugi::char_t*>(alloc(size));
CHECK(text);
- strcpy(text, "<node/>");
+ memcpy(text, STR("<?xml?><node/>"), size);
pugi::xml_document doc;
- CHECK(doc.parse(transfer_ownership_tag(), text));
- CHECK_NODE(doc, "<node />");
+ CHECK(doc.load_buffer_inplace_own(text, size));
+ CHECK_NODE(doc, STR("<node />"));
}
TEST(document_parse_result_bool)
@@ -189,3 +269,306 @@ TEST(document_parse_result_description)
CHECK(result.description()[0] != 0);
}
}
+
+TEST(document_load_fail)
+{
+ xml_document doc;
+ CHECK(!doc.load(STR("<foo><bar/>")));
+ CHECK(doc.child(STR("foo")).child(STR("bar")));
+}
+
+inline void check_utftest_document(const xml_document& doc)
+{
+ // ascii text
+ CHECK_STRING(doc.last_child().first_child().name(), STR("English"));
+
+ // check that we have parsed some non-ascii text
+ CHECK((unsigned)doc.last_child().last_child().name()[0] >= 0x80);
+
+ // check magic string
+ const pugi::char_t* v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value();
+
+#ifdef PUGIXML_WCHAR_MODE
+ CHECK(v[0] == 0x4e16 && v[1] == 0x754c && v[2] == 0x6709 && v[3] == 0x5f88 && v[4] == 0x591a && v[5] == 0x8bed && v[6] == 0x8a00);
+
+ // last character is a surrogate pair
+ unsigned int v7 = v[7];
+ size_t wcharsize = sizeof(wchar_t);
+
+ CHECK(wcharsize == 2 ? (v[7] == 0xd852 && v[8] == 0xdf62) : (v7 == 0x24b62));
+#else
+ // unicode string
+ CHECK_STRING(v, "\xe4\xb8\x96\xe7\x95\x8c\xe6\x9c\x89\xe5\xbe\x88\xe5\xa4\x9a\xe8\xaf\xad\xe8\xa8\x80\xf0\xa4\xad\xa2");
+#endif
+}
+
+TEST(document_load_file_convert_auto)
+{
+ const char* files[] =
+ {
+ "tests/data/utftest_utf16_be.xml",
+ "tests/data/utftest_utf16_be_bom.xml",
+ "tests/data/utftest_utf16_be_nodecl.xml",
+ "tests/data/utftest_utf16_le.xml",
+ "tests/data/utftest_utf16_le_bom.xml",
+ "tests/data/utftest_utf16_le_nodecl.xml",
+ "tests/data/utftest_utf32_be.xml",
+ "tests/data/utftest_utf32_be_bom.xml",
+ "tests/data/utftest_utf32_be_nodecl.xml",
+ "tests/data/utftest_utf32_le.xml",
+ "tests/data/utftest_utf32_le_bom.xml",
+ "tests/data/utftest_utf32_le_nodecl.xml",
+ "tests/data/utftest_utf8.xml",
+ "tests/data/utftest_utf8_bom.xml",
+ "tests/data/utftest_utf8_nodecl.xml"
+ };
+
+ encoding_t encodings[] =
+ {
+ encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
+ encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
+ encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
+ encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
+ encoding_utf8, encoding_utf8, encoding_utf8
+ };
+
+ for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
+ {
+ xml_document doc;
+ xml_parse_result res = doc.load_file(files[i]);
+
+ CHECK(res);
+ CHECK(res.encoding == encodings[i]);
+ check_utftest_document(doc);
+ }
+}
+
+TEST(document_load_file_convert_specific)
+{
+ const char* files[] =
+ {
+ "tests/data/utftest_utf16_be.xml",
+ "tests/data/utftest_utf16_be_bom.xml",
+ "tests/data/utftest_utf16_be_nodecl.xml",
+ "tests/data/utftest_utf16_le.xml",
+ "tests/data/utftest_utf16_le_bom.xml",
+ "tests/data/utftest_utf16_le_nodecl.xml",
+ "tests/data/utftest_utf32_be.xml",
+ "tests/data/utftest_utf32_be_bom.xml",
+ "tests/data/utftest_utf32_be_nodecl.xml",
+ "tests/data/utftest_utf32_le.xml",
+ "tests/data/utftest_utf32_le_bom.xml",
+ "tests/data/utftest_utf32_le_nodecl.xml",
+ "tests/data/utftest_utf8.xml",
+ "tests/data/utftest_utf8_bom.xml",
+ "tests/data/utftest_utf8_nodecl.xml"
+ };
+
+ encoding_t encodings[] =
+ {
+ encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
+ encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
+ encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
+ encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
+ encoding_utf8, encoding_utf8, encoding_utf8
+ };
+
+ for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
+ {
+ for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j)
+ {
+ encoding_t encoding = encodings[j];
+
+ xml_document doc;
+ xml_parse_result res = doc.load_file(files[i], parse_default, encoding);
+
+ if (encoding == encodings[i])
+ {
+ CHECK(res);
+ CHECK(res.encoding == encoding);
+ check_utftest_document(doc);
+ }
+ else
+ {
+ // should not get past first tag
+ CHECK(!doc.first_child());
+ }
+ }
+ }
+}
+
+TEST(document_load_file_convert_native_endianness)
+{
+ const char* files[2][6] =
+ {
+ {
+ "tests/data/utftest_utf16_be.xml",
+ "tests/data/utftest_utf16_be_bom.xml",
+ "tests/data/utftest_utf16_be_nodecl.xml",
+ "tests/data/utftest_utf32_be.xml",
+ "tests/data/utftest_utf32_be_bom.xml",
+ "tests/data/utftest_utf32_be_nodecl.xml",
+ },
+ {
+ "tests/data/utftest_utf16_le.xml",
+ "tests/data/utftest_utf16_le_bom.xml",
+ "tests/data/utftest_utf16_le_nodecl.xml",
+ "tests/data/utftest_utf32_le.xml",
+ "tests/data/utftest_utf32_le_bom.xml",
+ "tests/data/utftest_utf32_le_nodecl.xml",
+ }
+ };
+
+ encoding_t encodings[] =
+ {
+ encoding_utf16, encoding_utf16, encoding_utf16,
+ encoding_utf32, encoding_utf32, encoding_utf32
+ };
+
+ for (unsigned int i = 0; i < sizeof(files[0]) / sizeof(files[0][0]); ++i)
+ {
+ const char* right_file = files[is_little_endian()][i];
+ const char* wrong_file = files[!is_little_endian()][i];
+
+ for (unsigned int j = 0; j < sizeof(encodings) / sizeof(encodings[0]); ++j)
+ {
+ encoding_t encoding = encodings[j];
+
+ // check file with right endianness
+ {
+ xml_document doc;
+ xml_parse_result res = doc.load_file(right_file, parse_default, encoding);
+
+ if (encoding == encodings[i])
+ {
+ CHECK(res);
+ check_utftest_document(doc);
+ }
+ else
+ {
+ // should not get past first tag
+ CHECK(!doc.first_child());
+ }
+ }
+
+ // check file with wrong endianness
+ {
+ xml_document doc;
+ doc.load_file(wrong_file, parse_default, encoding);
+ CHECK(!doc.first_child());
+ }
+ }
+ }
+}
+
+static bool load_file_in_memory(const char* path, char*& data, size_t& size)
+{
+ FILE* file = fopen(path, "rb");
+ if (!file) return false;
+
+ fseek(file, 0, SEEK_END);
+ size = (size_t)ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ data = new char[size];
+
+ CHECK(fread(data, 1, size, file) == size);
+ fclose(file);
+
+ return true;
+}
+
+TEST(document_contents_preserve)
+{
+ struct file_t
+ {
+ const char* path;
+ encoding_t encoding;
+
+ char* data;
+ size_t size;
+ };
+
+ file_t files[] =
+ {
+ {"tests/data/utftest_utf16_be_clean.xml", encoding_utf16_be, 0, 0},
+ {"tests/data/utftest_utf16_le_clean.xml", encoding_utf16_le, 0, 0},
+ {"tests/data/utftest_utf32_be_clean.xml", encoding_utf32_be, 0, 0},
+ {"tests/data/utftest_utf32_le_clean.xml", encoding_utf32_le, 0, 0},
+ {"tests/data/utftest_utf8_clean.xml", encoding_utf8, 0, 0}
+ };
+
+ // load files in memory
+ for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
+ {
+ CHECK(load_file_in_memory(files[i].path, files[i].data, files[i].size));
+ }
+
+ // convert each file to each format and compare bitwise
+ for (unsigned int src = 0; src < sizeof(files) / sizeof(files[0]); ++src)
+ {
+ for (unsigned int dst = 0; dst < sizeof(files) / sizeof(files[0]); ++dst)
+ {
+ // parse into document (preserve comments, declaration and whitespace pcdata)
+ xml_document doc;
+ CHECK(doc.load_buffer(files[src].data, files[src].size, parse_default | parse_ws_pcdata | parse_declaration | parse_comments));
+
+ // compare saved document with the original (raw formatting, without extra declaration, write bom if it was in original file)
+ CHECK(test_save_narrow(doc, format_raw | format_no_declaration | format_write_bom, files[dst].encoding, files[dst].data, files[dst].size));
+ }
+ }
+
+ // cleanup
+ for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j)
+ {
+ delete[] files[j].data;
+ }
+}
+
+static bool test_parse_fail(const void* buffer, size_t size, encoding_t encoding = encoding_utf8)
+{
+ // copy buffer to heap (to enable out-of-bounds checks)
+ void* temp = malloc(size);
+ memcpy(temp, buffer, size);
+
+ // check that this parses without buffer overflows (yielding an error)
+ xml_document doc;
+ bool result = doc.load_buffer_inplace(temp, size, parse_default, encoding);
+
+ free(temp);
+
+ return !result;
+}
+
+TEST(document_convert_invalid_utf8)
+{
+ // invalid 1-byte input
+ CHECK(test_parse_fail("<\xb0", 2));
+
+ // invalid 2-byte input
+ CHECK(test_parse_fail("<\xc0", 2));
+ CHECK(test_parse_fail("<\xd0", 2));
+
+ // invalid 3-byte input
+ CHECK(test_parse_fail("<\xe2\x80", 3));
+ CHECK(test_parse_fail("<\xe2", 2));
+
+ // invalid 4-byte input
+ CHECK(test_parse_fail("<\xf2\x97\x98", 4));
+ CHECK(test_parse_fail("<\xf2\x97", 3));
+ CHECK(test_parse_fail("<\xf2", 2));
+
+ // invalid 5-byte input
+ CHECK(test_parse_fail("<\xf8", 2));
+}
+
+TEST(document_convert_invalid_utf16)
+{
+ // check non-terminated degenerate handling
+ CHECK(test_parse_fail("\x00<\xda\x1d", 4, encoding_utf16_be));
+ CHECK(test_parse_fail("<\x00\x1d\xda", 4, encoding_utf16_le));
+
+ // check incorrect leading code
+ CHECK(test_parse_fail("\x00<\xde\x24", 4, encoding_utf16_be));
+ CHECK(test_parse_fail("<\x00\x24\xde", 4, encoding_utf16_le));
+}
diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp
index b170607..c80e0e9 100644
--- a/tests/test_dom_modify.cpp
+++ b/tests/test_dom_modify.cpp
@@ -1,158 +1,170 @@
#include "common.hpp"
+#include <float.h>
+
TEST_XML(dom_attr_assign, "<node attr1='' attr2='' attr3='' attr4='' attr5=''/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- node.attribute("attr1") = "v1";
- xml_attribute() = "v1";
+ node.attribute(STR("attr1")) = STR("v1");
+ xml_attribute() = STR("v1");
- node.attribute("attr2") = -2147483647 - 1;
+ node.attribute(STR("attr2")) = -2147483647 - 1;
xml_attribute() = -2147483647 - 1;
- node.attribute("attr3") = 2147483647u;
+ node.attribute(STR("attr3")) = 2147483647u;
xml_attribute() = 2147483647;
- node.attribute("attr4") = 0.5;
+ node.attribute(STR("attr4")) = 0.5;
xml_attribute() = 0.5;
- node.attribute("attr5") = true;
+ node.attribute(STR("attr5")) = true;
xml_attribute() = true;
- CHECK_NODE(node, "<node attr1=\"v1\" attr2=\"-2147483648\" attr3=\"2147483647\" attr4=\"0.5\" attr5=\"true\" />");
+ CHECK_NODE(node, STR("<node attr1=\"v1\" attr2=\"-2147483648\" attr3=\"2147483647\" attr4=\"0.5\" attr5=\"true\" />"));
}
TEST_XML(dom_attr_set_value, "<node attr1='' attr2='' attr3='' attr4='' attr5=''/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.attribute("attr1").set_value("v1"));
- CHECK(!xml_attribute().set_value("v1"));
+ CHECK(node.attribute(STR("attr1")).set_value(STR("v1")));
+ CHECK(!xml_attribute().set_value(STR("v1")));
- CHECK(node.attribute("attr2").set_value(-2147483647 - 1));
+ CHECK(node.attribute(STR("attr2")).set_value(-2147483647 - 1));
CHECK(!xml_attribute().set_value(-2147483647 - 1));
- CHECK(node.attribute("attr3").set_value(2147483647u));
+ CHECK(node.attribute(STR("attr3")).set_value(2147483647u));
CHECK(!xml_attribute().set_value(2147483647));
- CHECK(node.attribute("attr4").set_value(0.5));
+ CHECK(node.attribute(STR("attr4")).set_value(0.5));
CHECK(!xml_attribute().set_value(0.5));
- CHECK(node.attribute("attr5").set_value(true));
+ CHECK(node.attribute(STR("attr5")).set_value(true));
CHECK(!xml_attribute().set_value(true));
- CHECK_NODE(node, "<node attr1=\"v1\" attr2=\"-2147483648\" attr3=\"2147483647\" attr4=\"0.5\" attr5=\"true\" />");
+ CHECK_NODE(node, STR("<node attr1=\"v1\" attr2=\"-2147483648\" attr3=\"2147483647\" attr4=\"0.5\" attr5=\"true\" />"));
}
TEST_XML(dom_node_set_name, "<node>text</node>")
{
- CHECK(doc.child("node").set_name("n"));
- CHECK(!doc.child("node").first_child().set_name("n"));
- CHECK(!xml_node().set_name("n"));
+ CHECK(doc.child(STR("node")).set_name(STR("n")));
+ CHECK(!doc.child(STR("node")).first_child().set_name(STR("n")));
+ CHECK(!xml_node().set_name(STR("n")));
- CHECK_NODE(doc, "<n>text</n>");
+ CHECK_NODE(doc, STR("<n>text</n>"));
}
TEST_XML(dom_node_set_value, "<node>text</node>")
{
- CHECK(doc.child("node").first_child().set_value("no text"));
- CHECK(!doc.child("node").set_value("no text"));
- CHECK(!xml_node().set_value("no text"));
+ CHECK(doc.child(STR("node")).first_child().set_value(STR("no text")));
+ CHECK(!doc.child(STR("node")).set_value(STR("no text")));
+ CHECK(!xml_node().set_value(STR("no text")));
+
+ CHECK_NODE(doc, STR("<node>no text</node>"));
+}
+
+TEST_XML(dom_node_set_value_allocated, "<node>text</node>")
+{
+ CHECK(doc.child(STR("node")).first_child().set_value(STR("no text")));
+ CHECK(!doc.child(STR("node")).set_value(STR("no text")));
+ CHECK(!xml_node().set_value(STR("no text")));
+ CHECK(doc.child(STR("node")).first_child().set_value(STR("no text at all")));
- CHECK_NODE(doc, "<node>no text</node>");
+ CHECK_NODE(doc, STR("<node>no text at all</node>"));
}
TEST_XML(dom_node_append_attribute, "<node><child/></node>")
{
- CHECK(xml_node().append_attribute("a") == xml_attribute());
- CHECK(doc.append_attribute("a") == xml_attribute());
+ CHECK(xml_node().append_attribute(STR("a")) == xml_attribute());
+ CHECK(doc.append_attribute(STR("a")) == xml_attribute());
- xml_attribute a1 = doc.child("node").append_attribute("a1");
+ xml_attribute a1 = doc.child(STR("node")).append_attribute(STR("a1"));
CHECK(a1);
- a1 = "v1";
+ a1 = STR("v1");
- xml_attribute a2 = doc.child("node").append_attribute("a2");
+ xml_attribute a2 = doc.child(STR("node")).append_attribute(STR("a2"));
CHECK(a2 && a1 != a2);
- a2 = "v2";
+ a2 = STR("v2");
- xml_attribute a3 = doc.child("node").child("child").append_attribute("a3");
+ xml_attribute a3 = doc.child(STR("node")).child(STR("child")).append_attribute(STR("a3"));
CHECK(a3 && a1 != a3 && a2 != a3);
- a3 = "v3";
+ a3 = STR("v3");
- CHECK_NODE(doc, "<node a1=\"v1\" a2=\"v2\"><child a3=\"v3\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\"><child a3=\"v3\" /></node>"));
}
TEST_XML(dom_node_insert_attribute_after, "<node a1='v1'><child a2='v2'/></node>")
{
- CHECK(xml_node().insert_attribute_after("a", xml_attribute()) == xml_attribute());
+ CHECK(xml_node().insert_attribute_after(STR("a"), xml_attribute()) == xml_attribute());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
- xml_attribute a1 = node.attribute("a1");
- xml_attribute a2 = child.attribute("a2");
+ xml_attribute a1 = node.attribute(STR("a1"));
+ xml_attribute a2 = child.attribute(STR("a2"));
- CHECK(node.insert_attribute_after("a", xml_attribute()) == xml_attribute());
- CHECK(node.insert_attribute_after("a", a2) == xml_attribute());
+ CHECK(node.insert_attribute_after(STR("a"), xml_attribute()) == xml_attribute());
+ CHECK(node.insert_attribute_after(STR("a"), a2) == xml_attribute());
- xml_attribute a3 = node.insert_attribute_after("a3", a1);
+ xml_attribute a3 = node.insert_attribute_after(STR("a3"), a1);
CHECK(a3 && a3 != a2 && a3 != a1);
- a3 = "v3";
+ a3 = STR("v3");
- xml_attribute a4 = node.insert_attribute_after("a4", a1);
+ xml_attribute a4 = node.insert_attribute_after(STR("a4"), a1);
CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1);
- a4 = "v4";
+ a4 = STR("v4");
- xml_attribute a5 = node.insert_attribute_after("a5", a3);
+ xml_attribute a5 = node.insert_attribute_after(STR("a5"), a3);
CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1);
- a5 = "v5";
+ a5 = STR("v5");
- CHECK(child.insert_attribute_after("a", a4) == xml_attribute());
+ CHECK(child.insert_attribute_after(STR("a"), a4) == xml_attribute());
- CHECK_NODE(doc, "<node a1=\"v1\" a4=\"v4\" a3=\"v3\" a5=\"v5\"><child a2=\"v2\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a4=\"v4\" a3=\"v3\" a5=\"v5\"><child a2=\"v2\" /></node>"));
}
TEST_XML(dom_node_insert_attribute_before, "<node a1='v1'><child a2='v2'/></node>")
{
- CHECK(xml_node().insert_attribute_before("a", xml_attribute()) == xml_attribute());
+ CHECK(xml_node().insert_attribute_before(STR("a"), xml_attribute()) == xml_attribute());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
- xml_attribute a1 = node.attribute("a1");
- xml_attribute a2 = child.attribute("a2");
+ xml_attribute a1 = node.attribute(STR("a1"));
+ xml_attribute a2 = child.attribute(STR("a2"));
- CHECK(node.insert_attribute_before("a", xml_attribute()) == xml_attribute());
- CHECK(node.insert_attribute_before("a", a2) == xml_attribute());
+ CHECK(node.insert_attribute_before(STR("a"), xml_attribute()) == xml_attribute());
+ CHECK(node.insert_attribute_before(STR("a"), a2) == xml_attribute());
- xml_attribute a3 = node.insert_attribute_before("a3", a1);
+ xml_attribute a3 = node.insert_attribute_before(STR("a3"), a1);
CHECK(a3 && a3 != a2 && a3 != a1);
- a3 = "v3";
+ a3 = STR("v3");
- xml_attribute a4 = node.insert_attribute_before("a4", a1);
+ xml_attribute a4 = node.insert_attribute_before(STR("a4"), a1);
CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1);
- a4 = "v4";
+ a4 = STR("v4");
- xml_attribute a5 = node.insert_attribute_before("a5", a3);
+ xml_attribute a5 = node.insert_attribute_before(STR("a5"), a3);
CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1);
- a5 = "v5";
+ a5 = STR("v5");
- CHECK(child.insert_attribute_before("a", a4) == xml_attribute());
+ CHECK(child.insert_attribute_before(STR("a"), a4) == xml_attribute());
- CHECK_NODE(doc, "<node a5=\"v5\" a3=\"v3\" a4=\"v4\" a1=\"v1\"><child a2=\"v2\" /></node>");
+ CHECK_NODE(doc, STR("<node a5=\"v5\" a3=\"v3\" a4=\"v4\" a1=\"v1\"><child a2=\"v2\" /></node>"));
}
TEST_XML(dom_node_append_copy_attribute, "<node a1='v1'><child a2='v2'/><child/></node>")
{
CHECK(xml_node().append_copy(xml_attribute()) == xml_attribute());
- CHECK(xml_node().append_copy(doc.child("node").attribute("a1")) == xml_attribute());
- CHECK(doc.append_copy(doc.child("node").attribute("a1")) == xml_attribute());
+ CHECK(xml_node().append_copy(doc.child(STR("node")).attribute(STR("a1"))) == xml_attribute());
+ CHECK(doc.append_copy(doc.child(STR("node")).attribute(STR("a1"))) == xml_attribute());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
- xml_attribute a1 = node.attribute("a1");
- xml_attribute a2 = child.attribute("a2");
+ xml_attribute a1 = node.attribute(STR("a1"));
+ xml_attribute a2 = child.attribute(STR("a2"));
xml_attribute a3 = node.append_copy(a1);
CHECK(a3 && a3 != a2 && a3 != a1);
@@ -163,29 +175,29 @@ TEST_XML(dom_node_append_copy_attribute, "<node a1='v1'><child a2='v2'/><child/>
xml_attribute a5 = node.last_child().append_copy(a1);
CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1);
- CHECK_NODE(doc, "<node a1=\"v1\" a1=\"v1\" a2=\"v2\"><child a2=\"v2\" /><child a1=\"v1\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a1=\"v1\" a2=\"v2\"><child a2=\"v2\" /><child a1=\"v1\" /></node>"));
- a3.set_name("a3");
- a3 = "v3";
+ a3.set_name(STR("a3"));
+ a3 = STR("v3");
- a4.set_name("a4");
- a4 = "v4";
+ a4.set_name(STR("a4"));
+ a4 = STR("v4");
- a5.set_name("a5");
- a5 = "v5";
+ a5.set_name(STR("a5"));
+ a5 = STR("v5");
- CHECK_NODE(doc, "<node a1=\"v1\" a3=\"v3\" a4=\"v4\"><child a2=\"v2\" /><child a5=\"v5\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a3=\"v3\" a4=\"v4\"><child a2=\"v2\" /><child a5=\"v5\" /></node>"));
}
TEST_XML(dom_node_insert_copy_after_attribute, "<node a1='v1'><child a2='v2'/></node>")
{
CHECK(xml_node().insert_copy_after(xml_attribute(), xml_attribute()) == xml_attribute());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
- xml_attribute a1 = node.attribute("a1");
- xml_attribute a2 = child.attribute("a2");
+ xml_attribute a1 = node.attribute(STR("a1"));
+ xml_attribute a2 = child.attribute(STR("a2"));
CHECK(node.insert_copy_after(a1, xml_attribute()) == xml_attribute());
CHECK(node.insert_copy_after(xml_attribute(), a1) == xml_attribute());
@@ -202,29 +214,29 @@ TEST_XML(dom_node_insert_copy_after_attribute, "<node a1='v1'><child a2='v2'/></
CHECK(child.insert_copy_after(a4, a4) == xml_attribute());
- CHECK_NODE(doc, "<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\" /></node>"));
- a3.set_name("a3");
- a3 = "v3";
+ a3.set_name(STR("a3"));
+ a3 = STR("v3");
- a4.set_name("a4");
- a4 = "v4";
+ a4.set_name(STR("a4"));
+ a4 = STR("v4");
- a5.set_name("a5");
- a5 = "v5";
+ a5.set_name(STR("a5"));
+ a5 = STR("v5");
- CHECK_NODE(doc, "<node a1=\"v1\" a5=\"v5\" a4=\"v4\" a3=\"v3\"><child a2=\"v2\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a5=\"v5\" a4=\"v4\" a3=\"v3\"><child a2=\"v2\" /></node>"));
}
TEST_XML(dom_node_insert_copy_before_attribute, "<node a1='v1'><child a2='v2'/></node>")
{
CHECK(xml_node().insert_copy_before(xml_attribute(), xml_attribute()) == xml_attribute());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
- xml_attribute a1 = node.attribute("a1");
- xml_attribute a2 = child.attribute("a2");
+ xml_attribute a1 = node.attribute(STR("a1"));
+ xml_attribute a2 = child.attribute(STR("a2"));
CHECK(node.insert_copy_before(a1, xml_attribute()) == xml_attribute());
CHECK(node.insert_copy_before(xml_attribute(), a1) == xml_attribute());
@@ -241,243 +253,254 @@ TEST_XML(dom_node_insert_copy_before_attribute, "<node a1='v1'><child a2='v2'/><
CHECK(child.insert_copy_before(a4, a4) == xml_attribute());
- CHECK_NODE(doc, "<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\" /></node>"));
- a3.set_name("a3");
- a3 = "v3";
+ a3.set_name(STR("a3"));
+ a3 = STR("v3");
- a4.set_name("a4");
- a4 = "v4";
+ a4.set_name(STR("a4"));
+ a4 = STR("v4");
- a5.set_name("a5");
- a5 = "v5";
+ a5.set_name(STR("a5"));
+ a5 = STR("v5");
- CHECK_NODE(doc, "<node a3=\"v3\" a4=\"v4\" a5=\"v5\" a1=\"v1\"><child a2=\"v2\" /></node>");
+ CHECK_NODE(doc, STR("<node a3=\"v3\" a4=\"v4\" a5=\"v5\" a1=\"v1\"><child a2=\"v2\" /></node>"));
}
TEST_XML(dom_node_remove_attribute, "<node a1='v1' a2='v2' a3='v3'><child a4='v4'/></node>")
{
- xml_node().remove_attribute("a");
+ xml_node().remove_attribute(STR("a"));
xml_node().remove_attribute(xml_attribute());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
- node.remove_attribute("a");
+ node.remove_attribute(STR("a"));
node.remove_attribute(xml_attribute());
- node.remove_attribute(child.attribute("a4"));
+ node.remove_attribute(child.attribute(STR("a4")));
- CHECK_NODE(doc, "<node a1=\"v1\" a2=\"v2\" a3=\"v3\"><child a4=\"v4\" /></node>");
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\" a3=\"v3\"><child a4=\"v4\" /></node>"));
- node.remove_attribute("a1");
- node.remove_attribute(node.attribute("a3"));
- child.remove_attribute("a4");
+ node.remove_attribute(STR("a1"));
+ node.remove_attribute(node.attribute(STR("a3")));
+ child.remove_attribute(STR("a4"));
- CHECK_NODE(doc, "<node a2=\"v2\"><child /></node>");
+ CHECK_NODE(doc, STR("<node a2=\"v2\"><child /></node>"));
}
TEST_XML(dom_node_append_child, "<node>foo<child/></node>")
{
CHECK(xml_node().append_child() == xml_node());
- CHECK(doc.child("node").first_child().append_child() == xml_node());
+ CHECK(doc.child(STR("node")).first_child().append_child() == xml_node());
CHECK(doc.append_child(node_document) == xml_node());
CHECK(doc.append_child(node_null) == xml_node());
- xml_node n1 = doc.child("node").append_child();
+ xml_node n1 = doc.child(STR("node")).append_child();
CHECK(n1);
- CHECK(n1.set_name("n1"));
+ CHECK(n1.set_name(STR("n1")));
- xml_node n2 = doc.child("node").append_child();
+ xml_node n2 = doc.child(STR("node")).append_child();
CHECK(n2 && n1 != n2);
- CHECK(n2.set_name("n2"));
+ CHECK(n2.set_name(STR("n2")));
- xml_node n3 = doc.child("node").child("child").append_child(node_pcdata);
+ xml_node n3 = doc.child(STR("node")).child(STR("child")).append_child(node_pcdata);
CHECK(n3 && n1 != n3 && n2 != n3);
- CHECK(n3.set_value("n3"));
+ CHECK(n3.set_value(STR("n3")));
xml_node n4 = doc.append_child(node_comment);
CHECK(n4 && n1 != n4 && n2 != n4 && n3 != n4);
- CHECK(n4.set_value("n4"));
+ CHECK(n4.set_value(STR("n4")));
- CHECK_NODE(doc, "<node>foo<child>n3</child><n1 /><n2 /></node><!--n4-->");
+ CHECK_NODE(doc, STR("<node>foo<child>n3</child><n1 /><n2 /></node><!--n4-->"));
}
TEST_XML(dom_node_insert_child_after, "<node>foo<child/></node>")
{
CHECK(xml_node().insert_child_after(node_element, xml_node()) == xml_node());
- CHECK(doc.child("node").first_child().insert_child_after(node_element, xml_node()) == xml_node());
+ CHECK(doc.child(STR("node")).first_child().insert_child_after(node_element, xml_node()) == xml_node());
CHECK(doc.insert_child_after(node_document, xml_node()) == xml_node());
CHECK(doc.insert_child_after(node_null, xml_node()) == xml_node());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
CHECK(node.insert_child_after(node_element, node) == xml_node());
CHECK(child.insert_child_after(node_element, node) == xml_node());
xml_node n1 = node.insert_child_after(node_element, child);
CHECK(n1 && n1 != node && n1 != child);
- CHECK(n1.set_name("n1"));
+ CHECK(n1.set_name(STR("n1")));
xml_node n2 = node.insert_child_after(node_element, child);
CHECK(n2 && n2 != node && n2 != child && n2 != n1);
- CHECK(n2.set_name("n2"));
+ CHECK(n2.set_name(STR("n2")));
xml_node n3 = node.insert_child_after(node_pcdata, n2);
CHECK(n3 && n3 != node && n3 != child && n3 != n1 && n3 != n2);
- CHECK(n3.set_value("n3"));
+ CHECK(n3.set_value(STR("n3")));
xml_node n4 = node.insert_child_after(node_pi, node.first_child());
CHECK(n4 && n4 != node && n4 != child && n4 != n1 && n4 != n2 && n4 != n3);
- CHECK(n4.set_name("n4"));
+ CHECK(n4.set_name(STR("n4")));
CHECK(child.insert_child_after(node_element, n3) == xml_node());
- CHECK_NODE(doc, "<node>foo<?n4?><child /><n2 />n3<n1 /></node>");
+ CHECK_NODE(doc, STR("<node>foo<?n4?><child /><n2 />n3<n1 /></node>"));
}
TEST_XML(dom_node_insert_child_before, "<node>foo<child/></node>")
{
CHECK(xml_node().insert_child_before(node_element, xml_node()) == xml_node());
- CHECK(doc.child("node").first_child().insert_child_before(node_element, xml_node()) == xml_node());
+ CHECK(doc.child(STR("node")).first_child().insert_child_before(node_element, xml_node()) == xml_node());
CHECK(doc.insert_child_before(node_document, xml_node()) == xml_node());
CHECK(doc.insert_child_before(node_null, xml_node()) == xml_node());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
CHECK(node.insert_child_before(node_element, node) == xml_node());
CHECK(child.insert_child_before(node_element, node) == xml_node());
xml_node n1 = node.insert_child_before(node_element, child);
CHECK(n1 && n1 != node && n1 != child);
- CHECK(n1.set_name("n1"));
+ CHECK(n1.set_name(STR("n1")));
xml_node n2 = node.insert_child_before(node_element, child);
CHECK(n2 && n2 != node && n2 != child && n2 != n1);
- CHECK(n2.set_name("n2"));
+ CHECK(n2.set_name(STR("n2")));
xml_node n3 = node.insert_child_before(node_pcdata, n2);
CHECK(n3 && n3 != node && n3 != child && n3 != n1 && n3 != n2);
- CHECK(n3.set_value("n3"));
+ CHECK(n3.set_value(STR("n3")));
xml_node n4 = node.insert_child_before(node_pi, node.first_child());
CHECK(n4 && n4 != node && n4 != child && n4 != n1 && n4 != n2 && n4 != n3);
- CHECK(n4.set_name("n4"));
+ CHECK(n4.set_name(STR("n4")));
CHECK(child.insert_child_before(node_element, n3) == xml_node());
- CHECK_NODE(doc, "<node><?n4?>foo<n1 />n3<n2 /><child /></node>");
+ CHECK_NODE(doc, STR("<node><?n4?>foo<n1 />n3<n2 /><child /></node>"));
}
TEST_XML(dom_node_remove_child, "<node><n1/><n2/><n3/><child><n4/></child></node>")
{
- xml_node().remove_child("a");
+ xml_node().remove_child(STR("a"));
xml_node().remove_child(xml_node());
- xml_node node = doc.child("node");
- xml_node child = node.child("child");
+ xml_node node = doc.child(STR("node"));
+ xml_node child = node.child(STR("child"));
- node.remove_child("a");
+ node.remove_child(STR("a"));
node.remove_child(xml_node());
- node.remove_child(child.child("n4"));
+ node.remove_child(child.child(STR("n4")));
- CHECK_NODE(doc, "<node><n1 /><n2 /><n3 /><child><n4 /></child></node>");
+ CHECK_NODE(doc, STR("<node><n1 /><n2 /><n3 /><child><n4 /></child></node>"));
- node.remove_child("n1");
- node.remove_child(node.child("n3"));
- child.remove_child("n4");
+ node.remove_child(STR("n1"));
+ node.remove_child(node.child(STR("n3")));
+ child.remove_child(STR("n4"));
- CHECK_NODE(doc, "<node><n2 /><child /></node>");
+ CHECK_NODE(doc, STR("<node><n2 /><child /></node>"));
}
TEST_XML(dom_node_append_copy, "<node>foo<child/></node>")
{
CHECK(xml_node().append_copy(xml_node()) == xml_node());
- CHECK(doc.child("node").first_child().append_copy(doc.child("node")) == xml_node());
+ CHECK(doc.child(STR("node")).first_child().append_copy(doc.child(STR("node"))) == xml_node());
CHECK(doc.append_copy(doc) == xml_node());
CHECK(doc.append_copy(xml_node()) == xml_node());
- xml_node n1 = doc.child("node").append_copy(doc.child("node").first_child());
+ xml_node n1 = doc.child(STR("node")).append_copy(doc.child(STR("node")).first_child());
CHECK(n1);
- CHECK_STRING(n1.value(), "foo");
- CHECK_NODE(doc, "<node>foo<child />foo</node>");
+ CHECK_STRING(n1.value(), STR("foo"));
+ CHECK_NODE(doc, STR("<node>foo<child />foo</node>"));
- xml_node n2 = doc.child("node").append_copy(doc.child("node").child("child"));
+ xml_node n2 = doc.child(STR("node")).append_copy(doc.child(STR("node")).child(STR("child")));
CHECK(n2 && n2 != n1);
- CHECK_STRING(n2.name(), "child");
- CHECK_NODE(doc, "<node>foo<child />foo<child /></node>");
+ CHECK_STRING(n2.name(), STR("child"));
+ CHECK_NODE(doc, STR("<node>foo<child />foo<child /></node>"));
- xml_node n3 = doc.child("node").child("child").append_copy(doc.child("node").first_child());
+ xml_node n3 = doc.child(STR("node")).child(STR("child")).append_copy(doc.child(STR("node")).first_child());
CHECK(n3 && n3 != n1 && n3 != n2);
- CHECK_STRING(n3.value(), "foo");
- CHECK_NODE(doc, "<node>foo<child>foo</child>foo<child /></node>");
+ CHECK_STRING(n3.value(), STR("foo"));
+ CHECK_NODE(doc, STR("<node>foo<child>foo</child>foo<child /></node>"));
}
TEST_XML(dom_node_insert_copy_after, "<node>foo<child/></node>")
{
CHECK(xml_node().insert_copy_after(xml_node(), xml_node()) == xml_node());
- CHECK(doc.child("node").first_child().insert_copy_after(doc.child("node"), doc.child("node")) == xml_node());
+ CHECK(doc.child(STR("node")).first_child().insert_copy_after(doc.child(STR("node")), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_copy_after(doc, doc) == xml_node());
- CHECK(doc.insert_copy_after(xml_node(), doc.child("node")) == xml_node());
- CHECK(doc.insert_copy_after(doc.child("node"), xml_node()) == xml_node());
+ CHECK(doc.insert_copy_after(xml_node(), doc.child(STR("node"))) == xml_node());
+ CHECK(doc.insert_copy_after(doc.child(STR("node")), xml_node()) == xml_node());
- xml_node n1 = doc.child("node").insert_copy_after(doc.child("node").child("child"), doc.child("node").first_child());
+ xml_node n1 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child());
CHECK(n1);
- CHECK_STRING(n1.name(), "child");
- CHECK_NODE(doc, "<node>foo<child /><child /></node>");
+ CHECK_STRING(n1.name(), STR("child"));
+ CHECK_NODE(doc, STR("<node>foo<child /><child /></node>"));
- xml_node n2 = doc.child("node").insert_copy_after(doc.child("node").first_child(), doc.child("node").last_child());
+ xml_node n2 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).first_child(), doc.child(STR("node")).last_child());
CHECK(n2 && n2 != n1);
- CHECK_STRING(n2.value(), "foo");
- CHECK_NODE(doc, "<node>foo<child /><child />foo</node>");
+ CHECK_STRING(n2.value(), STR("foo"));
+ CHECK_NODE(doc, STR("<node>foo<child /><child />foo</node>"));
- xml_node n3 = doc.child("node").insert_copy_after(doc.child("node").first_child(), doc.child("node").first_child());
+ xml_node n3 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).first_child(), doc.child(STR("node")).first_child());
CHECK(n3 && n3 != n1 && n3 != n2);
- CHECK_STRING(n3.value(), "foo");
- CHECK_NODE(doc, "<node>foofoo<child /><child />foo</node>");
+ CHECK_STRING(n3.value(), STR("foo"));
+ CHECK_NODE(doc, STR("<node>foofoo<child /><child />foo</node>"));
}
TEST_XML(dom_node_insert_copy_before, "<node>foo<child/></node>")
{
CHECK(xml_node().insert_copy_before(xml_node(), xml_node()) == xml_node());
- CHECK(doc.child("node").first_child().insert_copy_before(doc.child("node"), doc.child("node")) == xml_node());
+ CHECK(doc.child(STR("node")).first_child().insert_copy_before(doc.child(STR("node")), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_copy_before(doc, doc) == xml_node());
- CHECK(doc.insert_copy_before(xml_node(), doc.child("node")) == xml_node());
- CHECK(doc.insert_copy_before(doc.child("node"), xml_node()) == xml_node());
+ CHECK(doc.insert_copy_before(xml_node(), doc.child(STR("node"))) == xml_node());
+ CHECK(doc.insert_copy_before(doc.child(STR("node")), xml_node()) == xml_node());
- xml_node n1 = doc.child("node").insert_copy_before(doc.child("node").child("child"), doc.child("node").first_child());
+ xml_node n1 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child());
CHECK(n1);
- CHECK_STRING(n1.name(), "child");
- CHECK_NODE(doc, "<node><child />foo<child /></node>");
+ CHECK_STRING(n1.name(), STR("child"));
+ CHECK_NODE(doc, STR("<node><child />foo<child /></node>"));
- xml_node n2 = doc.child("node").insert_copy_before(doc.child("node").first_child(), doc.child("node").last_child());
+ xml_node n2 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).first_child(), doc.child(STR("node")).last_child());
CHECK(n2 && n2 != n1);
- CHECK_STRING(n2.name(), "child");
- CHECK_NODE(doc, "<node><child />foo<child /><child /></node>");
+ CHECK_STRING(n2.name(), STR("child"));
+ CHECK_NODE(doc, STR("<node><child />foo<child /><child /></node>"));
- xml_node n3 = doc.child("node").insert_copy_before(doc.child("node").first_child().next_sibling(), doc.child("node").first_child());
+ xml_node n3 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).first_child().next_sibling(), doc.child(STR("node")).first_child());
CHECK(n3 && n3 != n1 && n3 != n2);
- CHECK_STRING(n3.value(), "foo");
- CHECK_NODE(doc, "<node>foo<child />foo<child /><child /></node>");
+ CHECK_STRING(n3.value(), STR("foo"));
+ CHECK_NODE(doc, STR("<node>foo<child />foo<child /><child /></node>"));
}
TEST_XML(dom_node_copy_recursive, "<node>foo<child/></node>")
{
- doc.child("node").append_copy(doc.child("node"));
- CHECK_NODE(doc, "<node>foo<child /><node>foo<child /></node></node>");
+ doc.child(STR("node")).append_copy(doc.child(STR("node")));
+ CHECK_NODE(doc, STR("<node>foo<child /><node>foo<child /></node></node>"));
}
TEST_XML(dom_node_copy_crossdoc, "<node/>")
{
xml_document newdoc;
- newdoc.append_copy(doc.child("node"));
- CHECK_NODE(doc, "<node />");
- CHECK_NODE(newdoc, "<node />");
+ newdoc.append_copy(doc.child(STR("node")));
+ CHECK_NODE(doc, STR("<node />"));
+ CHECK_NODE(newdoc, STR("<node />"));
}
TEST_XML_FLAGS(dom_node_copy_types, "<root><?xml version='1.0'?><?pi value?><!--comment--><node id='1'>pcdata<![CDATA[cdata]]></node></root>", parse_default | parse_pi | parse_comments | parse_declaration)
{
- doc.append_copy(doc.child("root"));
- CHECK_NODE(doc, "<root><?xml version=\"1.0\"?><?pi value?><!--comment--><node id=\"1\">pcdata<![CDATA[cdata]]></node></root><root><?xml version=\"1.0\"?><?pi value?><!--comment--><node id=\"1\">pcdata<![CDATA[cdata]]></node></root>");
+ doc.append_copy(doc.child(STR("root")));
+ CHECK_NODE(doc, STR("<root><?xml version=\"1.0\"?><?pi value?><!--comment--><node id=\"1\">pcdata<![CDATA[cdata]]></node></root><root><?xml version=\"1.0\"?><?pi value?><!--comment--><node id=\"1\">pcdata<![CDATA[cdata]]></node></root>"));
+}
+
+TEST_XML(dom_attr_assign_large, "<node attr1='' attr2='' />")
+{
+ xml_node node = doc.child(STR("node"));
+
+ node.attribute(STR("attr1")) = FLT_MAX;
+ node.attribute(STR("attr2")) = DBL_MAX;
+
+ CHECK(test_node(node, STR("<node attr1=\"3.40282e+038\" attr2=\"1.79769e+308\" />"), STR(""), pugi::format_raw) ||
+ test_node(node, STR("<node attr1=\"3.40282e+38\" attr2=\"1.79769e+308\" />"), STR(""), pugi::format_raw));
}
diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp
index 513263b..3d8a53f 100644
--- a/tests/test_dom_traverse.cpp
+++ b/tests/test_dom_traverse.cpp
@@ -2,9 +2,13 @@
#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
#include <utility>
#include <vector>
#include <iterator>
+#include <string>
#include "helpers.hpp"
@@ -37,28 +41,28 @@ template <typename T> static void generic_empty_test(const T& obj)
TEST_XML(dom_attr_bool_ops, "<node attr='1'/>")
{
- generic_bool_ops_test(doc.child("node").attribute("attr"));
+ generic_bool_ops_test(doc.child(STR("node")).attribute(STR("attr")));
}
TEST_XML(dom_attr_eq_ops, "<node attr1='1' attr2='2'/>")
{
- generic_eq_ops_test(doc.child("node").attribute("attr1"), doc.child("node").attribute("attr2"));
+ generic_eq_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2")));
}
TEST_XML(dom_attr_rel_ops, "<node attr1='1' attr2='2'/>")
{
- generic_rel_ops_test(doc.child("node").attribute("attr1"), doc.child("node").attribute("attr2"));
+ generic_rel_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2")));
}
TEST_XML(dom_attr_empty, "<node attr='1'/>")
{
- generic_empty_test(doc.child("node").attribute("attr"));
+ generic_empty_test(doc.child(STR("node")).attribute(STR("attr")));
}
TEST_XML(dom_attr_next_previous_attribute, "<node attr1='1' attr2='2' />")
{
- xml_attribute attr1 = doc.child("node").attribute("attr1");
- xml_attribute attr2 = doc.child("node").attribute("attr2");
+ xml_attribute attr1 = doc.child(STR("node")).attribute(STR("attr1"));
+ xml_attribute attr2 = doc.child(STR("node")).attribute(STR("attr2"));
CHECK(attr1.next_attribute() == attr2);
CHECK(attr2.next_attribute() == xml_attribute());
@@ -72,87 +76,87 @@ TEST_XML(dom_attr_next_previous_attribute, "<node attr1='1' attr2='2' />")
TEST_XML(dom_attr_name_value, "<node attr='1'/>")
{
- xml_attribute attr = doc.child("node").attribute("attr");
+ xml_attribute attr = doc.child(STR("node")).attribute(STR("attr"));
- CHECK_NAME_VALUE(attr, "attr", "1");
- CHECK_NAME_VALUE(xml_attribute(), "", "");
+ CHECK_NAME_VALUE(attr, STR("attr"), STR("1"));
+ CHECK_NAME_VALUE(xml_attribute(), STR(""), STR(""));
}
TEST_XML(dom_attr_as_int, "<node attr1='1' attr2='-1' attr3='-2147483648' attr4='2147483647'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
CHECK(xml_attribute().as_int() == 0);
- CHECK(node.attribute("attr1").as_int() == 1);
- CHECK(node.attribute("attr2").as_int() == -1);
- CHECK(node.attribute("attr3").as_int() == -2147483647 - 1);
- CHECK(node.attribute("attr4").as_int() == 2147483647);
+ CHECK(node.attribute(STR("attr1")).as_int() == 1);
+ CHECK(node.attribute(STR("attr2")).as_int() == -1);
+ CHECK(node.attribute(STR("attr3")).as_int() == -2147483647 - 1);
+ CHECK(node.attribute(STR("attr4")).as_int() == 2147483647);
}
TEST_XML(dom_attr_as_uint, "<node attr1='0' attr2='1' attr3='2147483647'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
CHECK(xml_attribute().as_uint() == 0);
- CHECK(node.attribute("attr1").as_uint() == 0);
- CHECK(node.attribute("attr2").as_uint() == 1);
- CHECK(node.attribute("attr3").as_uint() == 2147483647);
+ CHECK(node.attribute(STR("attr1")).as_uint() == 0);
+ CHECK(node.attribute(STR("attr2")).as_uint() == 1);
+ CHECK(node.attribute(STR("attr3")).as_uint() == 2147483647);
}
TEST_XML(dom_attr_as_float, "<node attr1='0' attr2='1' attr3='0.12' attr4='-5.1' attr5='3e-4' attr6='3.14159265358979323846'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
CHECK(xml_attribute().as_float() == 0);
- CHECK_DOUBLE(node.attribute("attr1").as_float(), 0);
- CHECK_DOUBLE(node.attribute("attr2").as_float(), 1);
- CHECK_DOUBLE(node.attribute("attr3").as_float(), 0.12);
- CHECK_DOUBLE(node.attribute("attr4").as_float(), -5.1);
- CHECK_DOUBLE(node.attribute("attr5").as_float(), 3e-4);
- CHECK_DOUBLE(node.attribute("attr6").as_float(), 3.14159265358979323846);
+ CHECK_DOUBLE(node.attribute(STR("attr1")).as_float(), 0);
+ CHECK_DOUBLE(node.attribute(STR("attr2")).as_float(), 1);
+ CHECK_DOUBLE(node.attribute(STR("attr3")).as_float(), 0.12);
+ CHECK_DOUBLE(node.attribute(STR("attr4")).as_float(), -5.1);
+ CHECK_DOUBLE(node.attribute(STR("attr5")).as_float(), 3e-4);
+ CHECK_DOUBLE(node.attribute(STR("attr6")).as_float(), 3.14159265358979323846);
}
TEST_XML(dom_attr_as_double, "<node attr1='0' attr2='1' attr3='0.12' attr4='-5.1' attr5='3e-4' attr6='3.14159265358979323846'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
CHECK(xml_attribute().as_double() == 0);
- CHECK_DOUBLE(node.attribute("attr1").as_double(), 0);
- CHECK_DOUBLE(node.attribute("attr2").as_double(), 1);
- CHECK_DOUBLE(node.attribute("attr3").as_double(), 0.12);
- CHECK_DOUBLE(node.attribute("attr4").as_double(), -5.1);
- CHECK_DOUBLE(node.attribute("attr5").as_double(), 3e-4);
- CHECK_DOUBLE(node.attribute("attr6").as_double(), 3.14159265358979323846);
+ CHECK_DOUBLE(node.attribute(STR("attr1")).as_double(), 0);
+ CHECK_DOUBLE(node.attribute(STR("attr2")).as_double(), 1);
+ CHECK_DOUBLE(node.attribute(STR("attr3")).as_double(), 0.12);
+ CHECK_DOUBLE(node.attribute(STR("attr4")).as_double(), -5.1);
+ CHECK_DOUBLE(node.attribute(STR("attr5")).as_double(), 3e-4);
+ CHECK_DOUBLE(node.attribute(STR("attr6")).as_double(), 3.14159265358979323846);
}
TEST_XML(dom_attr_as_bool, "<node attr1='0' attr2='1' attr3='true' attr4='True' attr5='Yes' attr6='yes' attr7='false'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
CHECK(!xml_attribute().as_bool());
- CHECK(!node.attribute("attr1").as_bool());
- CHECK(node.attribute("attr2").as_bool());
- CHECK(node.attribute("attr3").as_bool());
- CHECK(node.attribute("attr4").as_bool());
- CHECK(node.attribute("attr5").as_bool());
- CHECK(node.attribute("attr6").as_bool());
- CHECK(!node.attribute("attr7").as_bool());
+ CHECK(!node.attribute(STR("attr1")).as_bool());
+ CHECK(node.attribute(STR("attr2")).as_bool());
+ CHECK(node.attribute(STR("attr3")).as_bool());
+ CHECK(node.attribute(STR("attr4")).as_bool());
+ CHECK(node.attribute(STR("attr5")).as_bool());
+ CHECK(node.attribute(STR("attr6")).as_bool());
+ CHECK(!node.attribute(STR("attr7")).as_bool());
}
TEST_XML(dom_attr_iterator, "<node><node1 attr1='0'/><node2 attr1='0' attr2='1'/><node3/></node>")
{
- xml_node node1 = doc.child("node").child("node1");
- xml_node node2 = doc.child("node").child("node2");
- xml_node node3 = doc.child("node").child("node3");
+ xml_node node1 = doc.child(STR("node")).child(STR("node1"));
+ xml_node node2 = doc.child(STR("node")).child(STR("node2"));
+ xml_node node3 = doc.child(STR("node")).child(STR("node3"));
CHECK(xml_node().attributes_begin() == xml_attribute_iterator());
CHECK(xml_node().attributes_end() == xml_attribute_iterator());
- CHECK(node1.attributes_begin() == xml_attribute_iterator(node1.attribute("attr1")));
+ CHECK(node1.attributes_begin() == xml_attribute_iterator(node1.attribute(STR("attr1"))));
CHECK(move_iter(node1.attributes_begin(), 1) == node1.attributes_end());
CHECK(move_iter(node1.attributes_end(), -1) == node1.attributes_begin());
- CHECK(*node1.attributes_begin() == node1.attribute("attr1"));
- CHECK_STRING(node1.attributes_begin()->name(), "attr1");
+ CHECK(*node1.attributes_begin() == node1.attribute(STR("attr1")));
+ CHECK_STRING(node1.attributes_begin()->name(), STR("attr1"));
CHECK(move_iter(node2.attributes_begin(), 2) == node2.attributes_end());
CHECK(move_iter(node2.attributes_end(), -2) == node2.attributes_begin());
@@ -160,7 +164,7 @@ TEST_XML(dom_attr_iterator, "<node><node1 attr1='0'/><node2 attr1='0' attr2='1'/
CHECK(node3.attributes_begin() == xml_attribute_iterator());
CHECK(node3.attributes_begin() == node3.attributes_end());
- xml_attribute_iterator it = node2.attribute("attr2");
+ xml_attribute_iterator it = node2.attribute(STR("attr2"));
xml_attribute_iterator itt = it;
CHECK(itt++ == it);
@@ -180,38 +184,38 @@ TEST_XML(dom_attr_iterator, "<node><node1 attr1='0'/><node2 attr1='0' attr2='1'/
TEST_XML(dom_node_bool_ops, "<node/>")
{
- generic_bool_ops_test(doc.child("node"));
+ generic_bool_ops_test(doc.child(STR("node")));
}
TEST_XML(dom_node_eq_ops, "<node><node1/><node2/></node>")
{
- generic_eq_ops_test(doc.child("node").child("node1"), doc.child("node").child("node2"));
+ generic_eq_ops_test(doc.child(STR("node")).child(STR("node1")), doc.child(STR("node")).child(STR("node2")));
}
TEST_XML(dom_node_rel_ops, "<node><node1/><node2/></node>")
{
- generic_rel_ops_test(doc.child("node").child("node1"), doc.child("node").child("node2"));
+ generic_rel_ops_test(doc.child(STR("node")).child(STR("node1")), doc.child(STR("node")).child(STR("node2")));
}
TEST_XML(dom_node_empty, "<node/>")
{
- generic_empty_test(doc.child("node"));
+ generic_empty_test(doc.child(STR("node")));
}
TEST_XML(dom_node_iterator, "<node><node1><child1/></node1><node2><child1/><child2/></node2><node3/></node>")
{
- xml_node node1 = doc.child("node").child("node1");
- xml_node node2 = doc.child("node").child("node2");
- xml_node node3 = doc.child("node").child("node3");
+ xml_node node1 = doc.child(STR("node")).child(STR("node1"));
+ xml_node node2 = doc.child(STR("node")).child(STR("node2"));
+ xml_node node3 = doc.child(STR("node")).child(STR("node3"));
CHECK(xml_node().begin() == xml_node_iterator());
CHECK(xml_node().end() == xml_node_iterator());
- CHECK(node1.begin() == xml_node_iterator(node1.child("child1")));
+ CHECK(node1.begin() == xml_node_iterator(node1.child(STR("child1"))));
CHECK(move_iter(node1.begin(), 1) == node1.end());
CHECK(move_iter(node1.end(), -1) == node1.begin());
- CHECK(*node1.begin() == node1.child("child1"));
- CHECK_STRING(node1.begin()->name(), "child1");
+ CHECK(*node1.begin() == node1.child(STR("child1")));
+ CHECK_STRING(node1.begin()->name(), STR("child1"));
CHECK(move_iter(node2.begin(), 2) == node2.end());
CHECK(move_iter(node2.end(), -2) == node2.begin());
@@ -219,7 +223,7 @@ TEST_XML(dom_node_iterator, "<node><node1><child1/></node1><node2><child1/><chil
CHECK(node3.begin() == xml_node_iterator());
CHECK(node3.begin() == node3.end());
- xml_node_iterator it = node2.child("child2");
+ xml_node_iterator it = node2.child(STR("child2"));
xml_node_iterator itt = it;
CHECK(itt++ == it);
@@ -240,15 +244,15 @@ TEST_XML(dom_node_iterator, "<node><node1><child1/></node1><node2><child1/><chil
TEST_XML(dom_node_parent, "<node><child/></node>")
{
CHECK(xml_node().parent() == xml_node());
- CHECK(doc.child("node").child("child").parent() == doc.child("node"));
- CHECK(doc.child("node").parent() == doc);
+ CHECK(doc.child(STR("node")).child(STR("child")).parent() == doc.child(STR("node")));
+ CHECK(doc.child(STR("node")).parent() == doc);
}
TEST_XML(dom_node_root, "<node><child/></node>")
{
CHECK(xml_node().root() == xml_node());
- CHECK(doc.child("node").child("child").root() == doc);
- CHECK(doc.child("node").root() == doc);
+ CHECK(doc.child(STR("node")).child(STR("child")).root() == doc);
+ CHECK(doc.child(STR("node")).root() == doc);
}
TEST_XML_FLAGS(dom_node_type, "<?xml?><?pi?><!--comment--><node>pcdata<![CDATA[cdata]]></node>", parse_default | parse_pi | parse_comments | parse_declaration)
@@ -263,7 +267,7 @@ TEST_XML_FLAGS(dom_node_type, "<?xml?><?pi?><!--comment--><node>pcdata<![CDATA[c
CHECK((it++)->type() == node_comment);
CHECK((it++)->type() == node_element);
- xml_node_iterator cit = doc.child("node").begin();
+ xml_node_iterator cit = doc.child(STR("node")).begin();
CHECK((cit++)->type() == node_pcdata);
CHECK((cit++)->type() == node_cdata);
@@ -271,64 +275,64 @@ TEST_XML_FLAGS(dom_node_type, "<?xml?><?pi?><!--comment--><node>pcdata<![CDATA[c
TEST_XML_FLAGS(dom_node_name_value, "<?xml?><?pi?><!--comment--><node>pcdata<![CDATA[cdata]]></node>", parse_default | parse_pi | parse_comments | parse_declaration)
{
- CHECK_NAME_VALUE(xml_node(), "", "");
- CHECK_NAME_VALUE(doc, "", "");
+ CHECK_NAME_VALUE(xml_node(), STR(""), STR(""));
+ CHECK_NAME_VALUE(doc, STR(""), STR(""));
xml_node_iterator it = doc.begin();
- CHECK_NAME_VALUE(*it++, "xml", "");
- CHECK_NAME_VALUE(*it++, "pi", "");
- CHECK_NAME_VALUE(*it++, "", "comment");
- CHECK_NAME_VALUE(*it++, "node", "");
+ CHECK_NAME_VALUE(*it++, STR("xml"), STR(""));
+ CHECK_NAME_VALUE(*it++, STR("pi"), STR(""));
+ CHECK_NAME_VALUE(*it++, STR(""), STR("comment"));
+ CHECK_NAME_VALUE(*it++, STR("node"), STR(""));
- xml_node_iterator cit = doc.child("node").begin();
+ xml_node_iterator cit = doc.child(STR("node")).begin();
- CHECK_NAME_VALUE(*cit++, "", "pcdata");
- CHECK_NAME_VALUE(*cit++, "", "cdata");
+ CHECK_NAME_VALUE(*cit++, STR(""), STR("pcdata"));
+ CHECK_NAME_VALUE(*cit++, STR(""), STR("cdata"));
}
TEST_XML(dom_node_child, "<node><child1/><child2/></node>")
{
- CHECK(xml_node().child("n") == xml_node());
+ CHECK(xml_node().child(STR("n")) == xml_node());
- CHECK(doc.child("n") == xml_node());
- CHECK_NAME_VALUE(doc.child("node"), "node", "");
- CHECK(doc.child("node").child("child2") == doc.child("node").last_child());
+ CHECK(doc.child(STR("n")) == xml_node());
+ CHECK_NAME_VALUE(doc.child(STR("node")), STR("node"), STR(""));
+ CHECK(doc.child(STR("node")).child(STR("child2")) == doc.child(STR("node")).last_child());
- CHECK(doc.child_w("n?de") == doc.child("node"));
- CHECK(doc.child_w("n[az]de") == xml_node());
- CHECK(doc.child_w("n[aoz]de") == doc.child("node"));
- CHECK(doc.child_w("*e") == doc.child("node"));
- CHECK(doc.child("node").child_w("*l?[23456789]*") == doc.child("node").child("child2"));
+ CHECK(doc.child_w(STR("n?de")) == doc.child(STR("node")));
+ CHECK(doc.child_w(STR("n[az]de")) == xml_node());
+ CHECK(doc.child_w(STR("n[aoz]de")) == doc.child(STR("node")));
+ CHECK(doc.child_w(STR("*e")) == doc.child(STR("node")));
+ CHECK(doc.child(STR("node")).child_w(STR("*l?[23456789]*")) == doc.child(STR("node")).child(STR("child2")));
}
TEST_XML(dom_node_attribute, "<node attr1='0' attr2='1'/>")
{
- CHECK(xml_node().attribute("a") == xml_attribute());
+ CHECK(xml_node().attribute(STR("a")) == xml_attribute());
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.attribute("n") == xml_attribute());
- CHECK_NAME_VALUE(node.attribute("attr1"), "attr1", "0");
- CHECK(node.attribute("attr2") == node.last_attribute());
+ CHECK(node.attribute(STR("n")) == xml_attribute());
+ CHECK_NAME_VALUE(node.attribute(STR("attr1")), STR("attr1"), STR("0"));
+ CHECK(node.attribute(STR("attr2")) == node.last_attribute());
- CHECK(node.attribute_w("*tt?[23456789]*") == node.attribute("attr2"));
- CHECK(node.attribute_w("?") == xml_attribute());
+ CHECK(node.attribute_w(STR("*tt?[23456789]*")) == node.attribute(STR("attr2")));
+ CHECK(node.attribute_w(STR("?")) == xml_attribute());
}
TEST_XML(dom_node_next_previous_sibling, "<node><child1/><child2/><child3/></node>")
{
CHECK(xml_node().next_sibling() == xml_node());
- CHECK(xml_node().next_sibling("n") == xml_node());
- CHECK(xml_node().next_sibling_w("n") == xml_node());
+ CHECK(xml_node().next_sibling(STR("n")) == xml_node());
+ CHECK(xml_node().next_sibling_w(STR("n")) == xml_node());
CHECK(xml_node().previous_sibling() == xml_node());
- CHECK(xml_node().previous_sibling("n") == xml_node());
- CHECK(xml_node().previous_sibling_w("n") == xml_node());
+ CHECK(xml_node().previous_sibling(STR("n")) == xml_node());
+ CHECK(xml_node().previous_sibling_w(STR("n")) == xml_node());
- xml_node child1 = doc.child("node").child("child1");
- xml_node child2 = doc.child("node").child("child2");
- xml_node child3 = doc.child("node").child("child3");
+ xml_node child1 = doc.child(STR("node")).child(STR("child1"));
+ xml_node child2 = doc.child(STR("node")).child(STR("child2"));
+ xml_node child3 = doc.child(STR("node")).child(STR("child3"));
CHECK(child1.next_sibling() == child2);
CHECK(child3.next_sibling() == xml_node());
@@ -336,41 +340,42 @@ TEST_XML(dom_node_next_previous_sibling, "<node><child1/><child2/><child3/></nod
CHECK(child1.previous_sibling() == xml_node());
CHECK(child3.previous_sibling() == child2);
- CHECK(child1.next_sibling("child3") == child3);
- CHECK(child1.next_sibling("child") == xml_node());
+ CHECK(child1.next_sibling(STR("child3")) == child3);
+ CHECK(child1.next_sibling(STR("child")) == xml_node());
- CHECK(child3.previous_sibling("child1") == child1);
- CHECK(child3.previous_sibling("child") == xml_node());
+ CHECK(child3.previous_sibling(STR("child1")) == child1);
+ CHECK(child3.previous_sibling(STR("child")) == xml_node());
- CHECK(child1.next_sibling_w("*[3456789]") == child3);
- CHECK(child1.next_sibling_w("?") == xml_node());
- CHECK(child3.previous_sibling_w("*[3456789]") == xml_node());
- CHECK(child3.previous_sibling_w("?") == xml_node());
+ CHECK(child1.next_sibling_w(STR("*[3456789]")) == child3);
+ CHECK(child1.next_sibling_w(STR("?")) == xml_node());
+ CHECK(child3.previous_sibling_w(STR("*[3456789]")) == xml_node());
+ CHECK(child3.previous_sibling_w(STR("?")) == xml_node());
+ CHECK(child3.previous_sibling_w(STR("*1")) == child1);
}
TEST_XML(dom_node_child_value, "<node><novalue/><child1>value1</child1><child2>value2<n/></child2><child3><![CDATA[value3]]></child3>value4</node>")
{
- CHECK_STRING(xml_node().child_value(), "");
- CHECK_STRING(xml_node().child_value("n"), "");
- CHECK_STRING(xml_node().child_value_w("n"), "");
+ CHECK_STRING(xml_node().child_value(), STR(""));
+ CHECK_STRING(xml_node().child_value(STR("n")), STR(""));
+ CHECK_STRING(xml_node().child_value_w(STR("n")), STR(""));
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK_STRING(node.child_value(), "value4");
- CHECK_STRING(node.child("child1").child_value(), "value1");
- CHECK_STRING(node.child("child2").child_value(), "value2");
- CHECK_STRING(node.child("child3").child_value(), "value3");
- CHECK_STRING(node.child_value("child3"), "value3");
- CHECK_STRING(node.child_value_w("c*[23456789]"), "value2");
- CHECK_STRING(node.child_value_w("*"), ""); // child_value(name) and child_value_w(pattern) do not continue the search if a node w/out value is found first
+ CHECK_STRING(node.child_value(), STR("value4"));
+ CHECK_STRING(node.child(STR("child1")).child_value(), STR("value1"));
+ CHECK_STRING(node.child(STR("child2")).child_value(), STR("value2"));
+ CHECK_STRING(node.child(STR("child3")).child_value(), STR("value3"));
+ CHECK_STRING(node.child_value(STR("child3")), STR("value3"));
+ CHECK_STRING(node.child_value_w(STR("c*[23456789]")), STR("value2"));
+ CHECK_STRING(node.child_value_w(STR("*")), STR("")); // child_value(name) and child_value_w(pattern) do not continue the search if a node w/out value is found first
}
TEST_XML(dom_node_first_last_attribute, "<node attr1='0' attr2='1'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.first_attribute() == node.attribute("attr1"));
- CHECK(node.last_attribute() == node.attribute("attr2"));
+ CHECK(node.first_attribute() == node.attribute(STR("attr1")));
+ CHECK(node.last_attribute() == node.attribute(STR("attr2")));
CHECK(xml_node().first_attribute() == xml_attribute());
CHECK(xml_node().last_attribute() == xml_attribute());
@@ -381,10 +386,10 @@ TEST_XML(dom_node_first_last_attribute, "<node attr1='0' attr2='1'/>")
TEST_XML(dom_node_first_last_child, "<node><child1/><child2/></node>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.first_child() == node.child("child1"));
- CHECK(node.last_child() == node.child("child2"));
+ CHECK(node.first_child() == node.child(STR("child1")));
+ CHECK(node.last_child() == node.child(STR("child2")));
CHECK(xml_node().first_child() == xml_node());
CHECK(xml_node().last_child() == xml_node());
@@ -395,22 +400,22 @@ TEST_XML(dom_node_first_last_child, "<node><child1/><child2/></node>")
TEST_XML(dom_node_find_child_by_attribute, "<node><child1 attr='value1'/><child2 attr='value2'/><child2 attr='value3'/></node>")
{
- CHECK(xml_node().find_child_by_attribute("name", "attr", "value") == xml_node());
- CHECK(xml_node().find_child_by_attribute_w("name", "attr", "value") == xml_node());
- CHECK(xml_node().find_child_by_attribute("attr", "value") == xml_node());
- CHECK(xml_node().find_child_by_attribute_w("attr", "value") == xml_node());
+ CHECK(xml_node().find_child_by_attribute(STR("name"), STR("attr"), STR("value")) == xml_node());
+ CHECK(xml_node().find_child_by_attribute_w(STR("name"), STR("attr"), STR("value")) == xml_node());
+ CHECK(xml_node().find_child_by_attribute(STR("attr"), STR("value")) == xml_node());
+ CHECK(xml_node().find_child_by_attribute_w(STR("attr"), STR("value")) == xml_node());
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.find_child_by_attribute("child2", "attr", "value3") == node.last_child());
- CHECK(node.find_child_by_attribute("child2", "attr3", "value3") == xml_node());
- CHECK(node.find_child_by_attribute("attr", "value2") == node.child("child2"));
- CHECK(node.find_child_by_attribute("attr3", "value") == xml_node());
+ CHECK(node.find_child_by_attribute(STR("child2"), STR("attr"), STR("value3")) == node.last_child());
+ CHECK(node.find_child_by_attribute(STR("child2"), STR("attr3"), STR("value3")) == xml_node());
+ CHECK(node.find_child_by_attribute(STR("attr"), STR("value2")) == node.child(STR("child2")));
+ CHECK(node.find_child_by_attribute(STR("attr3"), STR("value")) == xml_node());
- CHECK(node.find_child_by_attribute_w("*", "att?", "val*[0123456789]") == node.child("child1"));
- CHECK(node.find_child_by_attribute_w("*", "attr3", "val*[0123456789]") == xml_node());
- CHECK(node.find_child_by_attribute_w("att?", "val*[0123456789]") == node.child("child1"));
- CHECK(node.find_child_by_attribute_w("attr3", "val*[0123456789]") == xml_node());
+ CHECK(node.find_child_by_attribute_w(STR("*"), STR("att?"), STR("val*[0123456789]")) == node.child(STR("child1")));
+ CHECK(node.find_child_by_attribute_w(STR("*"), STR("attr3"), STR("val*[0123456789]")) == xml_node());
+ CHECK(node.find_child_by_attribute_w(STR("att?"), STR("val*[0123456789]")) == node.child(STR("child1")));
+ CHECK(node.find_child_by_attribute_w(STR("attr3"), STR("val*[0123456789]")) == xml_node());
}
TEST_XML(dom_node_all_elements_by_name, "<node><child><child/><child/></child></node>")
@@ -418,31 +423,31 @@ TEST_XML(dom_node_all_elements_by_name, "<node><child><child/><child/></child></
std::vector<xml_node> v;
v.clear();
- xml_node().all_elements_by_name("node", std::back_inserter(v));
+ xml_node().all_elements_by_name(STR("node"), std::back_inserter(v));
CHECK(v.empty());
v.clear();
- xml_node().all_elements_by_name_w("*", std::back_inserter(v));
+ xml_node().all_elements_by_name_w(STR("*"), std::back_inserter(v));
CHECK(v.empty());
v.clear();
- doc.all_elements_by_name("node", std::back_inserter(v));
- CHECK(v.size() == 1 && v[0] == doc.child("node"));
+ doc.all_elements_by_name(STR("node"), std::back_inserter(v));
+ CHECK(v.size() == 1 && v[0] == doc.child(STR("node")));
v.clear();
- doc.all_elements_by_name("child", std::back_inserter(v));
+ doc.all_elements_by_name(STR("child"), std::back_inserter(v));
CHECK(v.size() == 3);
- CHECK(v[0] == doc.child("node").child("child"));
- CHECK(v[1] == doc.child("node").child("child").first_child());
- CHECK(v[2] == doc.child("node").child("child").last_child());
+ CHECK(v[0] == doc.child(STR("node")).child(STR("child")));
+ CHECK(v[1] == doc.child(STR("node")).child(STR("child")).first_child());
+ CHECK(v[2] == doc.child(STR("node")).child(STR("child")).last_child());
v.clear();
- doc.all_elements_by_name_w("*", std::back_inserter(v));
+ doc.all_elements_by_name_w(STR("*"), std::back_inserter(v));
CHECK(v.size() == 4);
- CHECK(v[0] == doc.child("node"));
- CHECK(v[1] == doc.child("node").child("child"));
- CHECK(v[2] == doc.child("node").child("child").first_child());
- CHECK(v[3] == doc.child("node").child("child").last_child());
+ CHECK(v[0] == doc.child(STR("node")));
+ CHECK(v[1] == doc.child(STR("node")).child(STR("child")));
+ CHECK(v[2] == doc.child(STR("node")).child(STR("child")).first_child());
+ CHECK(v[3] == doc.child(STR("node")).child(STR("child")).last_child());
}
struct find_predicate_const
@@ -461,15 +466,20 @@ struct find_predicate_const
struct find_predicate_prefix
{
- const char* prefix;
+ const pugi::char_t* prefix;
- find_predicate_prefix(const char* prefix): prefix(prefix)
+ find_predicate_prefix(const pugi::char_t* prefix): prefix(prefix)
{
}
template <typename T> bool operator()(const T& obj) const
{
+ #ifdef PUGIXML_WCHAR_MODE
+ // can't use wcsncmp here because of a bug in DMC
+ return std::basic_string<pugi::char_t>(obj.name()).compare(0, wcslen(prefix), prefix) == 0;
+ #else
return strncmp(obj.name(), prefix, strlen(prefix)) == 0;
+ #endif
}
};
@@ -477,86 +487,86 @@ TEST_XML(dom_node_find_attribute, "<node attr1='0' attr2='1'/>")
{
CHECK(xml_node().find_attribute(find_predicate_const(true)) == xml_attribute());
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
CHECK(doc.find_attribute(find_predicate_const(true)) == xml_attribute());
CHECK(node.find_attribute(find_predicate_const(true)) == node.first_attribute());
CHECK(node.find_attribute(find_predicate_const(false)) == xml_attribute());
- CHECK(node.find_attribute(find_predicate_prefix("attr2")) == node.last_attribute());
- CHECK(node.find_attribute(find_predicate_prefix("attr")) == node.first_attribute());
+ CHECK(node.find_attribute(find_predicate_prefix(STR("attr2"))) == node.last_attribute());
+ CHECK(node.find_attribute(find_predicate_prefix(STR("attr"))) == node.first_attribute());
}
TEST_XML(dom_node_find_child, "<node><child1/><child2/></node>")
{
CHECK(xml_node().find_child(find_predicate_const(true)) == xml_node());
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.child("node").child("child1").find_child(find_predicate_const(true)) == xml_node());
+ CHECK(node.child(STR("node")).child(STR("child1")).find_child(find_predicate_const(true)) == xml_node());
CHECK(node.find_child(find_predicate_const(true)) == node.first_child());
CHECK(node.find_child(find_predicate_const(false)) == xml_node());
- CHECK(node.find_child(find_predicate_prefix("child2")) == node.last_child());
- CHECK(node.find_child(find_predicate_prefix("child")) == node.first_child());
+ CHECK(node.find_child(find_predicate_prefix(STR("child2"))) == node.last_child());
+ CHECK(node.find_child(find_predicate_prefix(STR("child"))) == node.first_child());
}
TEST_XML(dom_node_find_node, "<node><child1/><child2/></node>")
{
CHECK(xml_node().find_node(find_predicate_const(true)) == xml_node());
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.child("node").child("child1").find_node(find_predicate_const(true)) == xml_node());
+ CHECK(node.child(STR("node")).child(STR("child1")).find_node(find_predicate_const(true)) == xml_node());
CHECK(node.find_node(find_predicate_const(true)) == node.first_child());
CHECK(node.find_node(find_predicate_const(false)) == xml_node());
- CHECK(node.find_node(find_predicate_prefix("child2")) == node.last_child());
- CHECK(node.find_node(find_predicate_prefix("child")) == node.first_child());
- CHECK(doc.find_node(find_predicate_prefix("child")) == node.first_child());
- CHECK(doc.find_node(find_predicate_prefix("child2")) == node.last_child());
- CHECK(doc.find_node(find_predicate_prefix("child3")) == xml_node());
+ CHECK(node.find_node(find_predicate_prefix(STR("child2"))) == node.last_child());
+ CHECK(node.find_node(find_predicate_prefix(STR("child"))) == node.first_child());
+ CHECK(doc.find_node(find_predicate_prefix(STR("child"))) == node.first_child());
+ CHECK(doc.find_node(find_predicate_prefix(STR("child2"))) == node.last_child());
+ CHECK(doc.find_node(find_predicate_prefix(STR("child3"))) == xml_node());
}
#ifndef PUGIXML_NO_STL
TEST_XML(dom_node_path, "<node><child1>text<child2/></child1></node>")
{
- CHECK(xml_node().path() == "");
+ CHECK(xml_node().path() == STR(""));
- CHECK(doc.path() == "");
- CHECK(doc.child("node").path() == "/node");
- CHECK(doc.child("node").child("child1").path() == "/node/child1");
- CHECK(doc.child("node").child("child1").child("child2").path() == "/node/child1/child2");
- CHECK(doc.child("node").child("child1").first_child().path() == "/node/child1/");
+ CHECK(doc.path() == STR(""));
+ CHECK(doc.child(STR("node")).path() == STR("/node"));
+ CHECK(doc.child(STR("node")).child(STR("child1")).path() == STR("/node/child1"));
+ CHECK(doc.child(STR("node")).child(STR("child1")).child(STR("child2")).path() == STR("/node/child1/child2"));
+ CHECK(doc.child(STR("node")).child(STR("child1")).first_child().path() == STR("/node/child1/"));
- CHECK(doc.child("node").child("child1").path('\\') == "\\node\\child1");
+ CHECK(doc.child(STR("node")).child(STR("child1")).path('\\') == STR("\\node\\child1"));
}
#endif
TEST_XML(dom_node_first_element_by_path, "<node><child1>text<child2/></child1></node>")
{
- CHECK(xml_node().first_element_by_path("/") == xml_node());
+ CHECK(xml_node().first_element_by_path(STR("/")) == xml_node());
- CHECK(doc.first_element_by_path("") == doc);
- CHECK(doc.first_element_by_path("/") == doc);
+ CHECK(doc.first_element_by_path(STR("")) == doc);
+ CHECK(doc.first_element_by_path(STR("/")) == doc);
- CHECK(doc.first_element_by_path("/node/") == doc.child("node"));
- CHECK(doc.first_element_by_path("node/") == doc.child("node"));
- CHECK(doc.first_element_by_path("node") == doc.child("node"));
- CHECK(doc.first_element_by_path("/node") == doc.child("node"));
+ CHECK(doc.first_element_by_path(STR("/node/")) == doc.child(STR("node")));
+ CHECK(doc.first_element_by_path(STR("node/")) == doc.child(STR("node")));
+ CHECK(doc.first_element_by_path(STR("node")) == doc.child(STR("node")));
+ CHECK(doc.first_element_by_path(STR("/node")) == doc.child(STR("node")));
#ifndef PUGIXML_NO_STL
- CHECK(doc.first_element_by_path("/node/child1/child2").path() == "/node/child1/child2");
+ CHECK(doc.first_element_by_path(STR("/node/child1/child2")).path() == STR("/node/child1/child2"));
#endif
- CHECK(doc.first_element_by_path("/node/child2") == xml_node());
+ CHECK(doc.first_element_by_path(STR("/node/child2")) == xml_node());
- CHECK(doc.first_element_by_path("\\node\\child1", '\\') == doc.child("node").child("child1"));
+ CHECK(doc.first_element_by_path(STR("\\node\\child1"), '\\') == doc.child(STR("node")).child(STR("child1")));
- CHECK(doc.child("node").first_element_by_path("..") == doc);
- CHECK(doc.child("node").first_element_by_path(".") == doc.child("node"));
+ CHECK(doc.child(STR("node")).first_element_by_path(STR("..")) == doc);
+ CHECK(doc.child(STR("node")).first_element_by_path(STR(".")) == doc.child(STR("node")));
}
struct test_walker: xml_tree_walker
{
- std::string log;
+ std::basic_string<pugi::char_t> log;
unsigned int call_count;
unsigned int stop_count;
@@ -564,32 +574,53 @@ struct test_walker: xml_tree_walker
{
}
- virtual bool begin(xml_node& node)
+ std::basic_string<pugi::char_t> depthstr() const
{
- char buffer[32];
- sprintf(buffer, "|%d <%s=%s", depth(), node.name(), node.value());
+ char buf[32];
+ sprintf(buf, "%d", depth());
+
+ #ifdef PUGIXML_WCHAR_MODE
+ wchar_t wbuf[32];
+ std::copy(buf, buf + strlen(buf) + 1, wbuf);
+
+ return std::basic_string<pugi::char_t>(wbuf);
+ #else
+ return std::basic_string<pugi::char_t>(buf);
+ #endif
+ }
- log += buffer;
+ virtual bool begin(xml_node& node)
+ {
+ log += STR("|");
+ log += depthstr();
+ log += STR(" <");
+ log += node.name();
+ log += STR("=");
+ log += node.value();
return ++call_count != stop_count && xml_tree_walker::begin(node);
}
virtual bool for_each(xml_node& node)
{
- char buffer[32];
- sprintf(buffer, "|%d !%s=%s", depth(), node.name(), node.value());
-
- log += buffer;
+ log += STR("|");
+ log += depthstr();
+ log += STR(" !");
+ log += node.name();
+ log += STR("=");
+ log += node.value();
return ++call_count != stop_count && xml_tree_walker::end(node);
}
virtual bool end(xml_node& node)
{
- char buffer[32];
- sprintf(buffer, "|%d >%s=%s", depth(), node.name(), node.value());
-
- log += buffer;
+ log += STR("|");
+ log += depthstr();
+ log += STR(" >");
+ log += node.name();
+ log += STR("=");
+ log += node.value();
return ++call_count != stop_count;
}
@@ -602,7 +633,7 @@ TEST_XML(dom_node_traverse, "<node><child>text</child></node>")
CHECK(doc.traverse(walker));
CHECK(walker.call_count == 5);
- CHECK(walker.log == "|-1 <=|0 !node=|1 !child=|2 !=text|-1 >=");
+ CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|2 !=text|-1 >="));
}
TEST_XML(dom_node_traverse_siblings, "<node><child/><child>text</child><child/></node>")
@@ -612,7 +643,7 @@ TEST_XML(dom_node_traverse_siblings, "<node><child/><child>text</child><child/><
CHECK(doc.traverse(walker));
CHECK(walker.call_count == 7);
- CHECK(walker.log == "|-1 <=|0 !node=|1 !child=|1 !child=|2 !=text|1 !child=|-1 >=");
+ CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|1 !child=|2 !=text|1 !child=|-1 >="));
}
TEST(dom_node_traverse_empty)
@@ -622,17 +653,17 @@ TEST(dom_node_traverse_empty)
CHECK(xml_node().traverse(walker));
CHECK(walker.call_count == 2);
- CHECK(walker.log == "|-1 <=|-1 >=");
+ CHECK(walker.log == STR("|-1 <=|-1 >="));
}
TEST_XML(dom_node_traverse_child, "<node><child>text</child></node>")
{
test_walker walker;
- CHECK(doc.child("node").traverse(walker));
+ CHECK(doc.child(STR("node")).traverse(walker));
CHECK(walker.call_count == 4);
- CHECK(walker.log == "|-1 <node=|0 !child=|1 !=text|-1 >node=");
+ CHECK(walker.log == STR("|-1 <node=|0 !child=|1 !=text|-1 >node="));
}
TEST_XML(dom_node_traverse_stop_begin, "<node><child>text</child></node>")
@@ -642,7 +673,7 @@ TEST_XML(dom_node_traverse_stop_begin, "<node><child>text</child></node>")
CHECK(!doc.traverse(walker));
CHECK(walker.call_count == 1);
- CHECK(walker.log == "|-1 <=");
+ CHECK(walker.log == STR("|-1 <="));
}
TEST_XML(dom_node_traverse_stop_for_each, "<node><child>text</child></node>")
@@ -652,7 +683,7 @@ TEST_XML(dom_node_traverse_stop_for_each, "<node><child>text</child></node>")
CHECK(!doc.traverse(walker));
CHECK(walker.call_count == 3);
- CHECK(walker.log == "|-1 <=|0 !node=|1 !child=");
+ CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child="));
}
TEST_XML(dom_node_traverse_stop_end, "<node><child>text</child></node>")
@@ -662,7 +693,7 @@ TEST_XML(dom_node_traverse_stop_end, "<node><child>text</child></node>")
CHECK(!doc.traverse(walker));
CHECK(walker.call_count == 5);
- CHECK(walker.log == "|-1 <=|0 !node=|1 !child=|2 !=text|-1 >=");
+ CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|2 !=text|-1 >="));
}
TEST_XML_FLAGS(dom_offset_debug, "<?xml?><?pi?><!--comment--><node>pcdata<![CDATA[cdata]]></node>", parse_default | parse_pi | parse_comments | parse_declaration)
@@ -677,7 +708,7 @@ TEST_XML_FLAGS(dom_offset_debug, "<?xml?><?pi?><!--comment--><node>pcdata<![CDAT
CHECK((it++)->offset_debug() == 17);
CHECK((it++)->offset_debug() == 28);
- xml_node_iterator cit = doc.child("node").begin();
+ xml_node_iterator cit = doc.child(STR("node")).begin();
CHECK((cit++)->offset_debug() == 33);
CHECK((cit++)->offset_debug() == 48);
@@ -685,24 +716,24 @@ TEST_XML_FLAGS(dom_offset_debug, "<?xml?><?pi?><!--comment--><node>pcdata<![CDAT
TEST_XML(dom_node_wildcard_cset, "<node c='1'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.attribute_w("[A-Z]").as_int() == 0);
- CHECK(node.attribute_w("[a-z]").as_int() == 1);
- CHECK(node.attribute_w("[A-z]").as_int() == 1);
- CHECK(node.attribute_w("[z-a]").as_int() == 0);
- CHECK(node.attribute_w("[a-zA-Z]").as_int() == 1);
- CHECK(node.attribute_w("[!A-Z]").as_int() == 1);
- CHECK(node.attribute_w("[!A-Za-z]").as_int() == 0);
+ CHECK(node.attribute_w(STR("[A-Z]")).as_int() == 0);
+ CHECK(node.attribute_w(STR("[a-z]")).as_int() == 1);
+ CHECK(node.attribute_w(STR("[A-z]")).as_int() == 1);
+ CHECK(node.attribute_w(STR("[z-a]")).as_int() == 0);
+ CHECK(node.attribute_w(STR("[a-zA-Z]")).as_int() == 1);
+ CHECK(node.attribute_w(STR("[!A-Z]")).as_int() == 1);
+ CHECK(node.attribute_w(STR("[!A-Za-z]")).as_int() == 0);
}
TEST_XML(dom_node_wildcard_star, "<node cd='1'/>")
{
- xml_node node = doc.child("node");
+ xml_node node = doc.child(STR("node"));
- CHECK(node.attribute_w("*").as_int() == 1);
- CHECK(node.attribute_w("?d*").as_int() == 1);
- CHECK(node.attribute_w("?c*").as_int() == 0);
- CHECK(node.attribute_w("*?*c*").as_int() == 0);
- CHECK(node.attribute_w("*?*d*").as_int() == 1);
+ CHECK(node.attribute_w(STR("*")).as_int() == 1);
+ CHECK(node.attribute_w(STR("?d*")).as_int() == 1);
+ CHECK(node.attribute_w(STR("?c*")).as_int() == 0);
+ CHECK(node.attribute_w(STR("*?*c*")).as_int() == 0);
+ CHECK(node.attribute_w(STR("*?*d*")).as_int() == 1);
}
diff --git a/tests/test_header_guard.cpp b/tests/test_header_guard.cpp
new file mode 100644
index 0000000..3706cc9
--- /dev/null
+++ b/tests/test_header_guard.cpp
@@ -0,0 +1,3 @@
+// Tests header guards
+#include "../src/pugixml.hpp"
+#include "../src/pugixml.hpp"
diff --git a/tests/test_header_iosfwd_1.cpp b/tests/test_header_iosfwd_1.cpp
new file mode 100644
index 0000000..73e8527
--- /dev/null
+++ b/tests/test_header_iosfwd_1.cpp
@@ -0,0 +1,3 @@
+// Tests compatibility with iosfwd
+#include "../src/pugixml.hpp"
+#include <iosfwd>
diff --git a/tests/test_header_iosfwd_2.cpp b/tests/test_header_iosfwd_2.cpp
new file mode 100644
index 0000000..e472b9c
--- /dev/null
+++ b/tests/test_header_iosfwd_2.cpp
@@ -0,0 +1,3 @@
+// Tests compatibility with iosfwd
+#include <iosfwd>
+#include "../src/pugixml.hpp"
diff --git a/tests/test_header_iostream_1.cpp b/tests/test_header_iostream_1.cpp
new file mode 100644
index 0000000..2b359f9
--- /dev/null
+++ b/tests/test_header_iostream_1.cpp
@@ -0,0 +1,3 @@
+// Tests compatibility with iostream
+#include "../src/pugixml.hpp"
+#include <iostream>
diff --git a/tests/test_header_iostream_2.cpp b/tests/test_header_iostream_2.cpp
new file mode 100644
index 0000000..0b1b6b8
--- /dev/null
+++ b/tests/test_header_iostream_2.cpp
@@ -0,0 +1,3 @@
+// Tests compatibility with iostream
+#include <iostream>
+#include "../src/pugixml.hpp"
diff --git a/tests/test_header_string_1.cpp b/tests/test_header_string_1.cpp
new file mode 100644
index 0000000..9e9d33f
--- /dev/null
+++ b/tests/test_header_string_1.cpp
@@ -0,0 +1,3 @@
+// Tests compatibility with string
+#include "../src/pugixml.hpp"
+#include <string>
diff --git a/tests/test_header_string_2.cpp b/tests/test_header_string_2.cpp
new file mode 100644
index 0000000..01d72ac
--- /dev/null
+++ b/tests/test_header_string_2.cpp
@@ -0,0 +1,3 @@
+// Tests compatibility with string
+#include <string>
+#include "../src/pugixml.hpp"
diff --git a/tests/test_memory.cpp b/tests/test_memory.cpp
index 8706ed2..7ca87d6 100644
--- a/tests/test_memory.cpp
+++ b/tests/test_memory.cpp
@@ -2,13 +2,13 @@
namespace
{
- char buffer[8];
+ pugi::char_t buffer[8];
int allocate_count = 0;
int deallocate_count = 0;
void* allocate(size_t size)
{
- CHECK(size == 8);
+ CHECK(size == sizeof(pugi::char_t) * 8);
++allocate_count;
return buffer;
}
@@ -32,23 +32,23 @@ TEST(custom_memory_management)
{
// parse document
xml_document doc;
- CHECK(doc.load("<node/>"));
+ CHECK(doc.load(STR("<node />")));
CHECK(allocate_count == 1);
CHECK(deallocate_count == 0);
- CHECK_STRING(buffer, "<node\0>");
+ CHECK_STRING(buffer, STR("<node"));
// modify document
- doc.child("node").set_name("foobars");
+ doc.child(STR("node")).set_name(STR("foobars"));
CHECK(allocate_count == 2);
CHECK(deallocate_count == 0);
- CHECK_STRING(buffer, "foobars");
+ CHECK_STRING(buffer, STR("foobars"));
}
CHECK(allocate_count == 2);
CHECK(deallocate_count == 2);
- CHECK_STRING(buffer, "foobars");
+ CHECK_STRING(buffer, STR("foobars"));
// restore old functions
set_memory_management_functions(old_allocate, old_deallocate);
diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp
index fae3bb8..461578e 100644
--- a/tests/test_parse.cpp
+++ b/tests/test_parse.cpp
@@ -3,25 +3,25 @@
TEST(parse_pi_skip)
{
xml_document doc;
- CHECK(doc.load("<?pi?><?pi value?>", parse_minimal));
+ CHECK(doc.load(STR("<?pi?><?pi value?>"), parse_minimal));
CHECK(!doc.first_child());
}
TEST(parse_pi_parse)
{
xml_document doc;
- CHECK(doc.load("<?pi1?><?pi2 value?>", parse_minimal | parse_pi));
+ CHECK(doc.load(STR("<?pi1?><?pi2 value?>"), parse_minimal | parse_pi));
xml_node pi1 = doc.first_child();
xml_node pi2 = doc.last_child();
CHECK(pi1 != pi2);
CHECK(pi1.type() == node_pi);
- CHECK_STRING(pi1.name(), "pi1");
- CHECK_STRING(pi1.value(), "");
+ CHECK_STRING(pi1.name(), STR("pi1"));
+ CHECK_STRING(pi1.value(), STR(""));
CHECK(pi2.type() == node_pi);
- CHECK_STRING(pi2.name(), "pi2");
- CHECK_STRING(pi2.value(), "value");
+ CHECK_STRING(pi2.name(), STR("pi2"));
+ CHECK_STRING(pi2.value(), STR("value"));
}
TEST(parse_pi_error)
@@ -34,56 +34,69 @@ TEST(parse_pi_error)
{
unsigned int flags = flag_sets[i];
- CHECK(doc.load("<?", flags).status == status_bad_pi);
- CHECK(doc.load("<?#?>", flags).status == status_bad_pi);
- CHECK(doc.load("<?name", flags).status == status_bad_pi);
- CHECK(doc.load("<?name>", flags).status == status_bad_pi);
- CHECK(doc.load("<?name ?", flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<??"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?>"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?#?>"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name>"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name ?"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name?"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name? "), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name? "), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name "), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name "), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name "), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name value"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name value "), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?name value "), flags).status == status_bad_pi);
}
+
+ CHECK(doc.load(STR("<?xx#?>"), parse_minimal | parse_pi).status == status_bad_pi);
}
TEST(parse_comments_skip)
{
xml_document doc;
- CHECK(doc.load("<!----><!--value-->", parse_minimal));
+ CHECK(doc.load(STR("<!----><!--value-->"), parse_minimal));
CHECK(!doc.first_child());
}
TEST(parse_comments_parse)
{
xml_document doc;
- CHECK(doc.load("<!----><!--value-->", parse_minimal | parse_comments));
+ CHECK(doc.load(STR("<!----><!--value-->"), parse_minimal | parse_comments));
xml_node c1 = doc.first_child();
xml_node c2 = doc.last_child();
CHECK(c1 != c2);
CHECK(c1.type() == node_comment);
- CHECK_STRING(c1.name(), "");
- CHECK_STRING(c1.value(), "");
+ CHECK_STRING(c1.name(), STR(""));
+ CHECK_STRING(c1.value(), STR(""));
CHECK(c2.type() == node_comment);
- CHECK_STRING(c2.name(), "");
- CHECK_STRING(c2.value(), "value");
+ CHECK_STRING(c2.name(), STR(""));
+ CHECK_STRING(c2.value(), STR("value"));
}
TEST(parse_comments_parse_no_eol)
{
xml_document doc;
- CHECK(doc.load("<!--\r\rval1\rval2\r\nval3\nval4\r\r-->", parse_minimal | parse_comments));
+ CHECK(doc.load(STR("<!--\r\rval1\rval2\r\nval3\nval4\r\r-->"), parse_minimal | parse_comments));
xml_node c = doc.first_child();
CHECK(c.type() == node_comment);
- CHECK_STRING(c.value(), "\r\rval1\rval2\r\nval3\nval4\r\r");
+ CHECK_STRING(c.value(), STR("\r\rval1\rval2\r\nval3\nval4\r\r"));
}
TEST(parse_comments_parse_eol)
{
xml_document doc;
- CHECK(doc.load("<!--\r\rval1\rval2\r\nval3\nval4\r\r-->", parse_minimal | parse_comments | parse_eol));
+ CHECK(doc.load(STR("<!--\r\rval1\rval2\r\nval3\nval4\r\r-->"), parse_minimal | parse_comments | parse_eol));
xml_node c = doc.first_child();
CHECK(c.type() == node_comment);
- CHECK_STRING(c.value(), "\n\nval1\nval2\nval3\nval4\n\n");
+ CHECK_STRING(c.value(), STR("\n\nval1\nval2\nval3\nval4\n\n"));
}
TEST(parse_comments_error)
@@ -96,57 +109,57 @@ TEST(parse_comments_error)
{
unsigned int flags = flag_sets[i];
- CHECK(doc.load("<!-", flags).status == status_bad_comment);
- CHECK(doc.load("<!--", flags).status == status_bad_comment);
- CHECK(doc.load("<!--v", flags).status == status_bad_comment);
- CHECK(doc.load("<!-->", flags).status == status_bad_comment);
- CHECK(doc.load("<!--->", flags).status == status_bad_comment);
- CHECK(doc.load("<!-- <!-- --><!- -->", flags).status == status_bad_comment);
+ CHECK(doc.load(STR("<!-"), flags).status == status_bad_comment);
+ CHECK(doc.load(STR("<!--"), flags).status == status_bad_comment);
+ CHECK(doc.load(STR("<!--v"), flags).status == status_bad_comment);
+ CHECK(doc.load(STR("<!-->"), flags).status == status_bad_comment);
+ CHECK(doc.load(STR("<!--->"), flags).status == status_bad_comment);
+ CHECK(doc.load(STR("<!-- <!-- --><!- -->"), flags).status == status_bad_comment);
}
}
TEST(parse_cdata_skip)
{
xml_document doc;
- CHECK(doc.load("<![CDATA[]]><![CDATA[value]]>", parse_minimal));
+ CHECK(doc.load(STR("<![CDATA[]]><![CDATA[value]]>"), parse_minimal));
CHECK(!doc.first_child());
}
TEST(parse_cdata_parse)
{
xml_document doc;
- CHECK(doc.load("<![CDATA[]]><![CDATA[value]]>", parse_minimal | parse_cdata));
+ CHECK(doc.load(STR("<![CDATA[]]><![CDATA[value]]>"), parse_minimal | parse_cdata));
xml_node c1 = doc.first_child();
xml_node c2 = doc.last_child();
CHECK(c1 != c2);
CHECK(c1.type() == node_cdata);
- CHECK_STRING(c1.name(), "");
- CHECK_STRING(c1.value(), "");
+ CHECK_STRING(c1.name(), STR(""));
+ CHECK_STRING(c1.value(), STR(""));
CHECK(c2.type() == node_cdata);
- CHECK_STRING(c2.name(), "");
- CHECK_STRING(c2.value(), "value");
+ CHECK_STRING(c2.name(), STR(""));
+ CHECK_STRING(c2.value(), STR("value"));
}
TEST(parse_cdata_parse_no_eol)
{
xml_document doc;
- CHECK(doc.load("<![CDATA[\r\rval1\rval2\r\nval3\nval4\r\r]]>", parse_minimal | parse_cdata));
+ CHECK(doc.load(STR("<![CDATA[\r\rval1\rval2\r\nval3\nval4\r\r]]>"), parse_minimal | parse_cdata));
xml_node c = doc.first_child();
CHECK(c.type() == node_cdata);
- CHECK_STRING(c.value(), "\r\rval1\rval2\r\nval3\nval4\r\r");
+ CHECK_STRING(c.value(), STR("\r\rval1\rval2\r\nval3\nval4\r\r"));
}
TEST(parse_cdata_parse_eol)
{
xml_document doc;
- CHECK(doc.load("<![CDATA[\r\rval1\rval2\r\nval3\nval4\r\r]]>", parse_minimal | parse_cdata | parse_eol));
+ CHECK(doc.load(STR("<![CDATA[\r\rval1\rval2\r\nval3\nval4\r\r]]>"), parse_minimal | parse_cdata | parse_eol));
xml_node c = doc.first_child();
CHECK(c.type() == node_cdata);
- CHECK_STRING(c.value(), "\n\nval1\nval2\nval3\nval4\n\n");
+ CHECK_STRING(c.value(), STR("\n\nval1\nval2\nval3\nval4\n\n"));
}
TEST(parse_cdata_error)
@@ -159,28 +172,31 @@ TEST(parse_cdata_error)
{
unsigned int flags = flag_sets[i];
- CHECK(doc.load("<![", flags).status == status_bad_cdata);
- CHECK(doc.load("<![C", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CD", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CDA", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CDAT", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CDATA", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CDATA[", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CDATA[]", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CDATA[>", flags).status == status_bad_cdata);
- CHECK(doc.load("<![CDATA[ <![CDATA[]]><![CDATA ]]>", flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<!["), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![C"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CD"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDA"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDAT"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA["), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA[]"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA[data"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA[data]"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA[data]]"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA[>"), flags).status == status_bad_cdata);
+ CHECK(doc.load(STR("<![CDATA[ <![CDATA[]]><![CDATA ]]>"), flags).status == status_bad_cdata);
}
}
TEST(parse_ws_pcdata_skip)
{
xml_document doc;
- CHECK(doc.load(" ", parse_minimal));
+ CHECK(doc.load(STR(" "), parse_minimal));
CHECK(!doc.first_child());
- CHECK(doc.load("<root> <node> </node> </root>", parse_minimal));
+ CHECK(doc.load(STR("<root> <node> </node> </root>"), parse_minimal));
- xml_node root = doc.child("root");
+ xml_node root = doc.child(STR("root"));
CHECK(root.first_child() == root.last_child());
CHECK(!root.first_child().first_child());
@@ -189,9 +205,9 @@ TEST(parse_ws_pcdata_skip)
TEST(parse_ws_pcdata_parse)
{
xml_document doc;
- CHECK(doc.load("<root> <node> </node> </root>", parse_minimal | parse_ws_pcdata));
+ CHECK(doc.load(STR("<root> <node> </node> </root>"), parse_minimal | parse_ws_pcdata));
- xml_node root = doc.child("root");
+ xml_node root = doc.child(STR("root"));
xml_node c1 = root.first_child();
xml_node c2 = c1.next_sibling();
@@ -200,35 +216,35 @@ TEST(parse_ws_pcdata_parse)
CHECK(c3 == root.last_child());
CHECK(c1.type() == node_pcdata);
- CHECK_STRING(c1.value(), " ");
+ CHECK_STRING(c1.value(), STR(" "));
CHECK(c3.type() == node_pcdata);
- CHECK_STRING(c3.value(), " ");
+ CHECK_STRING(c3.value(), STR(" "));
CHECK(c2.first_child() == c2.last_child());
CHECK(c2.first_child().type() == node_pcdata);
- CHECK_STRING(c2.first_child().value(), " ");
+ CHECK_STRING(c2.first_child().value(), STR(" "));
}
TEST(parse_pcdata_no_eol)
{
xml_document doc;
- CHECK(doc.load("<root>\r\rval1\rval2\r\nval3\nval4\r\r</root>", parse_minimal));
+ CHECK(doc.load(STR("<root>\r\rval1\rval2\r\nval3\nval4\r\r</root>"), parse_minimal));
- CHECK_STRING(doc.child_value("root"), "\r\rval1\rval2\r\nval3\nval4\r\r");
+ CHECK_STRING(doc.child_value(STR("root")), STR("\r\rval1\rval2\r\nval3\nval4\r\r"));
}
TEST(parse_pcdata_eol)
{
xml_document doc;
- CHECK(doc.load("<root>\r\rval1\rval2\r\nval3\nval4\r\r</root>", parse_minimal | parse_eol));
+ CHECK(doc.load(STR("<root>\r\rval1\rval2\r\nval3\nval4\r\r</root>"), parse_minimal | parse_eol));
- CHECK_STRING(doc.child_value("root"), "\n\nval1\nval2\nval3\nval4\n\n");
+ CHECK_STRING(doc.child_value(STR("root")), STR("\n\nval1\nval2\nval3\nval4\n\n"));
}
TEST(parse_pcdata_skip_ext)
{
xml_document doc;
- CHECK(doc.load("pre<root/>post", parse_minimal));
+ CHECK(doc.load(STR("pre<root/>post"), parse_minimal));
CHECK(doc.first_child() == doc.last_child());
CHECK(doc.first_child().type() == node_element);
}
@@ -236,99 +252,109 @@ TEST(parse_pcdata_skip_ext)
TEST(parse_pcdata_error)
{
xml_document doc;
- CHECK(doc.load("<root>pcdata", parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("<root>pcdata"), parse_minimal).status == status_end_element_mismatch);
}
TEST(parse_escapes_skip)
{
xml_document doc;
- CHECK(doc.load("<node id='&lt;&gt;&amp;&apos;&quot;'>&lt;&gt;&amp;&apos;&quot;</node>", parse_minimal));
- CHECK_STRING(doc.child("node").attribute("id").value(), "&lt;&gt;&amp;&apos;&quot;");
+ CHECK(doc.load(STR("<node id='&lt;&gt;&amp;&apos;&quot;'>&lt;&gt;&amp;&apos;&quot;</node>"), parse_minimal));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("&lt;&gt;&amp;&apos;&quot;"));
}
TEST(parse_escapes_parse)
{
xml_document doc;
- CHECK(doc.load("<node id='&lt;&gt;&amp;&apos;&quot;'>&lt;&gt;&amp;&apos;&quot;</node>", parse_minimal | parse_escapes));
- CHECK_STRING(doc.child_value("node"), "<>&'\"");
- CHECK_STRING(doc.child("node").attribute("id").value(), "<>&'\"");
+ CHECK(doc.load(STR("<node id='&lt;&gt;&amp;&apos;&quot;'>&lt;&gt;&amp;&apos;&quot;</node>"), parse_minimal | parse_escapes));
+ CHECK_STRING(doc.child_value(STR("node")), STR("<>&'\""));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("<>&'\""));
}
TEST(parse_escapes_code)
{
xml_document doc;
- CHECK(doc.load("<node>&#1;&#32;&#x20;</node>", parse_minimal | parse_escapes));
- CHECK_STRING(doc.child_value("node"), "\01 ");
+ CHECK(doc.load(STR("<node>&#1;&#32;&#x20;</node>"), parse_minimal | parse_escapes));
+ CHECK_STRING(doc.child_value(STR("node")), STR("\01 "));
}
TEST(parse_escapes_unicode)
{
xml_document doc;
- CHECK(doc.load("<node>&#x03B3;&#x03b3;</node>", parse_minimal | parse_escapes));
- CHECK_STRING(doc.child_value("node"), "\xce\xb3\xce\xb3");
+ CHECK(doc.load(STR("<node>&#x03B3;&#x03b3;&#x24B62;</node>"), parse_minimal | parse_escapes));
+
+#ifdef PUGIXML_WCHAR_MODE
+ const pugi::char_t* v = doc.child_value(STR("node"));
+
+ unsigned int v2 = v[2];
+ size_t wcharsize = sizeof(wchar_t);
+
+ CHECK(v[0] == 0x3b3 && v[1] == 0x3b3 && (wcharsize == 2 ? v[2] == 0xd852 && v[3] == 0xdf62 : v2 == 0x24b62));
+#else
+ CHECK_STRING(doc.child_value(STR("node")), "\xce\xb3\xce\xb3\xf0\xa4\xad\xa2");
+#endif
}
TEST(parse_escapes_error)
{
xml_document doc;
- CHECK(doc.load("<node>&#x03g;&#ab;&quot</node>", parse_minimal | parse_escapes));
- CHECK_STRING(doc.child_value("node"), "&#x03g;&#ab;&quot");
+ CHECK(doc.load(STR("<node>&#x03g;&#ab;&quot</node>"), parse_minimal | parse_escapes));
+ CHECK_STRING(doc.child_value(STR("node")), STR("&#x03g;&#ab;&quot"));
- CHECK(!doc.load("<node id='&#x12"));
- CHECK(!doc.load("<node id='&g"));
- CHECK(!doc.load("<node id='&gt"));
- CHECK(!doc.load("<node id='&l"));
- CHECK(!doc.load("<node id='&lt"));
- CHECK(!doc.load("<node id='&a"));
- CHECK(!doc.load("<node id='&amp"));
- CHECK(!doc.load("<node id='&apos"));
+ CHECK(!doc.load(STR("<node id='&#x12")));
+ CHECK(!doc.load(STR("<node id='&g")));
+ CHECK(!doc.load(STR("<node id='&gt")));
+ CHECK(!doc.load(STR("<node id='&l")));
+ CHECK(!doc.load(STR("<node id='&lt")));
+ CHECK(!doc.load(STR("<node id='&a")));
+ CHECK(!doc.load(STR("<node id='&amp")));
+ CHECK(!doc.load(STR("<node id='&apos")));
}
TEST(parse_attribute_spaces)
{
xml_document doc;
- CHECK(doc.load("<node id1='v1' id2 ='v2' id3= 'v3' id4 = 'v4' id5 \n\r\t = \r\t\n 'v5' />", parse_minimal));
- CHECK_STRING(doc.child("node").attribute("id1").value(), "v1");
- CHECK_STRING(doc.child("node").attribute("id2").value(), "v2");
- CHECK_STRING(doc.child("node").attribute("id3").value(), "v3");
- CHECK_STRING(doc.child("node").attribute("id4").value(), "v4");
- CHECK_STRING(doc.child("node").attribute("id5").value(), "v5");
+ CHECK(doc.load(STR("<node id1='v1' id2 ='v2' id3= 'v3' id4 = 'v4' id5 \n\r\t = \r\t\n 'v5' />"), parse_minimal));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1"));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2"));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id3")).value(), STR("v3"));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id4")).value(), STR("v4"));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id5")).value(), STR("v5"));
}
TEST(parse_attribute_quot)
{
xml_document doc;
- CHECK(doc.load("<node id1='v1' id2=\"v2\"/>", parse_minimal));
- CHECK_STRING(doc.child("node").attribute("id1").value(), "v1");
- CHECK_STRING(doc.child("node").attribute("id2").value(), "v2");
+ CHECK(doc.load(STR("<node id1='v1' id2=\"v2\"/>"), parse_minimal));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1"));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2"));
}
TEST(parse_attribute_no_eol_no_wconv)
{
xml_document doc;
- CHECK(doc.load("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>", parse_minimal));
- CHECK_STRING(doc.child("node").attribute("id").value(), " \t\r\rval1 \rval2\r\nval3\nval4\r\r");
+ CHECK(doc.load(STR("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>"), parse_minimal));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\r\rval1 \rval2\r\nval3\nval4\r\r"));
}
TEST(parse_attribute_eol_no_wconv)
{
xml_document doc;
- CHECK(doc.load("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>", parse_minimal | parse_eol));
- CHECK_STRING(doc.child("node").attribute("id").value(), " \t\n\nval1 \nval2\nval3\nval4\n\n");
+ CHECK(doc.load(STR("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>"), parse_minimal | parse_eol));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\n\nval1 \nval2\nval3\nval4\n\n"));
}
TEST(parse_attribute_no_eol_wconv)
{
xml_document doc;
- CHECK(doc.load("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>", parse_minimal | parse_wconv_attribute));
- CHECK_STRING(doc.child("node").attribute("id").value(), " val1 val2 val3 val4 ");
+ CHECK(doc.load(STR("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>"), parse_minimal | parse_wconv_attribute));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 "));
}
TEST(parse_attribute_eol_wconv)
{
xml_document doc;
- CHECK(doc.load("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>", parse_minimal | parse_eol | parse_wconv_attribute));
- CHECK_STRING(doc.child("node").attribute("id").value(), " val1 val2 val3 val4 ");
+ CHECK(doc.load(STR("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>"), parse_minimal | parse_eol | parse_wconv_attribute));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 "));
}
TEST(parse_attribute_wnorm)
@@ -339,8 +365,8 @@ TEST(parse_attribute_wnorm)
for (int wconv = 0; wconv < 2; ++wconv)
{
unsigned int flags = parse_minimal | parse_wnorm_attribute | (eol ? parse_eol : 0) | (wconv ? parse_wconv_attribute : 0);
- CHECK(doc.load("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>", flags));
- CHECK_STRING(doc.child("node").attribute("id").value(), "val1 val2 val3 val4");
+ CHECK(doc.load(STR("<node id=' \t\r\rval1 \rval2\r\nval3\nval4\r\r'/>"), flags));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("val1 val2 val3 val4"));
}
}
@@ -360,80 +386,111 @@ TEST(parse_attribute_variations)
flags |= (wconv ? parse_wconv_attribute : 0);
flags |= (escapes ? parse_escapes : 0);
- CHECK(doc.load("<node id='1'/>", flags));
- CHECK_STRING(doc.child("node").attribute("id").value(), "1");
+ CHECK(doc.load(STR("<node id='1'/>"), flags));
+ CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("1"));
}
}
TEST(parse_attribute_error)
{
xml_document doc;
- CHECK(doc.load("<node id/>", parse_minimal).status == status_bad_attribute);
- CHECK(doc.load("<node id=/>", parse_minimal).status == status_bad_attribute);
- CHECK(doc.load("<node id='/>", parse_minimal).status == status_bad_attribute);
- CHECK(doc.load("<node id=\"/>", parse_minimal).status == status_bad_attribute);
- CHECK(doc.load("<node id=\"'/>", parse_minimal).status == status_bad_attribute);
- CHECK(doc.load("<node id='\"/>", parse_minimal).status == status_bad_attribute);
- CHECK(doc.load("<node id='\"/>", parse_minimal).status == status_bad_attribute);
- CHECK(doc.load("<node #/>", parse_minimal).status == status_bad_start_element);
- CHECK(doc.load("<node#/>", parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node id"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id "), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id "), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id "), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id/"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id?/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id=/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id='/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id=\"/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id=\"'/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id='\"/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node id='\"/>"), parse_minimal).status == status_bad_attribute);
+ CHECK(doc.load(STR("<node #/>"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node#/>"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node id1='1'id2='2'/>"), parse_minimal).status == status_bad_attribute);
}
TEST(parse_tag_single)
{
xml_document doc;
- CHECK(doc.load("<node/><node /><node\n/>", parse_minimal));
- CHECK_NODE(doc, "<node /><node /><node />");
+ CHECK(doc.load(STR("<node/><node /><node\n/>"), parse_minimal));
+ CHECK_NODE(doc, STR("<node /><node /><node />"));
}
TEST(parse_tag_hierarchy)
{
xml_document doc;
- CHECK(doc.load("<node><n1><n2/></n1><n3><n4><n5></n5></n4></n3 \r\n></node>", parse_minimal));
- CHECK_NODE(doc, "<node><n1><n2 /></n1><n3><n4><n5 /></n4></n3></node>");
+ CHECK(doc.load(STR("<node><n1><n2/></n1><n3><n4><n5></n5></n4></n3 \r\n></node>"), parse_minimal));
+ CHECK_NODE(doc, STR("<node><n1><n2 /></n1><n3><n4><n5 /></n4></n3></node>"));
}
TEST(parse_tag_error)
{
xml_document doc;
- CHECK(doc.load("<", parse_minimal).status == status_unrecognized_tag);
- CHECK(doc.load("<!", parse_minimal).status == status_unrecognized_tag);
- CHECK(doc.load("<!D", parse_minimal).status == status_unrecognized_tag);
- CHECK(doc.load("<#", parse_minimal).status == status_unrecognized_tag);
- CHECK(doc.load("<node#", parse_minimal).status == status_bad_start_element);
- CHECK(doc.load("<node", parse_minimal).status == status_bad_start_element);
- CHECK(doc.load("<node/", parse_minimal).status == status_bad_start_element);
- CHECK(doc.load("<node/ >", parse_minimal).status == status_bad_start_element);
- CHECK(doc.load("</ node>", parse_minimal).status == status_end_element_mismatch);
- CHECK(doc.load("</node", parse_minimal).status == status_end_element_mismatch);
- CHECK(doc.load("</node ", parse_minimal).status == status_end_element_mismatch);
- CHECK(doc.load("<node></ node>", parse_minimal).status == status_end_element_mismatch);
- CHECK(doc.load("<node></node", parse_minimal).status == status_bad_end_element);
- CHECK(doc.load("<node></node ", parse_minimal).status == status_bad_end_element);
- CHECK(doc.load("<node></nodes>", parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("<"), parse_minimal).status == status_unrecognized_tag);
+ CHECK(doc.load(STR("<!"), parse_minimal).status == status_unrecognized_tag);
+ CHECK(doc.load(STR("<!D"), parse_minimal).status == status_unrecognized_tag);
+ CHECK(doc.load(STR("<#"), parse_minimal).status == status_unrecognized_tag);
+ CHECK(doc.load(STR("<node#"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node/"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node /"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node / "), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node / >"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("<node/ >"), parse_minimal).status == status_bad_start_element);
+ CHECK(doc.load(STR("</ node>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("</node"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("</node "), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("<node></ node>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("<node></node"), parse_minimal).status == status_bad_end_element);
+ CHECK(doc.load(STR("<node></node "), parse_minimal).status == status_bad_end_element);
+ CHECK(doc.load(STR("<node></nodes>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("<node>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("<node/><"), parse_minimal).status == status_unrecognized_tag);
+ CHECK(doc.load(STR("<node attr='value'>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("</></node>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("</node>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("</>"), parse_minimal).status == status_end_element_mismatch);
+ CHECK(doc.load(STR("<node></node v>"), parse_minimal).status == status_bad_end_element);
+}
+
+TEST(parse_declaration_cases)
+{
+ xml_document doc;
+ CHECK(doc.load(STR("<?xml?><?xmL?><?xMl?><?xML?><?Xml?><?XmL?><?XMl?><?XML?>"), parse_minimal | parse_pi));
+ CHECK(!doc.first_child());
+}
+
+TEST(parse_declaration_attr_cases)
+{
+ xml_document doc;
+ CHECK(doc.load(STR("<?xml ?><?xmL ?><?xMl ?><?xML ?><?Xml ?><?XmL ?><?XMl ?><?XML ?>"), parse_minimal | parse_pi));
+ CHECK(!doc.first_child());
}
TEST(parse_declaration_skip)
{
xml_document doc;
- CHECK(doc.load("<?xml?><?xml version='1.0'?>", parse_minimal));
+ CHECK(doc.load(STR("<?xml?><?xml version='1.0'?>"), parse_minimal));
CHECK(!doc.first_child());
}
TEST(parse_declaration_parse)
{
xml_document doc;
- CHECK(doc.load("<?xml?><?xml version='1.0'?>", parse_minimal | parse_declaration));
+ CHECK(doc.load(STR("<?xml?><?xml version='1.0'?>"), parse_minimal | parse_declaration));
xml_node d1 = doc.first_child();
xml_node d2 = doc.last_child();
CHECK(d1 != d2);
CHECK(d1.type() == node_declaration);
- CHECK_STRING(d1.name(), "xml");
+ CHECK_STRING(d1.name(), STR("xml"));
CHECK(d2.type() == node_declaration);
- CHECK_STRING(d2.name(), "xml");
- CHECK_STRING(d2.attribute("version").value(), "1.0");
+ CHECK_STRING(d2.name(), STR("xml"));
+ CHECK_STRING(d2.attribute(STR("version")).value(), STR("1.0"));
}
TEST(parse_declaration_error)
@@ -446,38 +503,46 @@ TEST(parse_declaration_error)
{
unsigned int flags = flag_sets[i];
- CHECK(doc.load("<?xml", flags).status == status_bad_pi);
- CHECK(doc.load("<?xml?", flags).status == status_bad_pi);
- CHECK(doc.load("<?xml>", flags).status == status_bad_pi);
- CHECK(doc.load("<?xml version='1>", flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?xml"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?xml?"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?xml>"), flags).status == status_bad_pi);
+ CHECK(doc.load(STR("<?xml version='1>"), flags).status == status_bad_pi);
}
- CHECK(doc.load("<?xml version='1?>", parse_minimal | parse_declaration).status == status_bad_attribute);
+ CHECK(doc.load(STR("<?xml version='1?>"), parse_minimal | parse_declaration).status == status_bad_attribute);
}
TEST(parse_doctype_skip)
{
xml_document doc;
- CHECK(doc.load("<!DOCTYPE doc>") && !doc.first_child());
- CHECK(doc.load("<!DOCTYPE doc SYSTEM 'foo'>") && !doc.first_child());
- CHECK(doc.load("<!DOCTYPE doc SYSTEM \"foo\">") && !doc.first_child());
- CHECK(doc.load("<!DOCTYPE doc PUBLIC \"foo\" 'bar'>") && !doc.first_child());
- CHECK(doc.load("<!DOCTYPE doc PUBLIC \"foo'\">") && !doc.first_child());
- CHECK(doc.load("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]>") && !doc.first_child());
+ CHECK(doc.load(STR("<!DOCTYPE doc>")) && !doc.first_child());
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo'>")) && !doc.first_child());
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM \"foo\">")) && !doc.first_child());
+ CHECK(doc.load(STR("<!DOCTYPE doc PUBLIC \"foo\" 'bar'>")) && !doc.first_child());
+ CHECK(doc.load(STR("<!DOCTYPE doc PUBLIC \"foo'\">")) && !doc.first_child());
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]>")) && !doc.first_child());
- CHECK(doc.load("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]><node/>"));
- CHECK_NODE(doc, "<node />");
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]><node/>")));
+ CHECK_NODE(doc, STR("<node />"));
}
TEST(parse_doctype_error)
{
xml_document doc;
- CHECK(doc.load("<!DOCTYPE").status == status_bad_doctype);
- CHECK(doc.load("<!DOCTYPE doc").status == status_bad_doctype);
- CHECK(doc.load("<!DOCTYPE doc SYSTEM 'foo").status == status_bad_doctype);
- CHECK(doc.load("<!DOCTYPE doc SYSTEM \"foo").status == status_bad_doctype);
- CHECK(doc.load("<!DOCTYPE doc PUBLIC \"foo\" 'bar").status == status_bad_doctype);
- CHECK(doc.load("<!DOCTYPE doc PUBLIC \"foo'\"").status == status_bad_doctype);
- CHECK(doc.load("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY").status == status_bad_doctype);
- CHECK(doc.load("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>").status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM \"foo")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc PUBLIC \"foo\" 'bar")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc PUBLIC \"foo'\"")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]")).status == status_bad_doctype);
+ CHECK(doc.load(STR("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>] ")).status == status_bad_doctype);
+}
+
+TEST(parse_empty)
+{
+ xml_document doc;
+ CHECK(doc.load(STR("")) && !doc.first_child());
}
diff --git a/tests/test_unicode.cpp b/tests/test_unicode.cpp
index 61e23aa..ea2494b 100644
--- a/tests/test_unicode.cpp
+++ b/tests/test_unicode.cpp
@@ -1,39 +1,80 @@
+#ifndef PUGIXML_NO_STL
+
#include "common.hpp"
-// letters taken from http://www.utf8-chartable.de/
+#include <string>
-#ifdef __DMC__
-#define U_LITERALS // DMC does not understand \x01234 (it parses first three digits), but understands \u01234
-#endif
+// letters taken from http://www.utf8-chartable.de/
-inline wchar_t wchar_cast(unsigned int value)
+TEST(as_wide_empty)
{
- return static_cast<wchar_t>(value); // to avoid C4310 on MSVC
+ CHECK(as_wide("") == L"");
}
-#ifndef PUGIXML_NO_STL
-TEST(as_utf16)
+TEST(as_wide_valid_basic)
{
// valid 1-byte, 2-byte and 3-byte inputs
#ifdef U_LITERALS
- CHECK(as_utf16("?\xd0\x80\xe2\x80\xbd") == L"?\u0400\u203D");
+ CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\u0400\u203D");
#else
- CHECK(as_utf16("?\xd0\x80\xe2\x80\xbd") == L"?\x0400\x203D");
+ CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\x0400\x203D");
#endif
+}
- // invalid 1-byte input
- CHECK(as_utf16("\xb0") == L" ");
-
+TEST(as_wide_valid_astral)
+{
// valid 4-byte input
- std::wstring b4 = as_utf16("\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
- CHECK(b4.size() == 3 && b4[0] == wchar_cast(0x97624) && b4[1] == L' ' && b4[2] == wchar_cast(0x1003ff));
+ std::wstring b4 = as_wide("\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
+
+ size_t wcharsize = sizeof(wchar_t);
+
+ if (wcharsize == 4)
+ {
+ CHECK(b4.size() == 3 && b4[0] == wchar_cast(0x97624) && b4[1] == L' ' && b4[2] == wchar_cast(0x1003ff));
+ }
+ else
+ {
+ CHECK(b4.size() == 5 && b4[0] == 0xda1d && b4[1] == 0xde24 && b4[2] == L' ' && b4[3] == 0xdbc0 && b4[4] == 0xdfff);
+ }
+}
+
+TEST(as_wide_invalid)
+{
+ // invalid 1-byte input
+ CHECK(as_wide("a\xb0") == L"a");
+ CHECK(as_wide("a\xb0_") == L"a_");
+
+ // invalid 2-byte input
+ CHECK(as_wide("a\xc0") == L"a");
+ CHECK(as_wide("a\xd0") == L"a");
+ CHECK(as_wide("a\xc0_") == L"a_");
+ CHECK(as_wide("a\xd0_") == L"a_");
+
+ // invalid 3-byte input
+ CHECK(as_wide("a\xe2\x80") == L"a");
+ CHECK(as_wide("a\xe2") == L"a");
+ CHECK(as_wide("a\xe2\x80_") == L"a_");
+ CHECK(as_wide("a\xe2_") == L"a_");
+
+ // invalid 4-byte input
+ CHECK(as_wide("a\xf2\x97\x98") == L"a");
+ CHECK(as_wide("a\xf2\x97") == L"a");
+ CHECK(as_wide("a\xf2") == L"a");
+ CHECK(as_wide("a\xf2\x97\x98_") == L"a_");
+ CHECK(as_wide("a\xf2\x97_") == L"a_");
+ CHECK(as_wide("a\xf2_") == L"a_");
// invalid 5-byte input
- std::wstring b5 = as_utf16("\xf8\nbcd");
- CHECK(b5 == L" \nbcd");
+ std::wstring b5 = as_wide("\xf8\nbcd");
+ CHECK(b5 == L"\nbcd");
+}
+
+TEST(as_utf8_empty)
+{
+ CHECK(as_utf8(L"") == "");
}
-TEST(as_utf8)
+TEST(as_utf8_valid_basic)
{
// valid 1-byte, 2-byte and 3-byte outputs
#ifdef U_LITERALS
@@ -41,16 +82,56 @@ TEST(as_utf8)
#else
CHECK(as_utf8(L"?\x0400\x203D") == "?\xd0\x80\xe2\x80\xbd");
#endif
-
+}
+
+TEST(as_utf8_valid_astral)
+{
// valid 4-byte output
-#if 0
- // requires 4-byte wchar_t :(
- CHECK(as_utf8(L"\x97624 \x1003ff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
-#endif
+ size_t wcharsize = sizeof(wchar_t);
+
+ if (wcharsize == 4)
+ {
+ std::wstring s;
+ s.resize(3);
+ s[0] = wchar_cast(0x97624);
+ s[1] = ' ';
+ s[2] = wchar_cast(0x1003ff);
+
+ CHECK(as_utf8(s.c_str()) == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
+ }
+ else
+ {
+ #ifdef U_LITERALS
+ CHECK(as_utf8(L"\uda1d\ude24 \udbc0\udfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
+ #else
+ CHECK(as_utf8(L"\xda1d\xde24 \xdbc0\xdfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
+ #endif
+ }
}
-#endif
-TEST_XML(parse_bom_utf8, "\xef\xbb\xbf<node/>")
+TEST(as_utf8_invalid)
{
- CHECK_NODE(doc, "<node />");
+ size_t wcharsize = sizeof(wchar_t);
+
+ if (wcharsize == 2)
+ {
+ // check non-terminated degenerate handling
+ #ifdef U_LITERALS
+ CHECK(as_utf8(L"a\uda1d") == "a");
+ CHECK(as_utf8(L"a\uda1d_") == "a_");
+ #else
+ CHECK(as_utf8(L"a\xda1d") == "a");
+ CHECK(as_utf8(L"a\xda1d_") == "a_");
+ #endif
+
+ // check incorrect leading code
+ #ifdef U_LITERALS
+ CHECK(as_utf8(L"a\ude24") == "a");
+ CHECK(as_utf8(L"a\ude24_") == "a_");
+ #else
+ CHECK(as_utf8(L"a\xde24") == "a");
+ CHECK(as_utf8(L"a\xde24_") == "a_");
+ #endif
+ }
}
+#endif
diff --git a/tests/test_write.cpp b/tests/test_write.cpp
index 8981a39..c94ab89 100644
--- a/tests/test_write.cpp
+++ b/tests/test_write.cpp
@@ -1,95 +1,309 @@
#include "common.hpp"
+#include "writer_string.hpp"
+
#include <string>
#include <sstream>
TEST_XML(write_simple, "<node attr='1'><child>text</child></node>")
{
- CHECK_NODE_EX(doc, "<node attr=\"1\">\n<child>text</child>\n</node>\n", "", 0);
+ CHECK_NODE_EX(doc, STR("<node attr=\"1\">\n<child>text</child>\n</node>\n"), STR(""), 0);
}
TEST_XML(write_raw, "<node attr='1'><child>text</child></node>")
{
- CHECK_NODE_EX(doc, "<node attr=\"1\"><child>text</child></node>", "", format_raw);
+ CHECK_NODE_EX(doc, STR("<node attr=\"1\"><child>text</child></node>"), STR(""), format_raw);
}
TEST_XML(write_indent, "<node attr='1'><child><sub>text</sub></child></node>")
{
- CHECK_NODE_EX(doc, "<node attr=\"1\">\n\t<child>\n\t\t<sub>text</sub>\n\t</child>\n</node>\n", "\t", format_indent);
+ CHECK_NODE_EX(doc, STR("<node attr=\"1\">\n\t<child>\n\t\t<sub>text</sub>\n\t</child>\n</node>\n"), STR("\t"), format_indent);
}
TEST_XML(write_pcdata, "<node attr='1'><child><sub/>text</child></node>")
{
- CHECK_NODE_EX(doc, "<node attr=\"1\">\n\t<child>\n\t\t<sub />\n\t\ttext\n\t</child>\n</node>\n", "\t", format_indent);
+ CHECK_NODE_EX(doc, STR("<node attr=\"1\">\n\t<child>\n\t\t<sub />\n\t\ttext\n\t</child>\n</node>\n"), STR("\t"), format_indent);
}
TEST_XML(write_cdata, "<![CDATA[value]]>")
{
- CHECK_NODE(doc, "<![CDATA[value]]>");
- CHECK_NODE_EX(doc, "<![CDATA[value]]>\n", "", 0);
+ CHECK_NODE(doc, STR("<![CDATA[value]]>"));
+ CHECK_NODE_EX(doc, STR("<![CDATA[value]]>\n"), STR(""), 0);
}
TEST_XML_FLAGS(write_comment, "<!--text-->", parse_default | parse_comments)
{
- CHECK_NODE(doc, "<!--text-->");
- CHECK_NODE_EX(doc, "<!--text-->\n", "", 0);
+ CHECK_NODE(doc, STR("<!--text-->"));
+ CHECK_NODE_EX(doc, STR("<!--text-->\n"), STR(""), 0);
}
TEST_XML_FLAGS(write_pi, "<?name value?>", parse_default | parse_pi)
{
- CHECK_NODE(doc, "<?name value?>");
- CHECK_NODE_EX(doc, "<?name value?>\n", "", 0);
+ CHECK_NODE(doc, STR("<?name value?>"));
+ CHECK_NODE_EX(doc, STR("<?name value?>\n"), STR(""), 0);
}
TEST_XML_FLAGS(write_declaration, "<?xml version='2.0'?>", parse_default | parse_declaration)
{
- CHECK_NODE(doc, "<?xml version=\"2.0\"?>");
- CHECK_NODE_EX(doc, "<?xml version=\"2.0\"?>\n", "", 0);
+ CHECK_NODE(doc, STR("<?xml version=\"2.0\"?>"));
+ CHECK_NODE_EX(doc, STR("<?xml version=\"2.0\"?>\n"), STR(""), 0);
}
TEST_XML(write_escape, "<node attr=''>text</node>")
{
- doc.child("node").attribute("attr") = "<>'\"&\x04\r\n\t";
- doc.child("node").first_child().set_value("<>'\"&\x04\r\n\t");
+ doc.child(STR("node")).attribute(STR("attr")) = STR("<>'\"&\x04\r\n\t");
+ doc.child(STR("node")).first_child().set_value(STR("<>'\"&\x04\r\n\t"));
+
+ CHECK_NODE(doc, STR("<node attr=\"&lt;&gt;'&quot;&amp;&#04;&#13;&#10;\t\">&lt;&gt;'\"&amp;&#04;\r\n\t</node>"));
+}
- CHECK_NODE(doc, "<node attr=\"&lt;&gt;'&quot;&amp;&#4;&#13;&#10;\t\">&lt;&gt;'\"&amp;&#4;\r\n\t</node>");
+TEST_XML(write_escape_unicode, "<node attr='&#x3c00;'/>")
+{
+#ifdef PUGIXML_WCHAR_MODE
+ #ifdef U_LITERALS
+ CHECK_NODE(doc, STR("<node attr=\"\u3c00\" />"));
+ #else
+ CHECK_NODE(doc, STR("<node attr=\"\x3c00\" />"));
+ #endif
+#else
+ CHECK_NODE(doc, STR("<node attr=\"\xe3\xb0\x80\" />"));
+#endif
}
struct test_writer: xml_writer
{
- std::string contents;
+ std::basic_string<pugi::char_t> contents;
virtual void write(const void* data, size_t size)
{
- contents += std::string(static_cast<const char*>(data), static_cast<const char*>(data) + size);
+ CHECK(size % sizeof(pugi::char_t) == 0);
+ contents += std::basic_string<pugi::char_t>(static_cast<const pugi::char_t*>(data), static_cast<const pugi::char_t*>(data) + size / sizeof(pugi::char_t));
}
};
TEST_XML(write_print_writer, "<node/>")
{
test_writer writer;
- doc.print(writer);
+ doc.print(writer, STR(""), format_default, get_native_encoding());
- CHECK(writer.contents == "<node />\n");
+ CHECK(writer.contents == STR("<node />\n"));
}
#ifndef PUGIXML_NO_STL
TEST_XML(write_print_stream, "<node/>")
{
std::ostringstream oss;
- doc.print(oss);
+ doc.print(oss, STR(""), format_default, encoding_utf8);
CHECK(oss.str() == "<node />\n");
}
+
+TEST_XML(write_print_stream_encode, "<n/>")
+{
+ std::ostringstream oss;
+ doc.print(oss, STR(""), format_default, encoding_utf16_be);
+
+ CHECK(oss.str() == std::string("\x00<\x00n\x00 \x00/\x00>\x00\n", 12));
+}
+
+TEST_XML(write_print_stream_wide, "<node/>")
+{
+ std::basic_ostringstream<wchar_t> oss;
+ doc.print(oss, STR(""), format_default, encoding_utf8);
+
+ CHECK(oss.str() == L"<node />\n");
+}
#endif
TEST_XML(write_huge_chunk, "<node/>")
{
- std::string name(10000, 'n');
- doc.child("node").set_name(name.c_str());
+ std::basic_string<pugi::char_t> name(10000, STR('n'));
+ doc.child(STR("node")).set_name(name.c_str());
test_writer writer;
- doc.print(writer);
+ doc.print(writer, STR(""), format_default, get_native_encoding());
- CHECK(writer.contents == "<" + name + " />\n");
+ CHECK(writer.contents == STR("<") + name + STR(" />\n"));
}
+
+TEST(write_encodings)
+{
+ static char s_utf8[] = "<\x54\xC2\xA2\xE2\x82\xAC\xF0\xA4\xAD\xA2/>";
+
+ xml_document doc;
+ CHECK(doc.load_buffer(s_utf8, sizeof(s_utf8), parse_default, encoding_utf8));
+
+ CHECK(write_narrow(doc, format_default, encoding_utf8) == "<\x54\xC2\xA2\xE2\x82\xAC\xF0\xA4\xAD\xA2 />\n");
+
+ CHECK(test_write_narrow(doc, format_default, encoding_utf32_le, "<\x00\x00\x00\x54\x00\x00\x00\xA2\x00\x00\x00\xAC\x20\x00\x00\x62\x4B\x02\x00 \x00\x00\x00/\x00\x00\x00>\x00\x00\x00\n\x00\x00\x00", 36));
+ CHECK(test_write_narrow(doc, format_default, encoding_utf32_be, "\x00\x00\x00<\x00\x00\x00\x54\x00\x00\x00\xA2\x00\x00\x20\xAC\x00\x02\x4B\x62\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>\x00\x00\x00\n", 36));
+ CHECK(write_narrow(doc, format_default, encoding_utf32) == write_narrow(doc, format_default, is_little_endian() ? encoding_utf32_le : encoding_utf32_be));
+
+ CHECK(test_write_narrow(doc, format_default, encoding_utf16_le, "<\x00\x54\x00\xA2\x00\xAC\x20\x52\xd8\x62\xdf \x00/\x00>\x00\n\x00", 20));
+ CHECK(test_write_narrow(doc, format_default, encoding_utf16_be, "\x00<\x00\x54\x00\xA2\x20\xAC\xd8\x52\xdf\x62\x00 \x00/\x00>\x00\n", 20));
+ CHECK(write_narrow(doc, format_default, encoding_utf16) == write_narrow(doc, format_default, is_little_endian() ? encoding_utf16_le : encoding_utf16_be));
+
+ size_t wcharsize = sizeof(wchar_t);
+ std::wstring v = write_wide(doc, format_default, encoding_wchar);
+
+ if (wcharsize == 4)
+ {
+ CHECK(v.size() == 9 && v[0] == '<' && v[1] == 0x54 && v[2] == 0xA2 && v[3] == 0x20AC && v[4] == wchar_cast(0x24B62) && v[5] == ' ' && v[6] == '/' && v[7] == '>' && v[8] == '\n');
+ }
+ else
+ {
+ CHECK(v.size() == 10 && v[0] == '<' && v[1] == 0x54 && v[2] == 0xA2 && v[3] == 0x20AC && v[4] == 0xd852 && v[5] == 0xdf62 && v[6] == ' ' && v[7] == '/' && v[8] == '>' && v[9] == '\n');
+ }
+}
+
+#ifdef PUGIXML_WCHAR_MODE
+TEST(write_encoding_huge)
+{
+ const unsigned int N = 16000;
+
+ // make a large utf16 name consisting of 6-byte char pairs (6 does not divide internal buffer size, so will need split correction)
+ std::string s_utf16 = std::string("\x00<", 2);
+
+ for (unsigned int i = 0; i < N; ++i) s_utf16 += "\x20\xAC\xd8\x52\xdf\x62";
+
+ s_utf16 += std::string("\x00/\x00>", 4);
+
+ xml_document doc;
+ CHECK(doc.load_buffer(&s_utf16[0], s_utf16.length(), parse_default, encoding_utf16_be));
+
+ std::string s_utf8 = "<";
+
+ for (unsigned int j = 0; j < N; ++j) s_utf8 += "\xE2\x82\xAC\xF0\xA4\xAD\xA2";
+
+ s_utf8 += " />\n";
+
+ CHECK(test_write_narrow(doc, format_default, encoding_utf8, s_utf8.c_str(), s_utf8.length()));
+}
+#else
+TEST(write_encoding_huge)
+{
+ const unsigned int N = 16000;
+
+ // make a large utf8 name consisting of 3-byte chars (3 does not divide internal buffer size, so will need split correction)
+ std::string s_utf8 = "<";
+
+ for (unsigned int i = 0; i < N; ++i) s_utf8 += "\xE2\x82\xAC";
+
+ s_utf8 += "/>";
+
+ xml_document doc;
+ CHECK(doc.load_buffer(&s_utf8[0], s_utf8.length(), parse_default, encoding_utf8));
+
+ std::string s_utf16 = std::string("\x00<", 2);
+
+ for (unsigned int j = 0; j < N; ++j) s_utf16 += "\x20\xAC";
+
+ s_utf16 += std::string("\x00 \x00/\x00>\x00\n", 8);
+
+ CHECK(test_write_narrow(doc, format_default, encoding_utf16_be, s_utf16.c_str(), s_utf16.length()));
+}
+
+TEST(write_encoding_huge_invalid)
+{
+ const unsigned int N = 16000;
+
+ // make a large utf8 name consisting of non-leading chars
+ std::string s_utf8 = "<";
+
+ for (unsigned int i = 0; i < N; ++i) s_utf8 += "\x82";
+
+ s_utf8 += "/>";
+
+ xml_document doc;
+ CHECK(doc.load_buffer(&s_utf8[0], s_utf8.length(), parse_default, encoding_utf8));
+
+ std::string s_utf16 = std::string("\x00<\x00 \x00/\x00>\x00\n", 10);
+
+ CHECK(test_write_narrow(doc, format_default, encoding_utf16_be, s_utf16.c_str(), s_utf16.length()));
+}
+#endif
+
+TEST(write_unicode_escape)
+{
+ char s_utf8[] = "<\xE2\x82\xAC \xC2\xA2='\"\xF0\xA4\xAD\xA2&#x0a;\"'>&amp;\x14\xF0\xA4\xAD\xA2&lt;</\xE2\x82\xAC>";
+
+ xml_document doc;
+ CHECK(doc.load_buffer(s_utf8, sizeof(s_utf8), parse_default, encoding_utf8));
+
+ CHECK(write_narrow(doc, format_default, encoding_utf8) == "<\xE2\x82\xAC \xC2\xA2=\"&quot;\xF0\xA4\xAD\xA2&#10;&quot;\">&amp;&#20;\xF0\xA4\xAD\xA2&lt;</\xE2\x82\xAC>\n");
+}
+
+#ifdef PUGIXML_WCHAR_MODE
+static bool test_write_unicode_invalid(const wchar_t* name, const char* expected)
+{
+ xml_document doc;
+ doc.append_child(node_pcdata).set_value(name);
+
+ return write_narrow(doc, format_raw, encoding_utf8) == expected;
+}
+
+TEST(write_unicode_invalid_utf16)
+{
+ size_t wcharsize = sizeof(wchar_t);
+
+ if (wcharsize == 2)
+ {
+ // check non-terminated degenerate handling
+ #ifdef U_LITERALS
+ CHECK(test_write_unicode_invalid(L"a\uda1d", "a"));
+ CHECK(test_write_unicode_invalid(L"a\uda1d_", "a_"));
+ #else
+ CHECK(test_write_unicode_invalid(L"a\xda1d", "a"));
+ CHECK(test_write_unicode_invalid(L"a\xda1d_", "a_"));
+ #endif
+
+ // check incorrect leading code
+ #ifdef U_LITERALS
+ CHECK(test_write_unicode_invalid(L"a\ude24", "a"));
+ CHECK(test_write_unicode_invalid(L"a\ude24_", "a_"));
+ #else
+ CHECK(test_write_unicode_invalid(L"a\xde24", "a"));
+ CHECK(test_write_unicode_invalid(L"a\xde24_", "a_"));
+ #endif
+ }
+}
+#else
+static bool test_write_unicode_invalid(const char* name, const wchar_t* expected)
+{
+ xml_document doc;
+ doc.append_child(node_pcdata).set_value(name);
+
+ return write_wide(doc, format_raw, encoding_wchar) == expected;
+}
+
+TEST(write_unicode_invalid_utf8)
+{
+ // invalid 1-byte input
+ CHECK(test_write_unicode_invalid("a\xb0", L"a"));
+ CHECK(test_write_unicode_invalid("a\xb0_", L"a_"));
+
+ // invalid 2-byte input
+ CHECK(test_write_unicode_invalid("a\xc0", L"a"));
+ CHECK(test_write_unicode_invalid("a\xd0", L"a"));
+ CHECK(test_write_unicode_invalid("a\xc0_", L"a_"));
+ CHECK(test_write_unicode_invalid("a\xd0_", L"a_"));
+
+ // invalid 3-byte input
+ CHECK(test_write_unicode_invalid("a\xe2\x80", L"a"));
+ CHECK(test_write_unicode_invalid("a\xe2", L"a"));
+ CHECK(test_write_unicode_invalid("a\xe2\x80_", L"a_"));
+ CHECK(test_write_unicode_invalid("a\xe2_", L"a_"));
+
+ // invalid 4-byte input
+ CHECK(test_write_unicode_invalid("a\xf2\x97\x98", L"a"));
+ CHECK(test_write_unicode_invalid("a\xf2\x97", L"a"));
+ CHECK(test_write_unicode_invalid("a\xf2", L"a"));
+ CHECK(test_write_unicode_invalid("a\xf2\x97\x98_", L"a_"));
+ CHECK(test_write_unicode_invalid("a\xf2\x97_", L"a_"));
+ CHECK(test_write_unicode_invalid("a\xf2_", L"a_"));
+
+ // invalid 5-byte input
+ CHECK(test_write_unicode_invalid("a\xf8_", L"a_"));
+}
+
+#endif
diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp
index 5f23f44..7ef34ec 100644
--- a/tests/test_xpath.cpp
+++ b/tests/test_xpath.cpp
@@ -2,46 +2,52 @@
#include "common.hpp"
+#include <float.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <string>
+
TEST_XML(xpath_document_order, "<node><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>")
{
CHECK(xml_node().document_order() == 0);
- CHECK(doc.child("node").document_order() == 0);
+ CHECK(doc.child(STR("node")).document_order() == 0);
CHECK(doc.document_order() == 0);
doc.precompute_document_order();
CHECK(doc.document_order() == 1);
- CHECK(doc.child("node").document_order() == 2);
- CHECK(doc.child("node").child("child1").document_order() == 3);
- CHECK(doc.child("node").child("child1").attribute("attr1").document_order() == 4);
- CHECK(doc.child("node").child("child1").attribute("attr2").document_order() == 5);
- CHECK(doc.child("node").child("child2").document_order() == 6);
- CHECK(doc.child("node").child("child2").attribute("attr1").document_order() == 7);
- CHECK(doc.child("node").child("child2").first_child().document_order() == 8);
+ CHECK(doc.child(STR("node")).document_order() == 2);
+ CHECK(doc.child(STR("node")).child(STR("child1")).document_order() == 3);
+ CHECK(doc.child(STR("node")).child(STR("child1")).attribute(STR("attr1")).document_order() == 4);
+ CHECK(doc.child(STR("node")).child(STR("child1")).attribute(STR("attr2")).document_order() == 5);
+ CHECK(doc.child(STR("node")).child(STR("child2")).document_order() == 6);
+ CHECK(doc.child(STR("node")).child(STR("child2")).attribute(STR("attr1")).document_order() == 7);
+ CHECK(doc.child(STR("node")).child(STR("child2")).first_child().document_order() == 8);
}
TEST(xpath_allocator_many_pages)
{
- std::string query = "0";
+ pugi::string_t query = STR("0");
- for (int i = 0; i < 128; ++i) query += "+string-length('abcdefgh')";
+ for (int i = 0; i < 128; ++i) query += STR("+string-length('abcdefgh')");
CHECK_XPATH_NUMBER(xml_node(), query.c_str(), 1024);
}
TEST(xpath_allocator_large_page)
{
- std::string query;
+ pugi::string_t query;
- for (int i = 0; i < 1024; ++i) query += "abcdefgh";
+ for (int i = 0; i < 1024; ++i) query += STR("abcdefgh");
- CHECK_XPATH_NUMBER(xml_node(), ("string-length('" + query + "')").c_str(), 8192);
+ CHECK_XPATH_NUMBER(xml_node(), (STR("string-length('") + query + STR("')")).c_str(), 8192);
}
TEST_XML(xpath_sort_complex, "<node><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>")
{
// just some random union order, it should not matter probably?
- xpath_node_set ns = doc.child("node").select_nodes("child1 | child2 | child1/@* | . | child2/@* | child2/text()");
+ xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child1 | child2 | child1/@* | . | child2/@* | child2/text()"));
ns.sort(false);
xpath_node_set sorted = ns;
@@ -57,7 +63,7 @@ TEST_XML(xpath_sort_complex, "<node><child1 attr1='value1' attr2='value2'/><chil
TEST_XML(xpath_sort_children, "<node><child><subchild id='1'/></child><child><subchild id='2'/></child></node>")
{
- xpath_node_set ns = doc.child("node").select_nodes("child/subchild[@id=1] | child/subchild[@id=2]");
+ xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child/subchild[@id=1] | child/subchild[@id=2]"));
ns.sort(false);
xpath_node_set sorted = ns;
@@ -73,15 +79,15 @@ TEST_XML(xpath_sort_children, "<node><child><subchild id='1'/></child><child><su
TEST_XML(xpath_sort_attributes, "<node/>")
{
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// we need to insert attributes manually since unsorted node sets are (always?) sorted via pointers because of remove_duplicates,
// so we need to have different document and pointer order to cover all comparator cases
- n.append_attribute("attr2");
- n.append_attribute("attr3");
- n.insert_attribute_before("attr1", n.attribute("attr2"));
+ n.append_attribute(STR("attr2"));
+ n.append_attribute(STR("attr3"));
+ n.insert_attribute_before(STR("attr1"), n.attribute(STR("attr2")));
- xpath_node_set ns = n.select_nodes("@*");
+ xpath_node_set ns = n.select_nodes(STR("@*"));
ns.sort(true);
xpath_node_set reverse_sorted = ns;
@@ -95,4 +101,54 @@ TEST_XML(xpath_sort_attributes, "<node/>")
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 5 % 4 % 3;
}
+TEST(xpath_long_numbers_parse)
+{
+ const pugi::char_t* str_flt_max = STR("340282346638528860000000000000000000000");
+ const pugi::char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000");
+
+ const pugi::char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ const pugi::char_t* str_dbl_max_dec = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000");
+
+ xml_node c;
+
+ // check parsing
+ CHECK_XPATH_NUMBER(c, str_flt_max, FLT_MAX);
+ CHECK_XPATH_NUMBER(c, str_flt_max_dec, FLT_MAX);
+ CHECK_XPATH_NUMBER(c, str_dbl_max, DBL_MAX);
+ CHECK_XPATH_NUMBER(c, str_dbl_max_dec, DBL_MAX);
+}
+
+static bool test_xpath_string_prefix(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected, size_t match_length)
+{
+#ifdef PUGIXML_WCHAR_MODE
+ size_t expected_length = wcslen(expected);
+#else
+ size_t expected_length = strlen(expected);
+#endif
+
+ pugi::xpath_query q(query);
+ pugi::string_t value = q.evaluate_string(node);
+
+ return value.length() == expected_length && value.compare(0, match_length, expected, match_length) == 0;
+}
+
+TEST(xpath_long_numbers_stringize)
+{
+ const pugi::char_t* str_flt_max = STR("340282346638528860000000000000000000000");
+ const pugi::char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000");
+
+ const pugi::char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ const pugi::char_t* str_dbl_max_dec = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000");
+
+ xml_node c;
+
+ CHECK(test_xpath_string_prefix(c, str_flt_max, str_flt_max, 16));
+ CHECK(test_xpath_string_prefix(c, str_flt_max_dec, str_flt_max, 16));
+
+#ifndef __BORLANDC__ // printf with %f format still results in 1.xxxe+308 form
+ CHECK(test_xpath_string_prefix(c, str_dbl_max, str_dbl_max, 16));
+ CHECK(test_xpath_string_prefix(c, str_dbl_max_dec, str_dbl_max, 16));
+#endif
+}
+
#endif
diff --git a/tests/test_xpath_api.cpp b/tests/test_xpath_api.cpp
index 665e7e9..d7cc094 100644
--- a/tests/test_xpath_api.cpp
+++ b/tests/test_xpath_api.cpp
@@ -4,13 +4,15 @@
#include "helpers.hpp"
+#include <string>
+
TEST_XML(xpath_api_select_nodes, "<node><head/><foo/><foo/><tail/></node>")
{
doc.precompute_document_order();
- xpath_node_set ns1 = doc.select_nodes("node/foo");
+ xpath_node_set ns1 = doc.select_nodes(STR("node/foo"));
- xpath_query q("node/foo");
+ xpath_query q(STR("node/foo"));
xpath_node_set ns2 = doc.select_nodes(q);
CHECK(ns1.size() == 2 && ns1[0].node().document_order() == 4 && ns1[1].node().document_order() == 5);
@@ -21,20 +23,20 @@ TEST_XML(xpath_api_select_single_node, "<node><head/><foo/><foo/><tail/></node>"
{
doc.precompute_document_order();
- xpath_node n1 = doc.select_single_node("node/foo");
+ xpath_node n1 = doc.select_single_node(STR("node/foo"));
- xpath_query q("node/foo");
+ xpath_query q(STR("node/foo"));
xpath_node n2 = doc.select_single_node(q);
CHECK(n1.node().document_order() == 4);
CHECK(n2.node().document_order() == 4);
- xpath_node n3 = doc.select_single_node("node/bar");
+ xpath_node n3 = doc.select_single_node(STR("node/bar"));
CHECK(!n3);
- xpath_node n4 = doc.select_single_node("node/head/following-sibling::foo");
- xpath_node n5 = doc.select_single_node("node/tail/preceding-sibling::foo");
+ xpath_node n4 = doc.select_single_node(STR("node/head/following-sibling::foo"));
+ xpath_node n5 = doc.select_single_node(STR("node/tail/preceding-sibling::foo"));
CHECK(n4.node().document_order() == 4);
CHECK(n5.node().document_order() == 4);
@@ -44,7 +46,7 @@ TEST(xpath_api_exception_what)
{
try
{
- xpath_query q("");
+ xpath_query q(STR(""));
}
catch (const xpath_exception& e)
{
@@ -54,32 +56,32 @@ TEST(xpath_api_exception_what)
TEST_XML(xpath_api_node_bool_ops, "<node attr='value'/>")
{
- generic_bool_ops_test(doc.select_single_node("node"));
- generic_bool_ops_test(doc.select_single_node("node/@attr"));
+ generic_bool_ops_test(doc.select_single_node(STR("node")));
+ generic_bool_ops_test(doc.select_single_node(STR("node/@attr")));
}
TEST_XML(xpath_api_node_eq_ops, "<node attr='value'/>")
{
- generic_eq_ops_test(doc.select_single_node("node"), doc.select_single_node("node/@attr"));
+ generic_eq_ops_test(doc.select_single_node(STR("node")), doc.select_single_node(STR("node/@attr")));
}
TEST_XML(xpath_api_node_accessors, "<node attr='value'/>")
{
xpath_node null;
- xpath_node node = doc.select_single_node("node");
- xpath_node attr = doc.select_single_node("node/@attr");
+ xpath_node node = doc.select_single_node(STR("node"));
+ xpath_node attr = doc.select_single_node(STR("node/@attr"));
CHECK(!null.node());
CHECK(!null.attribute());
CHECK(!null.parent());
- CHECK(node.node() == doc.child("node"));
+ CHECK(node.node() == doc.child(STR("node")));
CHECK(!node.attribute());
CHECK(node.parent() == doc);
CHECK(!attr.node());
- CHECK(attr.attribute() == doc.child("node").attribute("attr"));
- CHECK(attr.parent() == doc.child("node"));
+ CHECK(attr.attribute() == doc.child(STR("node")).attribute(STR("attr")));
+ CHECK(attr.parent() == doc.child(STR("node")));
}
inline void xpath_api_node_accessors_helper(const xpath_node_set& set)
@@ -87,8 +89,8 @@ inline void xpath_api_node_accessors_helper(const xpath_node_set& set)
CHECK(set.size() == 2);
CHECK(set.type() == xpath_node_set::type_sorted);
CHECK(!set.empty());
- CHECK_STRING(set[0].node().name(), "foo");
- CHECK_STRING(set[1].node().name(), "foo");
+ CHECK_STRING(set[0].node().name(), STR("foo"));
+ CHECK_STRING(set[1].node().name(), STR("foo"));
CHECK(!set[2]);
CHECK(set.first() == set[0]);
CHECK(set.begin() + 2 == set.end());
@@ -105,7 +107,7 @@ TEST_XML(xpath_api_nodeset_accessors, "<node><foo/><foo/></node>")
CHECK(!null.first());
CHECK(null.begin() == null.end());
- xpath_node_set set = doc.select_nodes("node/foo");
+ xpath_node_set set = doc.select_nodes(STR("node/foo"));
xpath_api_node_accessors_helper(set);
xpath_node_set copy = set;
@@ -120,21 +122,21 @@ TEST_XML(xpath_api_nodeset_accessors, "<node><foo/><foo/></node>")
TEST_XML(xpath_api_evaluate, "<node attr='3'/>")
{
- xpath_query q("node/@attr");
+ xpath_query q(STR("node/@attr"));
CHECK(q.evaluate_boolean(doc));
CHECK(q.evaluate_number(doc) == 3);
- CHECK(q.evaluate_string(doc) == "3");
+ CHECK(q.evaluate_string(doc) == STR("3"));
xpath_node_set ns = q.evaluate_node_set(doc);
- CHECK(ns.size() == 1 && ns[0].attribute() == doc.child("node").attribute("attr"));
+ CHECK(ns.size() == 1 && ns[0].attribute() == doc.child(STR("node")).attribute(STR("attr")));
}
TEST(xpath_api_evaluate_node_set)
{
try
{
- xpath_query q("1");
+ xpath_query q(STR("1"));
q.evaluate_node_set(xml_node());
}
@@ -145,10 +147,10 @@ TEST(xpath_api_evaluate_node_set)
TEST(xpath_api_return_type)
{
- CHECK(xpath_query("node").return_type() == xpath_type_node_set);
- CHECK(xpath_query("1").return_type() == xpath_type_number);
- CHECK(xpath_query("'s'").return_type() == xpath_type_string);
- CHECK(xpath_query("true()").return_type() == xpath_type_boolean);
+ CHECK(xpath_query(STR("node")).return_type() == xpath_type_node_set);
+ CHECK(xpath_query(STR("1")).return_type() == xpath_type_number);
+ CHECK(xpath_query(STR("'s'")).return_type() == xpath_type_string);
+ CHECK(xpath_query(STR("true()")).return_type() == xpath_type_boolean);
}
#endif
diff --git a/tests/test_xpath_functions.cpp b/tests/test_xpath_functions.cpp
index 1ab4d71..ed18e5f 100644
--- a/tests/test_xpath_functions.cpp
+++ b/tests/test_xpath_functions.cpp
@@ -5,60 +5,62 @@
TEST_XML(xpath_number_number, "<node>123</node>")
{
xml_node c;
- xml_node n = doc.child("node").first_child();
+ xml_node n = doc.child(STR("node")).first_child();
// number with 0 arguments
- CHECK_XPATH_NUMBER_NAN(c, "number()");
- CHECK_XPATH_NUMBER(n, "number()", 123);
+ CHECK_XPATH_NUMBER_NAN(c, STR("number()"));
+ CHECK_XPATH_NUMBER(n, STR("number()"), 123);
// number with 1 string argument
- CHECK_XPATH_NUMBER(c, "number(' -123.456 ')", -123.456);
- CHECK_XPATH_NUMBER(c, "number(' -123.')", -123);
- CHECK_XPATH_NUMBER(c, "number('123.')", 123);
- CHECK_XPATH_NUMBER(c, "number('.56')", 0.56);
- CHECK_XPATH_NUMBER(c, "number('123 ')", 123);
- CHECK_XPATH_NUMBER_NAN(c, "number('foobar')");
- CHECK_XPATH_NUMBER_NAN(c, "number('f1')");
- CHECK_XPATH_NUMBER_NAN(c, "number('1f')");
- CHECK_XPATH_NUMBER_NAN(c, "number('1.f')");
- CHECK_XPATH_NUMBER_NAN(c, "number('1.0f')");
- CHECK_XPATH_NUMBER_NAN(c, "number('123 f')");
+ CHECK_XPATH_NUMBER(c, STR("number(' -123.456 ')"), -123.456);
+ CHECK_XPATH_NUMBER(c, STR("number(' -123.')"), -123);
+ CHECK_XPATH_NUMBER(c, STR("number('123.')"), 123);
+ CHECK_XPATH_NUMBER(c, STR("number('.56')"), 0.56);
+ CHECK_XPATH_NUMBER(c, STR("number('123 ')"), 123);
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('foobar')"));
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('f1')"));
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('1f')"));
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('1.f')"));
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('1.0f')"));
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('123 f')"));
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('')"));
+ CHECK_XPATH_NUMBER_NAN(c, STR("number('.')"));
// number with 1 bool argument
- CHECK_XPATH_NUMBER(c, "number(true())", 1);
- CHECK_XPATH_NUMBER(c, "number(false())", 0);
+ CHECK_XPATH_NUMBER(c, STR("number(true())"), 1);
+ CHECK_XPATH_NUMBER(c, STR("number(false())"), 0);
// number with 1 node set argument
- CHECK_XPATH_NUMBER(n, "number(.)", 123);
+ CHECK_XPATH_NUMBER(n, STR("number(.)"), 123);
// number with 1 number argument
- CHECK_XPATH_NUMBER(c, "number(1)", 1);
+ CHECK_XPATH_NUMBER(c, STR("number(1)"), 1);
// number with 2 arguments
- CHECK_XPATH_FAIL("number(1, 2)");
+ CHECK_XPATH_FAIL(STR("number(1, 2)"));
}
TEST_XML(xpath_number_sum, "<node>123<child>789</child></node><node/>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// sum with 0 arguments
- CHECK_XPATH_FAIL("sum()");
+ CHECK_XPATH_FAIL(STR("sum()"));
// sum with 1 argument
- CHECK_XPATH_NUMBER(c, "sum(.)", 0);
- CHECK_XPATH_NUMBER(n, "sum(.)", 123789); // 123 .. 789
+ CHECK_XPATH_NUMBER(c, STR("sum(.)"), 0);
+ CHECK_XPATH_NUMBER(n, STR("sum(.)"), 123789); // 123 .. 789
- CHECK_XPATH_NUMBER(n, "sum(./descendant-or-self::node())", 125490); // node + 123 + child + 789 = 123789 + 123 + 789 + 789 = 125490
- CHECK_XPATH_NUMBER(n, "sum(.//node())", 1701); // 123 + child + 789 = 123 + 789 + 789
- CHECK_XPATH_NUMBER_NAN(doc.last_child(), "sum(.)");
+ CHECK_XPATH_NUMBER(n, STR("sum(./descendant-or-self::node())"), 125490); // node + 123 + child + 789 = 123789 + 123 + 789 + 789 = 125490
+ CHECK_XPATH_NUMBER(n, STR("sum(.//node())"), 1701); // 123 + child + 789 = 123 + 789 + 789
+ CHECK_XPATH_NUMBER_NAN(doc.last_child(), STR("sum(.)"));
// sum with 2 arguments
- CHECK_XPATH_FAIL("sum(1, 2)");
+ CHECK_XPATH_FAIL(STR("sum(1, 2)"));
// sum with 1 non-node-set argument
- CHECK_XPATH_FAIL("sum(1)");
+ CHECK_XPATH_FAIL(STR("sum(1)"));
}
TEST(xpath_number_floor)
@@ -66,18 +68,18 @@ TEST(xpath_number_floor)
xml_node c;
// floor with 0 arguments
- CHECK_XPATH_FAIL("floor()");
+ CHECK_XPATH_FAIL(STR("floor()"));
// floor with 1 argument
- CHECK_XPATH_NUMBER(c, "floor(1.2)", 1);
- CHECK_XPATH_NUMBER(c, "floor(1)", 1);
- CHECK_XPATH_NUMBER(c, "floor(-1.2)", -2);
- CHECK_XPATH_NUMBER_NAN(c, "floor(string('nan'))");
- CHECK_XPATH_STRING(c, "string(floor(1 div 0))", "Infinity");
- CHECK_XPATH_STRING(c, "string(floor(-1 div 0))", "-Infinity");
+ CHECK_XPATH_NUMBER(c, STR("floor(1.2)"), 1);
+ CHECK_XPATH_NUMBER(c, STR("floor(1)"), 1);
+ CHECK_XPATH_NUMBER(c, STR("floor(-1.2)"), -2);
+ CHECK_XPATH_NUMBER_NAN(c, STR("floor(string('nan'))"));
+ CHECK_XPATH_STRING(c, STR("string(floor(1 div 0))"), STR("Infinity"));
+ CHECK_XPATH_STRING(c, STR("string(floor(-1 div 0))"), STR("-Infinity"));
// floor with 2 arguments
- CHECK_XPATH_FAIL("floor(1, 2)");
+ CHECK_XPATH_FAIL(STR("floor(1, 2)"));
}
TEST(xpath_number_ceiling)
@@ -85,18 +87,18 @@ TEST(xpath_number_ceiling)
xml_node c;
// ceiling with 0 arguments
- CHECK_XPATH_FAIL("ceiling()");
+ CHECK_XPATH_FAIL(STR("ceiling()"));
// ceiling with 1 argument
- CHECK_XPATH_NUMBER(c, "ceiling(1.2)", 2);
- CHECK_XPATH_NUMBER(c, "ceiling(1)", 1);
- CHECK_XPATH_NUMBER(c, "ceiling(-1.2)", -1);
- CHECK_XPATH_NUMBER_NAN(c, "ceiling(string('nan'))");
- CHECK_XPATH_STRING(c, "string(ceiling(1 div 0))", "Infinity");
- CHECK_XPATH_STRING(c, "string(ceiling(-1 div 0))", "-Infinity");
+ CHECK_XPATH_NUMBER(c, STR("ceiling(1.2)"), 2);
+ CHECK_XPATH_NUMBER(c, STR("ceiling(1)"), 1);
+ CHECK_XPATH_NUMBER(c, STR("ceiling(-1.2)"), -1);
+ CHECK_XPATH_NUMBER_NAN(c, STR("ceiling(string('nan'))"));
+ CHECK_XPATH_STRING(c, STR("string(ceiling(1 div 0))"), STR("Infinity"));
+ CHECK_XPATH_STRING(c, STR("string(ceiling(-1 div 0))"), STR("-Infinity"));
// ceiling with 2 arguments
- CHECK_XPATH_FAIL("ceiling(1, 2)");
+ CHECK_XPATH_FAIL(STR("ceiling(1, 2)"));
}
TEST(xpath_number_round)
@@ -104,22 +106,22 @@ TEST(xpath_number_round)
xml_node c;
// round with 0 arguments
- CHECK_XPATH_FAIL("round()");
+ CHECK_XPATH_FAIL(STR("round()"));
// round with 1 argument
- CHECK_XPATH_NUMBER(c, "round(1.2)", 1);
- CHECK_XPATH_NUMBER(c, "round(1.5)", 2);
- CHECK_XPATH_NUMBER(c, "round(1.8)", 2);
- CHECK_XPATH_NUMBER(c, "round(1)", 1);
- CHECK_XPATH_NUMBER(c, "round(-1.2)", -1);
- CHECK_XPATH_NUMBER(c, "round(-1.5)", -1);
- CHECK_XPATH_NUMBER(c, "round(-1.6)", -2);
- CHECK_XPATH_NUMBER_NAN(c, "round(string('nan'))");
- CHECK_XPATH_STRING(c, "string(round(1 div 0))", "Infinity");
- CHECK_XPATH_STRING(c, "string(round(-1 div 0))", "-Infinity");
+ CHECK_XPATH_NUMBER(c, STR("round(1.2)"), 1);
+ CHECK_XPATH_NUMBER(c, STR("round(1.5)"), 2);
+ CHECK_XPATH_NUMBER(c, STR("round(1.8)"), 2);
+ CHECK_XPATH_NUMBER(c, STR("round(1)"), 1);
+ CHECK_XPATH_NUMBER(c, STR("round(-1.2)"), -1);
+ CHECK_XPATH_NUMBER(c, STR("round(-1.5)"), -1);
+ CHECK_XPATH_NUMBER(c, STR("round(-1.6)"), -2);
+ CHECK_XPATH_NUMBER_NAN(c, STR("round(string('nan'))"));
+ CHECK_XPATH_STRING(c, STR("string(round(1 div 0))"), STR("Infinity"));
+ CHECK_XPATH_STRING(c, STR("string(round(-1 div 0))"), STR("-Infinity"));
// round with 2 arguments
- CHECK_XPATH_FAIL("round(1, 2)");
+ CHECK_XPATH_FAIL(STR("round(1, 2)"));
}
TEST_XML(xpath_boolean_boolean, "<node />")
@@ -127,26 +129,26 @@ TEST_XML(xpath_boolean_boolean, "<node />")
xml_node c;
// boolean with 0 arguments
- CHECK_XPATH_FAIL("boolean()");
+ CHECK_XPATH_FAIL(STR("boolean()"));
// boolean with 1 number argument
- CHECK_XPATH_BOOLEAN(c, "boolean(0)", false);
- CHECK_XPATH_BOOLEAN(c, "boolean(1)", true);
- CHECK_XPATH_BOOLEAN(c, "boolean(-1)", true);
- CHECK_XPATH_BOOLEAN(c, "boolean(0.1)", true);
- CHECK_XPATH_BOOLEAN(c, "boolean(number('nan'))", false);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean(0)"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean(1)"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean(-1)"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean(0.1)"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean(number('nan'))"), false);
// boolean with 1 string argument
- CHECK_XPATH_BOOLEAN(c, "boolean('x')", true);
- CHECK_XPATH_BOOLEAN(c, "boolean('')", false);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean('x')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean('')"), false);
// boolean with 1 node set argument
- CHECK_XPATH_BOOLEAN(c, "boolean(.)", false);
- CHECK_XPATH_BOOLEAN(doc, "boolean(.)", true);
- CHECK_XPATH_BOOLEAN(doc, "boolean(foo)", false);
+ CHECK_XPATH_BOOLEAN(c, STR("boolean(.)"), false);
+ CHECK_XPATH_BOOLEAN(doc, STR("boolean(.)"), true);
+ CHECK_XPATH_BOOLEAN(doc, STR("boolean(foo)"), false);
// boolean with 2 arguments
- CHECK_XPATH_FAIL("boolean(1, 2)");
+ CHECK_XPATH_FAIL(STR("boolean(1, 2)"));
}
TEST(xpath_boolean_not)
@@ -154,14 +156,14 @@ TEST(xpath_boolean_not)
xml_node c;
// not with 0 arguments
- CHECK_XPATH_FAIL("not()");
+ CHECK_XPATH_FAIL(STR("not()"));
// not with 1 argument
- CHECK_XPATH_BOOLEAN(c, "not(true())", false);
- CHECK_XPATH_BOOLEAN(c, "not(false())", true);
+ CHECK_XPATH_BOOLEAN(c, STR("not(true())"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("not(false())"), true);
// boolean with 2 arguments
- CHECK_XPATH_FAIL("not(1, 2)");
+ CHECK_XPATH_FAIL(STR("not(1, 2)"));
}
TEST(xpath_boolean_true)
@@ -169,10 +171,10 @@ TEST(xpath_boolean_true)
xml_node c;
// true with 0 arguments
- CHECK_XPATH_BOOLEAN(c, "true()", true);
+ CHECK_XPATH_BOOLEAN(c, STR("true()"), true);
// true with 1 argument
- CHECK_XPATH_FAIL("true(1)");
+ CHECK_XPATH_FAIL(STR("true(1)"));
}
TEST(xpath_boolean_false)
@@ -180,10 +182,10 @@ TEST(xpath_boolean_false)
xml_node c;
// false with 0 arguments
- CHECK_XPATH_BOOLEAN(c, "false()", false);
+ CHECK_XPATH_BOOLEAN(c, STR("false()"), false);
// false with 1 argument
- CHECK_XPATH_FAIL("false(1)");
+ CHECK_XPATH_FAIL(STR("false(1)"));
}
TEST_XML(xpath_boolean_lang, "<node xml:lang='en'><child xml:lang='ru-UK'><subchild/></child></node><foo><bar/></foo>")
@@ -191,71 +193,71 @@ TEST_XML(xpath_boolean_lang, "<node xml:lang='en'><child xml:lang='ru-UK'><subch
xml_node c;
// lang with 0 arguments
- CHECK_XPATH_FAIL("lang()");
+ CHECK_XPATH_FAIL(STR("lang()"));
// lang with 1 argument, no language
- CHECK_XPATH_BOOLEAN(c, "lang('en')", false);
- CHECK_XPATH_BOOLEAN(doc.child("foo"), "lang('en')", false);
- CHECK_XPATH_BOOLEAN(doc.child("foo"), "lang('')", false);
- CHECK_XPATH_BOOLEAN(doc.child("foo").child("bar"), "lang('en')", false);
+ CHECK_XPATH_BOOLEAN(c, STR("lang('en')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("foo")), STR("lang('en')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("foo")), STR("lang('')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("foo")).child(STR("bar")), STR("lang('en')"), false);
// lang with 1 argument, same language/prefix
- CHECK_XPATH_BOOLEAN(doc.child("node"), "lang('en')", true);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child"), "lang('ru-uk')", true);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child"), "lang('ru')", true);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child").child("subchild"), "lang('ru')", true);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child").child("subchild"), "lang('RU')", true);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")), STR("lang('en')"), true);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('ru-uk')"), true);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('ru')"), true);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('ru')"), true);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('RU')"), true);
// lang with 1 argument, different language/prefix
- CHECK_XPATH_BOOLEAN(doc.child("node"), "lang('')", false);
- CHECK_XPATH_BOOLEAN(doc.child("node"), "lang('e')", false);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child"), "lang('en')", false);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child"), "lang('ru-gb')", false);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child"), "lang('r')", false);
- CHECK_XPATH_BOOLEAN(doc.child("node").child("child").child("subchild"), "lang('en')", false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")), STR("lang('')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")), STR("lang('e')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('en')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('ru-gb')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('r')"), false);
+ CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('en')"), false);
// lang with 2 arguments
- CHECK_XPATH_FAIL("lang(1, 2)");
+ CHECK_XPATH_FAIL(STR("lang(1, 2)"));
}
TEST_XML(xpath_string_string, "<node>123<child id='1'>789</child><child><![CDATA[200]]></child>100</node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// string with 0 arguments
- CHECK_XPATH_STRING(c, "string()", "");
- CHECK_XPATH_STRING(n.child("child"), "string()", "789");
+ CHECK_XPATH_STRING(c, STR("string()"), STR(""));
+ CHECK_XPATH_STRING(n.child(STR("child")), STR("string()"), STR("789"));
// string with 1 node-set argument
- CHECK_XPATH_STRING(n, "string(child)", "789");
- CHECK_XPATH_STRING(n, "string(child/@id)", "1");
- CHECK_XPATH_STRING(n, "string(.)", "123789200100");
+ CHECK_XPATH_STRING(n, STR("string(child)"), STR("789"));
+ CHECK_XPATH_STRING(n, STR("string(child/@id)"), STR("1"));
+ CHECK_XPATH_STRING(n, STR("string(.)"), STR("123789200100"));
// string with 1 number argument
- CHECK_XPATH_STRING(c, "string(0 div 0)", "NaN");
- CHECK_XPATH_STRING(c, "string(0)", "0");
- CHECK_XPATH_STRING(c, "string(-0)", "0");
- CHECK_XPATH_STRING(c, "string(1 div 0)", "Infinity");
- CHECK_XPATH_STRING(c, "string(-1 div 0)", "-Infinity");
- CHECK_XPATH_STRING(c, "string(1234567)", "1234567");
- CHECK_XPATH_STRING(c, "string(-1234567)", "-1234567");
- CHECK_XPATH_STRING(c, "string(1234.5678)", "1234.5678");
- CHECK_XPATH_STRING(c, "string(-1234.5678)", "-1234.5678");
- CHECK_XPATH_STRING(c, "string(0.5678)", "0.5678");
- CHECK_XPATH_STRING(c, "string(-0.5678)", "-0.5678");
- CHECK_XPATH_STRING(c, "string(0.0)", "0");
- CHECK_XPATH_STRING(c, "string(-0.0)", "0");
+ CHECK_XPATH_STRING(c, STR("string(0 div 0)"), STR("NaN"));
+ CHECK_XPATH_STRING(c, STR("string(0)"), STR("0"));
+ CHECK_XPATH_STRING(c, STR("string(-0)"), STR("0"));
+ CHECK_XPATH_STRING(c, STR("string(1 div 0)"), STR("Infinity"));
+ CHECK_XPATH_STRING(c, STR("string(-1 div 0)"), STR("-Infinity"));
+ CHECK_XPATH_STRING(c, STR("string(1234567)"), STR("1234567"));
+ CHECK_XPATH_STRING(c, STR("string(-1234567)"), STR("-1234567"));
+ CHECK_XPATH_STRING(c, STR("string(1234.5678)"), STR("1234.5678"));
+ CHECK_XPATH_STRING(c, STR("string(-1234.5678)"), STR("-1234.5678"));
+ CHECK_XPATH_STRING(c, STR("string(0.5678)"), STR("0.5678"));
+ CHECK_XPATH_STRING(c, STR("string(-0.5678)"), STR("-0.5678"));
+ CHECK_XPATH_STRING(c, STR("string(0.0)"), STR("0"));
+ CHECK_XPATH_STRING(c, STR("string(-0.0)"), STR("0"));
// string with 1 boolean argument
- CHECK_XPATH_STRING(c, "string(true())", "true");
- CHECK_XPATH_STRING(c, "string(false())", "false");
+ CHECK_XPATH_STRING(c, STR("string(true())"), STR("true"));
+ CHECK_XPATH_STRING(c, STR("string(false())"), STR("false"));
// string with 1 string argument
- CHECK_XPATH_STRING(c, "string('abc')", "abc");
+ CHECK_XPATH_STRING(c, STR("string('abc')"), STR("abc"));
// string with 2 arguments
- CHECK_XPATH_FAIL("string(1, 2)");
+ CHECK_XPATH_FAIL(STR("string(1, 2)"));
}
TEST(xpath_string_concat)
@@ -263,22 +265,22 @@ TEST(xpath_string_concat)
xml_node c;
// concat with 0 arguments
- CHECK_XPATH_FAIL("concat()");
+ CHECK_XPATH_FAIL(STR("concat()"));
// concat with 1 argument
- CHECK_XPATH_FAIL("concat('')");
+ CHECK_XPATH_FAIL(STR("concat('')"));
// concat with exactly 2 arguments
- CHECK_XPATH_STRING(c, "concat('prev','next')", "prevnext");
- CHECK_XPATH_STRING(c, "concat('','next')", "next");
- CHECK_XPATH_STRING(c, "concat('prev','')", "prev");
+ CHECK_XPATH_STRING(c, STR("concat('prev','next')"), STR("prevnext"));
+ CHECK_XPATH_STRING(c, STR("concat('','next')"), STR("next"));
+ CHECK_XPATH_STRING(c, STR("concat('prev','')"), STR("prev"));
// concat with 3 or more arguments
- CHECK_XPATH_STRING(c, "concat('a', 'b', 'c')", "abc");
- CHECK_XPATH_STRING(c, "concat('a', 'b', 'c', 'd')", "abcd");
- CHECK_XPATH_STRING(c, "concat('a', 'b', 'c', 'd', 'e')", "abcde");
- CHECK_XPATH_STRING(c, "concat('a', 'b', 'c', 'd', 'e', 'f')", "abcdef");
- CHECK_XPATH_STRING(c, "concat('a', 'b', 'c', 'd', 'e', 'f', 'g')", "abcdefg");
+ CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c')"), STR("abc"));
+ CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd')"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd', 'e')"), STR("abcde"));
+ CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd', 'e', 'f')"), STR("abcdef"));
+ CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd', 'e', 'f', 'g')"), STR("abcdefg"));
}
TEST(xpath_string_starts_with)
@@ -286,22 +288,22 @@ TEST(xpath_string_starts_with)
xml_node c;
// starts-with with 0 arguments
- CHECK_XPATH_FAIL("starts-with()");
+ CHECK_XPATH_FAIL(STR("starts-with()"));
// starts-with with 1 argument
- CHECK_XPATH_FAIL("starts-with('a')");
+ CHECK_XPATH_FAIL(STR("starts-with('a')"));
// starts-with with 2 arguments
- CHECK_XPATH_BOOLEAN(c, "starts-with('abc', '')", true);
- CHECK_XPATH_BOOLEAN(c, "starts-with('abc', 'a')", true);
- CHECK_XPATH_BOOLEAN(c, "starts-with('abc', 'abc')", true);
- CHECK_XPATH_BOOLEAN(c, "starts-with('abc', 'abcd')", false);
- CHECK_XPATH_BOOLEAN(c, "starts-with('bc', 'c')", false);
- CHECK_XPATH_BOOLEAN(c, "starts-with('', 'c')", false);
- CHECK_XPATH_BOOLEAN(c, "starts-with('', '')", true);
+ CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', '')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'a')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'abc')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'abcd')"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("starts-with('bc', 'c')"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("starts-with('', 'c')"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("starts-with('', '')"), true);
// starts-with with 3 arguments
- CHECK_XPATH_FAIL("starts-with('a', 'b', 'c')");
+ CHECK_XPATH_FAIL(STR("starts-with('a', 'b', 'c')"));
}
TEST(xpath_string_contains)
@@ -309,23 +311,23 @@ TEST(xpath_string_contains)
xml_node c;
// contains with 0 arguments
- CHECK_XPATH_FAIL("contains()");
+ CHECK_XPATH_FAIL(STR("contains()"));
// contains with 1 argument
- CHECK_XPATH_FAIL("contains('a')");
+ CHECK_XPATH_FAIL(STR("contains('a')"));
// contains with 2 arguments
- CHECK_XPATH_BOOLEAN(c, "contains('abc', '')", true);
- CHECK_XPATH_BOOLEAN(c, "contains('abc', 'a')", true);
- CHECK_XPATH_BOOLEAN(c, "contains('abc', 'abc')", true);
- CHECK_XPATH_BOOLEAN(c, "contains('abcd', 'bc')", true);
- CHECK_XPATH_BOOLEAN(c, "contains('abc', 'abcd')", false);
- CHECK_XPATH_BOOLEAN(c, "contains('b', 'bc')", false);
- CHECK_XPATH_BOOLEAN(c, "contains('', 'c')", false);
- CHECK_XPATH_BOOLEAN(c, "contains('', '')", true);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('abc', '')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'a')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'abc')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('abcd', 'bc')"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'abcd')"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('b', 'bc')"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('', 'c')"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("contains('', '')"), true);
// contains with 3 arguments
- CHECK_XPATH_FAIL("contains('a', 'b', 'c')");
+ CHECK_XPATH_FAIL(STR("contains('a', 'b', 'c')"));
}
TEST(xpath_string_substring_before)
@@ -333,24 +335,24 @@ TEST(xpath_string_substring_before)
xml_node c;
// substring-before with 0 arguments
- CHECK_XPATH_FAIL("substring-before()");
+ CHECK_XPATH_FAIL(STR("substring-before()"));
// substring-before with 1 argument
- CHECK_XPATH_FAIL("substring-before('a')");
+ CHECK_XPATH_FAIL(STR("substring-before('a')"));
// substring-before with 2 arguments
- CHECK_XPATH_STRING(c, "substring-before('abc', 'abc')", "");
- CHECK_XPATH_STRING(c, "substring-before('abc', 'a')", "");
- CHECK_XPATH_STRING(c, "substring-before('abc', 'cd')", "");
- CHECK_XPATH_STRING(c, "substring-before('abc', 'b')", "a");
- CHECK_XPATH_STRING(c, "substring-before('abc', 'c')", "ab");
- CHECK_XPATH_STRING(c, "substring-before('', '')", "");
+ CHECK_XPATH_STRING(c, STR("substring-before('abc', 'abc')"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring-before('abc', 'a')"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring-before('abc', 'cd')"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring-before('abc', 'b')"), STR("a"));
+ CHECK_XPATH_STRING(c, STR("substring-before('abc', 'c')"), STR("ab"));
+ CHECK_XPATH_STRING(c, STR("substring-before('', '')"), STR(""));
// substring-before with 2 arguments, from W3C standard
- CHECK_XPATH_STRING(c, "substring-before(\"1999/04/01\",\"/\")", "1999");
+ CHECK_XPATH_STRING(c, STR("substring-before(\"1999/04/01\",\"/\")"), STR("1999"));
// substring-before with 3 arguments
- CHECK_XPATH_FAIL("substring-before('a', 'b', 'c')");
+ CHECK_XPATH_FAIL(STR("substring-before('a', 'b', 'c')"));
}
TEST(xpath_string_substring_after)
@@ -358,25 +360,25 @@ TEST(xpath_string_substring_after)
xml_node c;
// substring-after with 0 arguments
- CHECK_XPATH_FAIL("substring-after()");
+ CHECK_XPATH_FAIL(STR("substring-after()"));
// substring-after with 1 argument
- CHECK_XPATH_FAIL("substring-after('a')");
+ CHECK_XPATH_FAIL(STR("substring-after('a')"));
// substring-after with 2 arguments
- CHECK_XPATH_STRING(c, "substring-after('abc', 'abc')", "");
- CHECK_XPATH_STRING(c, "substring-after('abc', 'a')", "bc");
- CHECK_XPATH_STRING(c, "substring-after('abc', 'cd')", "");
- CHECK_XPATH_STRING(c, "substring-after('abc', 'b')", "c");
- CHECK_XPATH_STRING(c, "substring-after('abc', 'c')", "");
- CHECK_XPATH_STRING(c, "substring-after('', '')", "");
+ CHECK_XPATH_STRING(c, STR("substring-after('abc', 'abc')"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring-after('abc', 'a')"), STR("bc"));
+ CHECK_XPATH_STRING(c, STR("substring-after('abc', 'cd')"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring-after('abc', 'b')"), STR("c"));
+ CHECK_XPATH_STRING(c, STR("substring-after('abc', 'c')"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring-after('', '')"), STR(""));
// substring-before with 2 arguments, from W3C standard
- CHECK_XPATH_STRING(c, "substring-after(\"1999/04/01\",\"/\")", "04/01");
- CHECK_XPATH_STRING(c, "substring-after(\"1999/04/01\",\"19\")", "99/04/01");
+ CHECK_XPATH_STRING(c, STR("substring-after(\"1999/04/01\",\"/\")"), STR("04/01"));
+ CHECK_XPATH_STRING(c, STR("substring-after(\"1999/04/01\",\"19\")"), STR("99/04/01"));
// substring-after with 3 arguments
- CHECK_XPATH_FAIL("substring-after('a', 'b', 'c')");
+ CHECK_XPATH_FAIL(STR("substring-after('a', 'b', 'c')"));
}
TEST(xpath_string_substring)
@@ -384,91 +386,91 @@ TEST(xpath_string_substring)
xml_node c;
// substring with 0 arguments
- CHECK_XPATH_FAIL("substring()");
+ CHECK_XPATH_FAIL(STR("substring()"));
// substring with 1 argument
- CHECK_XPATH_FAIL("substring('')");
+ CHECK_XPATH_FAIL(STR("substring('')"));
// substring with 2 arguments
- CHECK_XPATH_STRING(c, "substring('abcd', 2)", "bcd");
- CHECK_XPATH_STRING(c, "substring('abcd', 1)", "abcd");
- CHECK_XPATH_STRING(c, "substring('abcd', 1.1)", "abcd");
- CHECK_XPATH_STRING(c, "substring('abcd', 1.5)", "bcd");
- CHECK_XPATH_STRING(c, "substring('abcd', 1.8)", "bcd");
- CHECK_XPATH_STRING(c, "substring('abcd', 10)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', 0)", "abcd");
- CHECK_XPATH_STRING(c, "substring('abcd', -100)", "abcd");
- CHECK_XPATH_STRING(c, "substring('abcd', -1 div 0)", "abcd");
- CHECK_XPATH_STRING(c, "substring('abcd', 1 div 0)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', 0 div 0)", "");
- CHECK_XPATH_STRING(c, "substring('', 1)", "");
- CHECK_XPATH_STRING(c, "substring('', 0)", "");
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 2)"), STR("bcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1)"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1.1)"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1.5)"), STR("bcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1.8)"), STR("bcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 10)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 0)"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', -100)"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', -1 div 0)"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1 div 0)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 0 div 0)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('', 1)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('', 0)"), STR(""));
// substring with 3 arguments
- CHECK_XPATH_STRING(c, "substring('abcd', 2, 1)", "b");
- CHECK_XPATH_STRING(c, "substring('abcd', 2, 2)", "bc");
- CHECK_XPATH_STRING(c, "substring('abcd', 1, 0)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', 1, 0.4)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', 1, 0.5)", "a");
- CHECK_XPATH_STRING(c, "substring('abcd', 10, -5)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', 0, -1)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', -100, 100)", "abcd");
- CHECK_XPATH_STRING(c, "substring('abcd', -1 div 0, 4)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', 1 div 0, 0 div 0)", "");
- CHECK_XPATH_STRING(c, "substring('abcd', 0 div 0, 1)", "");
- CHECK_XPATH_STRING(c, "substring('', 1, 2)", "");
- CHECK_XPATH_STRING(c, "substring('', 0, 0)", "");
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 2, 1)"), STR("b"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 2, 2)"), STR("bc"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1, 0)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1, 0.4)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1, 0.5)"), STR("a"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 10, -5)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 0, -1)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 100)"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', -1 div 0, 4)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 1 div 0, 0 div 0)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('abcd', 0 div 0, 1)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('', 1, 2)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('', 0, 0)"), STR(""));
// substring with 3 arguments, from W3C standard
- CHECK_XPATH_STRING(c, "substring('12345', 1.5, 2.6)", "234");
- CHECK_XPATH_STRING(c, "substring('12345', 0, 3)", "12");
- CHECK_XPATH_STRING(c, "substring('12345', 0 div 0, 3)", "");
- CHECK_XPATH_STRING(c, "substring('12345', 1, 0 div 0)", "");
- CHECK_XPATH_STRING(c, "substring('12345', -42, 1 div 0)", "12345");
- CHECK_XPATH_STRING(c, "substring('12345', -1 div 0, 1 div 0)", "");
+ CHECK_XPATH_STRING(c, STR("substring('12345', 1.5, 2.6)"), STR("234"));
+ CHECK_XPATH_STRING(c, STR("substring('12345', 0, 3)"), STR("12"));
+ CHECK_XPATH_STRING(c, STR("substring('12345', 0 div 0, 3)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('12345', 1, 0 div 0)"), STR(""));
+ CHECK_XPATH_STRING(c, STR("substring('12345', -42, 1 div 0)"), STR("12345"));
+ CHECK_XPATH_STRING(c, STR("substring('12345', -1 div 0, 1 div 0)"), STR(""));
// substring with 4 arguments
- CHECK_XPATH_FAIL("substring('', 1, 2, 3)");
+ CHECK_XPATH_FAIL(STR("substring('', 1, 2, 3)"));
}
TEST_XML(xpath_string_string_length, "<node>123</node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// string-length with 0 arguments
- CHECK_XPATH_NUMBER(c, "string-length()", 0);
- CHECK_XPATH_NUMBER(n, "string-length()", 3);
+ CHECK_XPATH_NUMBER(c, STR("string-length()"), 0);
+ CHECK_XPATH_NUMBER(n, STR("string-length()"), 3);
// string-length with 1 argument
- CHECK_XPATH_NUMBER(c, "string-length('')", 0);
- CHECK_XPATH_NUMBER(c, "string-length('a')", 1);
- CHECK_XPATH_NUMBER(c, "string-length('abcdef')", 6);
+ CHECK_XPATH_NUMBER(c, STR("string-length('')"), 0);
+ CHECK_XPATH_NUMBER(c, STR("string-length('a')"), 1);
+ CHECK_XPATH_NUMBER(c, STR("string-length('abcdef')"), 6);
// string-length with 2 arguments
- CHECK_XPATH_FAIL("string-length(1, 2)");
+ CHECK_XPATH_FAIL(STR("string-length(1, 2)"));
}
TEST_XML_FLAGS(xpath_string_normalize_space, "<node> \t\r\rval1 \rval2\r\nval3\nval4\r\r</node>", parse_minimal)
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// normalize-space with 0 arguments
- CHECK_XPATH_STRING(c, "normalize-space()", "");
- CHECK_XPATH_STRING(n, "normalize-space()", "val1 val2 val3 val4");
+ CHECK_XPATH_STRING(c, STR("normalize-space()"), STR(""));
+ CHECK_XPATH_STRING(n, STR("normalize-space()"), STR("val1 val2 val3 val4"));
// normalize-space with 1 argument
- CHECK_XPATH_STRING(c, "normalize-space('')", "");
- CHECK_XPATH_STRING(c, "normalize-space('abcd')", "abcd");
- CHECK_XPATH_STRING(c, "normalize-space(' \r\nabcd')", "abcd");
- CHECK_XPATH_STRING(c, "normalize-space('abcd \n\r')", "abcd");
- CHECK_XPATH_STRING(c, "normalize-space('ab\r\n\tcd')", "ab cd");
- CHECK_XPATH_STRING(c, "normalize-space('ab cd')", "ab cd");
- CHECK_XPATH_STRING(c, "normalize-space('\07')", "\07");
+ CHECK_XPATH_STRING(c, STR("normalize-space('')"), STR(""));
+ CHECK_XPATH_STRING(c, STR("normalize-space('abcd')"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("normalize-space(' \r\nabcd')"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("normalize-space('abcd \n\r')"), STR("abcd"));
+ CHECK_XPATH_STRING(c, STR("normalize-space('ab\r\n\tcd')"), STR("ab cd"));
+ CHECK_XPATH_STRING(c, STR("normalize-space('ab cd')"), STR("ab cd"));
+ CHECK_XPATH_STRING(c, STR("normalize-space('\07')"), STR("\07"));
// normalize-space with 2 arguments
- CHECK_XPATH_FAIL("normalize-space(1, 2)");
+ CHECK_XPATH_FAIL(STR("normalize-space(1, 2)"));
}
TEST(xpath_string_translate)
@@ -476,180 +478,180 @@ TEST(xpath_string_translate)
xml_node c;
// translate with 0 arguments
- CHECK_XPATH_FAIL("translate()");
+ CHECK_XPATH_FAIL(STR("translate()"));
// translate with 1 argument
- CHECK_XPATH_FAIL("translate('a')");
+ CHECK_XPATH_FAIL(STR("translate('a')"));
// translate with 2 arguments
- CHECK_XPATH_FAIL("translate('a', 'b')");
+ CHECK_XPATH_FAIL(STR("translate('a', 'b')"));
// translate with 3 arguments
- CHECK_XPATH_STRING(c, "translate('abc', '', '')", "abc");
- CHECK_XPATH_STRING(c, "translate('abc', '', 'foo')", "abc");
- CHECK_XPATH_STRING(c, "translate('abc', 'ab', 'ba')", "bac");
- CHECK_XPATH_STRING(c, "translate('abc', 'ab', 'f')", "fc");
- CHECK_XPATH_STRING(c, "translate('abc', 'aabb', '1234')", "13c");
- CHECK_XPATH_STRING(c, "translate('', 'abc', 'bac')", "");
+ CHECK_XPATH_STRING(c, STR("translate('abc', '', '')"), STR("abc"));
+ CHECK_XPATH_STRING(c, STR("translate('abc', '', 'foo')"), STR("abc"));
+ CHECK_XPATH_STRING(c, STR("translate('abc', 'ab', 'ba')"), STR("bac"));
+ CHECK_XPATH_STRING(c, STR("translate('abc', 'ab', 'f')"), STR("fc"));
+ CHECK_XPATH_STRING(c, STR("translate('abc', 'aabb', '1234')"), STR("13c"));
+ CHECK_XPATH_STRING(c, STR("translate('', 'abc', 'bac')"), STR(""));
// translate with 3 arguments, from W3C standard
- CHECK_XPATH_STRING(c, "translate('bar','abc','ABC')", "BAr");
- CHECK_XPATH_STRING(c, "translate('--aaa--','abc-','ABC')", "AAA");
+ CHECK_XPATH_STRING(c, STR("translate('bar','abc','ABC')"), STR("BAr"));
+ CHECK_XPATH_STRING(c, STR("translate('--aaa--','abc-','ABC')"), STR("AAA"));
// translate with 4 arguments
- CHECK_XPATH_FAIL("translate('a', 'b', 'c', 'd')");
+ CHECK_XPATH_FAIL(STR("translate('a', 'b', 'c', 'd')"));
}
TEST_XML(xpath_nodeset_last, "<node><c1/><c1/><c2/><c3/><c3/><c3/><c3/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// last with 0 arguments
- CHECK_XPATH_NUMBER(n, "last()", 1);
- CHECK_XPATH_NODESET(n, "c1[last() = 1]");
- CHECK_XPATH_NODESET(n, "c1[last() = 2]") % 3 % 4; // c1, c1
- CHECK_XPATH_NODESET(n, "c2/preceding-sibling::node()[last() = 2]") % 4 % 3; // c1, c1
+ CHECK_XPATH_NUMBER(n, STR("last()"), 1);
+ CHECK_XPATH_NODESET(n, STR("c1[last() = 1]"));
+ CHECK_XPATH_NODESET(n, STR("c1[last() = 2]")) % 3 % 4; // c1, c1
+ CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[last() = 2]")) % 4 % 3; // c1, c1
// last with 1 argument
- CHECK_XPATH_FAIL("last(c)");
+ CHECK_XPATH_FAIL(STR("last(c)"));
}
TEST_XML(xpath_nodeset_position, "<node><c1/><c1/><c2/><c3/><c3/><c3/><c3/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// position with 0 arguments
- CHECK_XPATH_NUMBER(n, "position()", 1);
- CHECK_XPATH_NODESET(n, "c1[position() = 0]");
- CHECK_XPATH_NODESET(n, "c1[position() = 1]") % 3;
- CHECK_XPATH_NODESET(n, "c1[position() = 2]") % 4;
- CHECK_XPATH_NODESET(n, "c1[position() = 3]");
- CHECK_XPATH_NODESET(n, "c2/preceding-sibling::node()[position() = 1]") % 4;
- CHECK_XPATH_NODESET(n, "c2/preceding-sibling::node()[position() = 2]") % 3;
+ CHECK_XPATH_NUMBER(n, STR("position()"), 1);
+ CHECK_XPATH_NODESET(n, STR("c1[position() = 0]"));
+ CHECK_XPATH_NODESET(n, STR("c1[position() = 1]")) % 3;
+ CHECK_XPATH_NODESET(n, STR("c1[position() = 2]")) % 4;
+ CHECK_XPATH_NODESET(n, STR("c1[position() = 3]"));
+ CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[position() = 1]")) % 4;
+ CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[position() = 2]")) % 3;
// position with 1 argument
- CHECK_XPATH_FAIL("position(c)");
+ CHECK_XPATH_FAIL(STR("position(c)"));
}
TEST_XML(xpath_nodeset_count, "<node><c1/><c1/><c2/><c3/><c3/><c3/><c3/></node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// count with 0 arguments
- CHECK_XPATH_FAIL("count()");
+ CHECK_XPATH_FAIL(STR("count()"));
// count with 1 non-node-set argument
- CHECK_XPATH_FAIL("count(1)");
- CHECK_XPATH_FAIL("count(true())");
- CHECK_XPATH_FAIL("count('')");
+ CHECK_XPATH_FAIL(STR("count(1)"));
+ CHECK_XPATH_FAIL(STR("count(true())"));
+ CHECK_XPATH_FAIL(STR("count('')"));
// count with 1 node-set argument
- CHECK_XPATH_NUMBER(c, "count(.)", 0);
- CHECK_XPATH_NUMBER(n, "count(.)", 1);
- CHECK_XPATH_NUMBER(n, "count(c1)", 2);
- CHECK_XPATH_NUMBER(n, "count(c2)", 1);
- CHECK_XPATH_NUMBER(n, "count(c3)", 4);
- CHECK_XPATH_NUMBER(n, "count(c4)", 0);
+ CHECK_XPATH_NUMBER(c, STR("count(.)"), 0);
+ CHECK_XPATH_NUMBER(n, STR("count(.)"), 1);
+ CHECK_XPATH_NUMBER(n, STR("count(c1)"), 2);
+ CHECK_XPATH_NUMBER(n, STR("count(c2)"), 1);
+ CHECK_XPATH_NUMBER(n, STR("count(c3)"), 4);
+ CHECK_XPATH_NUMBER(n, STR("count(c4)"), 0);
// count with 2 arguments
- CHECK_XPATH_FAIL("count(x, y)");
+ CHECK_XPATH_FAIL(STR("count(x, y)"));
}
TEST_XML(xpath_nodeset_id, "<node id='foo'/>")
{
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// id with 0 arguments
- CHECK_XPATH_FAIL("id()");
+ CHECK_XPATH_FAIL(STR("id()"));
// id with 1 argument - no DTD => no id
- CHECK_XPATH_NODESET(n, "id('foo')");
+ CHECK_XPATH_NODESET(n, STR("id('foo')"));
// id with 2 arguments
- CHECK_XPATH_FAIL("id(1, 2)");
+ CHECK_XPATH_FAIL(STR("id(1, 2)"));
}
TEST_XML_FLAGS(xpath_nodeset_local_name, "<node xmlns:foo='http://foo'><c1>text</c1><c2 xmlns:foo='http://foo2' foo:attr='value'><foo:child/></c2><c3 xmlns='http://def' attr='value'><child/></c3><c4><?target stuff?></c4></node>", parse_default | parse_pi)
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// local-name with 0 arguments
- CHECK_XPATH_STRING(c, "local-name()", "");
- CHECK_XPATH_STRING(n, "local-name()", "node");
+ CHECK_XPATH_STRING(c, STR("local-name()"), STR(""));
+ CHECK_XPATH_STRING(n, STR("local-name()"), STR("node"));
// local-name with 1 non-node-set argument
- CHECK_XPATH_FAIL("local-name(1)");
+ CHECK_XPATH_FAIL(STR("local-name(1)"));
// local-name with 1 node-set argument
- CHECK_XPATH_STRING(n, "local-name(c1)", "c1");
- CHECK_XPATH_STRING(n, "local-name(c2/node())", "child");
- CHECK_XPATH_STRING(n, "local-name(c2/attribute::node())", "attr");
- CHECK_XPATH_STRING(n, "local-name(c1/node())", "");
- CHECK_XPATH_STRING(n, "local-name(c4/node())", "target");
- CHECK_XPATH_STRING(n, "local-name(c1/following-sibling::node())", "c2");
- CHECK_XPATH_STRING(n, "local-name(c4/preceding-sibling::node())", "c1");
+ CHECK_XPATH_STRING(n, STR("local-name(c1)"), STR("c1"));
+ CHECK_XPATH_STRING(n, STR("local-name(c2/node())"), STR("child"));
+ CHECK_XPATH_STRING(n, STR("local-name(c2/attribute::node())"), STR("attr"));
+ CHECK_XPATH_STRING(n, STR("local-name(c1/node())"), STR(""));
+ CHECK_XPATH_STRING(n, STR("local-name(c4/node())"), STR("target"));
+ CHECK_XPATH_STRING(n, STR("local-name(c1/following-sibling::node())"), STR("c2"));
+ CHECK_XPATH_STRING(n, STR("local-name(c4/preceding-sibling::node())"), STR("c1"));
// local-name with 2 arguments
- CHECK_XPATH_FAIL("local-name(c1, c2)");
+ CHECK_XPATH_FAIL(STR("local-name(c1, c2)"));
}
TEST_XML_FLAGS(xpath_nodeset_namespace_uri, "<node xmlns:foo='http://foo'><c1>text</c1><c2 xmlns:foo='http://foo2' foo:attr='value'><foo:child/></c2><c3 xmlns='http://def' attr='value'><child/></c3><c4><?target stuff?></c4><c5><foo:child/></c5><c6 bar:attr=''/></node>", parse_default | parse_pi)
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// namespace-uri with 0 arguments
- CHECK_XPATH_STRING(c, "namespace-uri()", "");
- CHECK_XPATH_STRING(n.child("c2").child("foo:child"), "namespace-uri()", "http://foo2");
+ CHECK_XPATH_STRING(c, STR("namespace-uri()"), STR(""));
+ CHECK_XPATH_STRING(n.child(STR("c2")).child(STR("foo:child")), STR("namespace-uri()"), STR("http://foo2"));
// namespace-uri with 1 non-node-set argument
- CHECK_XPATH_FAIL("namespace-uri(1)");
+ CHECK_XPATH_FAIL(STR("namespace-uri(1)"));
// namespace-uri with 1 node-set argument
- CHECK_XPATH_STRING(n, "namespace-uri(c1)", "");
- CHECK_XPATH_STRING(n, "namespace-uri(c5/child::node())", "http://foo");
- CHECK_XPATH_STRING(n, "namespace-uri(c2/attribute::node())", "http://foo2");
- CHECK_XPATH_STRING(n, "namespace-uri(c2/child::node())", "http://foo2");
- CHECK_XPATH_STRING(n, "namespace-uri(c1/child::node())", "");
- CHECK_XPATH_STRING(n, "namespace-uri(c4/child::node())", "");
- CHECK_XPATH_STRING(n, "namespace-uri(c3)", "http://def");
- CHECK_XPATH_STRING(n, "namespace-uri(c3/@attr)", ""); // the namespace name for an unprefixed attribute name always has no value (Namespaces in XML 1.0)
- CHECK_XPATH_STRING(n, "namespace-uri(c3/child::node())", "http://def");
- CHECK_XPATH_STRING(n, "namespace-uri(c6/@bar:attr)", "");
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c1)"), STR(""));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c5/child::node())"), STR("http://foo"));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c2/attribute::node())"), STR("http://foo2"));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c2/child::node())"), STR("http://foo2"));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c1/child::node())"), STR(""));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c4/child::node())"), STR(""));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c3)"), STR("http://def"));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c3/@attr)"), STR("")); // the namespace name for an unprefixed attribute name always has no value (Namespaces in XML 1.0)
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c3/child::node())"), STR("http://def"));
+ CHECK_XPATH_STRING(n, STR("namespace-uri(c6/@bar:attr)"), STR(""));
// namespace-uri with 2 arguments
- CHECK_XPATH_FAIL("namespace-uri(c1, c2)");
+ CHECK_XPATH_FAIL(STR("namespace-uri(c1, c2)"));
}
TEST_XML_FLAGS(xpath_nodeset_name, "<node xmlns:foo='http://foo'><c1>text</c1><c2 xmlns:foo='http://foo2' foo:attr='value'><foo:child/></c2><c3 xmlns='http://def' attr='value'><child/></c3><c4><?target stuff?></c4></node>", parse_default | parse_pi)
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// name with 0 arguments
- CHECK_XPATH_STRING(c, "name()", "");
- CHECK_XPATH_STRING(n, "name()", "node");
+ CHECK_XPATH_STRING(c, STR("name()"), STR(""));
+ CHECK_XPATH_STRING(n, STR("name()"), STR("node"));
// name with 1 non-node-set argument
- CHECK_XPATH_FAIL("name(1)");
+ CHECK_XPATH_FAIL(STR("name(1)"));
// name with 1 node-set argument
- CHECK_XPATH_STRING(n, "name(c1)", "c1");
- CHECK_XPATH_STRING(n, "name(c2/node())", "foo:child");
- CHECK_XPATH_STRING(n, "name(c2/attribute::node())", "foo:attr");
- CHECK_XPATH_STRING(n, "name(c1/node())", "");
- CHECK_XPATH_STRING(n, "name(c4/node())", "target");
- CHECK_XPATH_STRING(n, "name(c1/following-sibling::node())", "c2");
- CHECK_XPATH_STRING(n, "name(c4/preceding-sibling::node())", "c1");
+ CHECK_XPATH_STRING(n, STR("name(c1)"), STR("c1"));
+ CHECK_XPATH_STRING(n, STR("name(c2/node())"), STR("foo:child"));
+ CHECK_XPATH_STRING(n, STR("name(c2/attribute::node())"), STR("foo:attr"));
+ CHECK_XPATH_STRING(n, STR("name(c1/node())"), STR(""));
+ CHECK_XPATH_STRING(n, STR("name(c4/node())"), STR("target"));
+ CHECK_XPATH_STRING(n, STR("name(c1/following-sibling::node())"), STR("c2"));
+ CHECK_XPATH_STRING(n, STR("name(c4/preceding-sibling::node())"), STR("c1"));
// name with 2 arguments
- CHECK_XPATH_FAIL("name(c1, c2)");
+ CHECK_XPATH_FAIL(STR("name(c1, c2)"));
}
TEST(xpath_function_arguments)
@@ -657,56 +659,56 @@ TEST(xpath_function_arguments)
xml_node c;
// conversion to string
- CHECK_XPATH_NUMBER(c, "string-length(12)", 2);
+ CHECK_XPATH_NUMBER(c, STR("string-length(12)"), 2);
// conversion to number
- CHECK_XPATH_NUMBER(c, "round('1.2')", 1);
- CHECK_XPATH_NUMBER(c, "round('1.7')", 2);
+ CHECK_XPATH_NUMBER(c, STR("round('1.2')"), 1);
+ CHECK_XPATH_NUMBER(c, STR("round('1.7')"), 2);
// conversion to boolean
- CHECK_XPATH_BOOLEAN(c, "not('1')", false);
- CHECK_XPATH_BOOLEAN(c, "not('')", true);
+ CHECK_XPATH_BOOLEAN(c, STR("not('1')"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("not('')"), true);
// conversion to node set
- CHECK_XPATH_FAIL("sum(1)");
+ CHECK_XPATH_FAIL(STR("sum(1)"));
// expression evaluation
- CHECK_XPATH_NUMBER(c, "round((2 + 2 * 2) div 4)", 2);
+ CHECK_XPATH_NUMBER(c, STR("round((2 + 2 * 2) div 4)"), 2);
// empty expressions
- CHECK_XPATH_FAIL("round(,)");
- CHECK_XPATH_FAIL("substring(,)");
- CHECK_XPATH_FAIL("substring('a',)");
- CHECK_XPATH_FAIL("substring(,'a')");
+ CHECK_XPATH_FAIL(STR("round(,)"));
+ CHECK_XPATH_FAIL(STR("substring(,)"));
+ CHECK_XPATH_FAIL(STR("substring('a',)"));
+ CHECK_XPATH_FAIL(STR("substring(,'a')"));
// extra commas
- CHECK_XPATH_FAIL("round(,1)");
- CHECK_XPATH_FAIL("round(1,)");
+ CHECK_XPATH_FAIL(STR("round(,1)"));
+ CHECK_XPATH_FAIL(STR("round(1,)"));
// lack of commas
- CHECK_XPATH_FAIL("substring(1 2)");
+ CHECK_XPATH_FAIL(STR("substring(1 2)"));
// whitespace after function name
- CHECK_XPATH_BOOLEAN(c, "true ()", true);
+ CHECK_XPATH_BOOLEAN(c, STR("true ()"), true);
// too many arguments
- CHECK_XPATH_FAIL("round(1, 2, 3, 4, 5, 6)");
+ CHECK_XPATH_FAIL(STR("round(1, 2, 3, 4, 5, 6)"));
}
TEST_XML_FLAGS(xpath_string_value, "<node><c1>pcdata</c1><c2><child/></c2><c3 attr='avalue'/><c4><?target pivalue?></c4><c5><!--comment--></c5><c6><![CDATA[cdata]]></c6></node>", parse_default | parse_pi | parse_comments)
{
xml_node c;
- xml_node n = doc.child("node");
-
- CHECK_XPATH_STRING(c, "string()", "");
- CHECK_XPATH_STRING(doc, "string()", "pcdatacdata");
- CHECK_XPATH_STRING(n, "string()", "pcdatacdata");
- CHECK_XPATH_STRING(n, "string(c1/node())", "pcdata");
- CHECK_XPATH_STRING(n, "string(c2/node())", "");
- CHECK_XPATH_STRING(n, "string(c3/@attr)", "avalue");
- CHECK_XPATH_STRING(n, "string(c4/node())", "pivalue");
- CHECK_XPATH_STRING(n, "string(c5/node())", "comment");
- CHECK_XPATH_STRING(n, "string(c6/node())", "cdata");
+ xml_node n = doc.child(STR("node"));
+
+ CHECK_XPATH_STRING(c, STR("string()"), STR(""));
+ CHECK_XPATH_STRING(doc, STR("string()"), STR("pcdatacdata"));
+ CHECK_XPATH_STRING(n, STR("string()"), STR("pcdatacdata"));
+ CHECK_XPATH_STRING(n, STR("string(c1/node())"), STR("pcdata"));
+ CHECK_XPATH_STRING(n, STR("string(c2/node())"), STR(""));
+ CHECK_XPATH_STRING(n, STR("string(c3/@attr)"), STR("avalue"));
+ CHECK_XPATH_STRING(n, STR("string(c4/node())"), STR("pivalue"));
+ CHECK_XPATH_STRING(n, STR("string(c5/node())"), STR("comment"));
+ CHECK_XPATH_STRING(n, STR("string(c6/node())"), STR("cdata"));
}
#endif
diff --git a/tests/test_xpath_operators.cpp b/tests/test_xpath_operators.cpp
index 876e86a..79202a7 100644
--- a/tests/test_xpath_operators.cpp
+++ b/tests/test_xpath_operators.cpp
@@ -17,65 +17,65 @@
TEST_XML(xpath_operators_arithmetic, "<node><foo-bar>10</foo-bar><foo>2</foo><bar>3</bar></node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// incorrect unary operator
- CHECK_XPATH_FAIL("-");
+ CHECK_XPATH_FAIL(STR("-"));
// correct unary operator
- CHECK_XPATH_NUMBER(c, "-1", -1);
- CHECK_XPATH_NUMBER(c, "--1", 1);
- CHECK_XPATH_NUMBER(c, "---1", -1);
+ CHECK_XPATH_NUMBER(c, STR("-1"), -1);
+ CHECK_XPATH_NUMBER(c, STR("--1"), 1);
+ CHECK_XPATH_NUMBER(c, STR("---1"), -1);
// incorrect binary operators
- CHECK_XPATH_FAIL("5+");
- CHECK_XPATH_FAIL("5-");
- CHECK_XPATH_FAIL("5*");
- CHECK_XPATH_FAIL("+5");
- CHECK_XPATH_FAIL("*5");
- CHECK_XPATH_FAIL("1div2");
- CHECK_XPATH_FAIL("1mod");
- CHECK_XPATH_FAIL("1div");
+ CHECK_XPATH_FAIL(STR("5+"));
+ CHECK_XPATH_FAIL(STR("5-"));
+ CHECK_XPATH_FAIL(STR("5*"));
+ CHECK_XPATH_FAIL(STR("+5"));
+ CHECK_XPATH_FAIL(STR("*5"));
+ CHECK_XPATH_FAIL(STR("1div2"));
+ CHECK_XPATH_FAIL(STR("1mod"));
+ CHECK_XPATH_FAIL(STR("1div"));
// correct trivial binary operators
- CHECK_XPATH_NUMBER(c, "1 + 2", 3);
- CHECK_XPATH_NUMBER(c, "1+2", 3);
- CHECK_XPATH_NUMBER(c, "1 * 2", 2);
- CHECK_XPATH_NUMBER(c, "1*2", 2);
- CHECK_XPATH_NUMBER(c, "1 div 2", 0.5);
+ CHECK_XPATH_NUMBER(c, STR("1 + 2"), 3);
+ CHECK_XPATH_NUMBER(c, STR("1+2"), 3);
+ CHECK_XPATH_NUMBER(c, STR("1 * 2"), 2);
+ CHECK_XPATH_NUMBER(c, STR("1*2"), 2);
+ CHECK_XPATH_NUMBER(c, STR("1 div 2"), 0.5);
// operator precedence
- CHECK_XPATH_NUMBER(c, "2 + 2 * 2 div 1 mod 3", 3);
- CHECK_XPATH_NUMBER(c, "2 + 2 * 2 div (1 mod 3)", 6);
- CHECK_XPATH_NUMBER(c, "(2 + 2) * 2 div (1 mod 3)", 8);
- CHECK_XPATH_NUMBER(c, "(2 + 2) * (2 div 1) mod 3", 2);
- CHECK_XPATH_NUMBER(c, "2 - -2", 4);
- CHECK_XPATH_NUMBER(c, "2--2", 4);
- CHECK_XPATH_NUMBER(c, "1-2-3", -4);
+ CHECK_XPATH_NUMBER(c, STR("2 + 2 * 2 div 1 mod 3"), 3);
+ CHECK_XPATH_NUMBER(c, STR("2 + 2 * 2 div (1 mod 3)"), 6);
+ CHECK_XPATH_NUMBER(c, STR("(2 + 2) * 2 div (1 mod 3)"), 8);
+ CHECK_XPATH_NUMBER(c, STR("(2 + 2) * (2 div 1) mod 3"), 2);
+ CHECK_XPATH_NUMBER(c, STR("2 - -2"), 4);
+ CHECK_XPATH_NUMBER(c, STR("2--2"), 4);
+ CHECK_XPATH_NUMBER(c, STR("1-2-3"), -4);
// infinity/nan
- CHECK_XPATH_STRING(c, "1 div 0", "Infinity");
- CHECK_XPATH_STRING(c, "-1 div 0", "-Infinity");
- CHECK_XPATH_STRING(c, "-1 div 0 + 1 div 0", "NaN");
- CHECK_XPATH_STRING(c, "0 div 0", "NaN");
- CHECK_XPATH_STRING(c, "1 div 0 + 1 div 0", "Infinity");
- CHECK_XPATH_STRING(c, "-1 div 0 + -1 div 0", "-Infinity");
- CHECK_XPATH_STRING(c, "1 div 0 + 100", "Infinity");
- CHECK_XPATH_STRING(c, "-1 div 0 + 100", "-Infinity");
- CHECK_XPATH_STRING(c, "0 div 0 + 100", "NaN");
+ CHECK_XPATH_STRING(c, STR("1 div 0"), STR("Infinity"));
+ CHECK_XPATH_STRING(c, STR("-1 div 0"), STR("-Infinity"));
+ CHECK_XPATH_STRING(c, STR("-1 div 0 + 1 div 0"), STR("NaN"));
+ CHECK_XPATH_STRING(c, STR("0 div 0"), STR("NaN"));
+ CHECK_XPATH_STRING(c, STR("1 div 0 + 1 div 0"), STR("Infinity"));
+ CHECK_XPATH_STRING(c, STR("-1 div 0 + -1 div 0"), STR("-Infinity"));
+ CHECK_XPATH_STRING(c, STR("1 div 0 + 100"), STR("Infinity"));
+ CHECK_XPATH_STRING(c, STR("-1 div 0 + 100"), STR("-Infinity"));
+ CHECK_XPATH_STRING(c, STR("0 div 0 + 100"), STR("NaN"));
// mod, from W3C standard
- CHECK_XPATH_NUMBER(c, "5 mod 2", 1);
- CHECK_XPATH_NUMBER(c, "5 mod -2", 1);
- CHECK_XPATH_NUMBER(c, "-5 mod 2", -1);
- CHECK_XPATH_NUMBER(c, "-5 mod -2", -1);
+ CHECK_XPATH_NUMBER(c, STR("5 mod 2"), 1);
+ CHECK_XPATH_NUMBER(c, STR("5 mod -2"), 1);
+ CHECK_XPATH_NUMBER(c, STR("-5 mod 2"), -1);
+ CHECK_XPATH_NUMBER(c, STR("-5 mod -2"), -1);
// correct subtraction parsing, from W3C standard
- CHECK_XPATH_NUMBER(n, "foo-bar", 10);
- CHECK_XPATH_NUMBER(n, "foo -bar", -1);
- CHECK_XPATH_NUMBER(n, "foo - bar", -1);
- CHECK_XPATH_NUMBER(n, "-foo-bar", -10);
- CHECK_XPATH_NUMBER(n, "-foo -bar", -5);
+ CHECK_XPATH_NUMBER(n, STR("foo-bar"), 10);
+ CHECK_XPATH_NUMBER(n, STR("foo -bar"), -1);
+ CHECK_XPATH_NUMBER(n, STR("foo - bar"), -1);
+ CHECK_XPATH_NUMBER(n, STR("-foo-bar"), -10);
+ CHECK_XPATH_NUMBER(n, STR("-foo -bar"), -5);
}
TEST(xpath_operators_logical)
@@ -83,21 +83,21 @@ TEST(xpath_operators_logical)
xml_node c;
// boolean arithmetic
- CHECK_XPATH_BOOLEAN(c, "true() or true()", true);
- CHECK_XPATH_BOOLEAN(c, "true() or false()", true);
- CHECK_XPATH_BOOLEAN(c, "false() or false()", false);
- CHECK_XPATH_BOOLEAN(c, "false() or true()", true);
-
- CHECK_XPATH_BOOLEAN(c, "true() and true()", true);
- CHECK_XPATH_BOOLEAN(c, "true() and false()", false);
- CHECK_XPATH_BOOLEAN(c, "false() and false()", false);
- CHECK_XPATH_BOOLEAN(c, "false() and true()", false);
+ CHECK_XPATH_BOOLEAN(c, STR("true() or true()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("true() or false()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("false() or false()"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("false() or true()"), true);
+
+ CHECK_XPATH_BOOLEAN(c, STR("true() and true()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("true() and false()"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("false() and false()"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("false() and true()"), false);
// boolean conversion
- CHECK_XPATH_BOOLEAN(c, "1 or ''", true);
- CHECK_XPATH_BOOLEAN(c, "1 and ''", false);
- CHECK_XPATH_BOOLEAN(c, "0 or ''", false);
- CHECK_XPATH_BOOLEAN(c, "0 or 'a'", true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 or ''"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 and ''"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 or ''"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 or 'a'"), true);
}
TEST(xpath_operators_equality_primitive_boolean)
@@ -105,25 +105,25 @@ TEST(xpath_operators_equality_primitive_boolean)
xml_node c;
// boolean vs boolan
- CHECK_XPATH_BOOLEAN(c, "true() = true()", true);
- CHECK_XPATH_BOOLEAN(c, "false() = false()", true);
- CHECK_XPATH_BOOLEAN(c, "true() != false()", true);
- CHECK_XPATH_BOOLEAN(c, "false() != false()", false);
+ CHECK_XPATH_BOOLEAN(c, STR("true() = true()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("false() = false()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("true() != false()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("false() != false()"), false);
// upcast to boolean
- CHECK_XPATH_BOOLEAN(c, "true() = 2", true);
- CHECK_XPATH_BOOLEAN(c, "true() != 2", false);
- CHECK_XPATH_BOOLEAN(c, "false() = 2", false);
- CHECK_XPATH_BOOLEAN(c, "false() != 2", true);
- CHECK_XPATH_BOOLEAN(c, "false() = 0", true);
- CHECK_XPATH_BOOLEAN(c, "false() != 0", false);
-
- CHECK_XPATH_BOOLEAN(c, "2 = true()", true);
- CHECK_XPATH_BOOLEAN(c, "2 != true()", false);
- CHECK_XPATH_BOOLEAN(c, "2 = false()", false);
- CHECK_XPATH_BOOLEAN(c, "2 != false()", true);
- CHECK_XPATH_BOOLEAN(c, "0 = false()", true);
- CHECK_XPATH_BOOLEAN(c, "0 != false()", false);
+ CHECK_XPATH_BOOLEAN(c, STR("true() = 2"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("true() != 2"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("false() = 2"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("false() != 2"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("false() = 0"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("false() != 0"), false);
+
+ CHECK_XPATH_BOOLEAN(c, STR("2 = true()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("2 != true()"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("2 = false()"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("2 != false()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("0 = false()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("0 != false()"), false);
}
TEST(xpath_operators_equality_primitive_number)
@@ -131,26 +131,26 @@ TEST(xpath_operators_equality_primitive_number)
xml_node c;
// number vs number
- CHECK_XPATH_BOOLEAN(c, "1 = 1", true);
- CHECK_XPATH_BOOLEAN(c, "0.5 = 0.5", true);
- CHECK_XPATH_BOOLEAN(c, "1 != 2", true);
- CHECK_XPATH_BOOLEAN(c, "1 = -1", false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 = 1"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("0.5 = 0.5"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 != 2"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 = -1"), false);
// infinity/nan
- CHECK_XPATH_BOOLEAN(c, "1 div 0 = 2 div 0", true);
- CHECK_XPATH_BOOLEAN(c, "-1 div 0 != 2 div 0", true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 div 0 = 2 div 0"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("-1 div 0 != 2 div 0"), true);
#ifndef MSVC6_NAN_BUG
- CHECK_XPATH_BOOLEAN(c, "0 div 0 = 1", false);
- CHECK_XPATH_BOOLEAN(c, "0 div 0 != 1", true);
- CHECK_XPATH_BOOLEAN(c, "0 div 0 = 0 div 0", false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 div 0 = 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 div 0 != 1"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("0 div 0 = 0 div 0"), false);
#endif
// upcast to number
- CHECK_XPATH_BOOLEAN(c, "2 = '2'", true);
- CHECK_XPATH_BOOLEAN(c, "2 != '2'", false);
- CHECK_XPATH_BOOLEAN(c, "'1' != 2", true);
- CHECK_XPATH_BOOLEAN(c, "'1' = 2", false);
+ CHECK_XPATH_BOOLEAN(c, STR("2 = '2'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("2 != '2'"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("'1' != 2"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("'1' = 2"), false);
}
TEST(xpath_operators_equality_primitive_string)
@@ -158,104 +158,104 @@ TEST(xpath_operators_equality_primitive_string)
xml_node c;
// string vs string
- CHECK_XPATH_BOOLEAN(c, "'a' = 'a'", true);
- CHECK_XPATH_BOOLEAN(c, "'a' = 'b'", false);
- CHECK_XPATH_BOOLEAN(c, "'ab' != 'a'", true);
- CHECK_XPATH_BOOLEAN(c, "'' != 'a'", true);
- CHECK_XPATH_BOOLEAN(c, "'a' != ''", true);
- CHECK_XPATH_BOOLEAN(c, "'' != ''", false);
+ CHECK_XPATH_BOOLEAN(c, STR("'a' = 'a'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("'a' = 'b'"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("'ab' != 'a'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("'' != 'a'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("'a' != ''"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("'' != ''"), false);
}
TEST_XML(xpath_operators_equality_node_set_node_set, "<node><c1><v>a</v><v>b</v></c1><c2><v>a</v><v>c</v></c2><c3><v>b</v></c3><c4><v>d</v></c4><c5><v>a</v><v>b</v></c5><c6><v>b</v></c6></node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// node set vs node set
- CHECK_XPATH_BOOLEAN(c, "x = x", false); // empty node set compares as false with any other object via any comparison operator, as per XPath spec
- CHECK_XPATH_BOOLEAN(c, "x != x", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v = c2/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v = c3/v", true);
- CHECK_XPATH_BOOLEAN(n, "c2/v = c3/v", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v = c4/v", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v = x", false);
- CHECK_XPATH_BOOLEAN(n, "x = c1", false);
-
- CHECK_XPATH_BOOLEAN(n, "c1/v != c2/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v != c3/v", true);
- CHECK_XPATH_BOOLEAN(n, "c2/v != c3/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v != c4/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v != c5/v", true); // (a, b) != (a, b), since a != b, as per XPath spec (comparison operators are so not intutive)
- CHECK_XPATH_BOOLEAN(n, "c3/v != c6/v", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v != x", false);
- CHECK_XPATH_BOOLEAN(n, "x != c1/v", false);
+ CHECK_XPATH_BOOLEAN(c, STR("x = x"), false); // empty node set compares as false with any other object via any comparison operator, as per XPath spec
+ CHECK_XPATH_BOOLEAN(c, STR("x != x"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = c2/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = c3/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v = c3/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = c4/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = x"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("x = c1"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != c2/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != c3/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v != c3/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != c4/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != c5/v"), true); // (a, b) != (a, b), since a != b, as per XPath spec (comparison operators are so not intutive)
+ CHECK_XPATH_BOOLEAN(n, STR("c3/v != c6/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != x"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("x != c1/v"), false);
}
TEST_XML(xpath_operators_equality_node_set_primitive, "<node><c1><v>1</v><v>-1</v><v>100</v></c1><c2><v>1</v><v>nan</v></c2></node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// node set vs number
- CHECK_XPATH_BOOLEAN(c, "x = 1", false);
- CHECK_XPATH_BOOLEAN(c, "x != 1", false);
- CHECK_XPATH_BOOLEAN(c, "1 = x", false);
- CHECK_XPATH_BOOLEAN(c, "1 != x", false);
-
- CHECK_XPATH_BOOLEAN(n, "c1/v = 1", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v = -1", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v != 1", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v = 5", false);
- CHECK_XPATH_BOOLEAN(n, "c2/v = 1", true);
-
- CHECK_XPATH_BOOLEAN(n, "1 = c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "-1 = c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "1 != c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "5 = c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "1 = c2/v", true);
+ CHECK_XPATH_BOOLEAN(c, STR("x = 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x != 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 = x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 != x"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = 1"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = -1"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != 1"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = 5"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v = 1"), true);
+
+ CHECK_XPATH_BOOLEAN(n, STR("1 = c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("-1 = c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("1 != c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("5 = c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("1 = c2/v"), true);
#ifndef MSVC6_NAN_BUG
- CHECK_XPATH_BOOLEAN(n, "c2/v != 1", true);
- CHECK_XPATH_BOOLEAN(n, "1 != c2/v", true);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v != 1"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("1 != c2/v"), true);
#endif
// node set vs string
- CHECK_XPATH_BOOLEAN(c, "x = '1'", false);
- CHECK_XPATH_BOOLEAN(c, "x != '1'", false);
- CHECK_XPATH_BOOLEAN(c, "'1' = x", false);
- CHECK_XPATH_BOOLEAN(c, "'1' != x", false);
-
- CHECK_XPATH_BOOLEAN(n, "c1/v = '1'", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v = '-1'", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v != '1'", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v = '5'", false);
- CHECK_XPATH_BOOLEAN(n, "c2/v = '1'", true);
- CHECK_XPATH_BOOLEAN(n, "c2/v != '1'", true);
-
- CHECK_XPATH_BOOLEAN(n, "'1' = c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "'-1' = c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "'1' != c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "'5' = c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "'1' = c2/v", true);
- CHECK_XPATH_BOOLEAN(n, "'1' != c2/v", true);
+ CHECK_XPATH_BOOLEAN(c, STR("x = '1'"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x != '1'"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("'1' = x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("'1' != x"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = '1'"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = '-1'"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != '1'"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = '5'"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v = '1'"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v != '1'"), true);
+
+ CHECK_XPATH_BOOLEAN(n, STR("'1' = c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("'-1' = c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("'1' != c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("'5' = c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("'1' = c2/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("'1' != c2/v"), true);
// node set vs almost-numeric string just in case
- CHECK_XPATH_BOOLEAN(n, "c1/v = '1.0'", false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = '1.0'"), false);
// node set vs boolean - special rules! empty sets are equal to true()
- CHECK_XPATH_BOOLEAN(n, "x = true()", false);
- CHECK_XPATH_BOOLEAN(n, "x != true()", true);
- CHECK_XPATH_BOOLEAN(n, "x = false()", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v = true()", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v != true()", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v = false()", false);
-
- CHECK_XPATH_BOOLEAN(n, "true() = x", false);
- CHECK_XPATH_BOOLEAN(n, "true() != x", true);
- CHECK_XPATH_BOOLEAN(n, "false() = x", true);
- CHECK_XPATH_BOOLEAN(n, "true() = c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "true() != c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "false() = c1/v", false);
+ CHECK_XPATH_BOOLEAN(n, STR("x = true()"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("x != true()"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("x = false()"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = true()"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v != true()"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v = false()"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("true() = x"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("true() != x"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("false() = x"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("true() = c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("true() != c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("false() = c1/v"), false);
}
TEST(xpath_operators_inequality_primitive)
@@ -263,143 +263,143 @@ TEST(xpath_operators_inequality_primitive)
xml_node c;
// number vs number
- CHECK_XPATH_BOOLEAN(c, "1 < 2", true);
- CHECK_XPATH_BOOLEAN(c, "1 <= 2", true);
- CHECK_XPATH_BOOLEAN(c, "1 > 2", false);
- CHECK_XPATH_BOOLEAN(c, "1 >= 2", false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 < 2"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 <= 2"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 > 2"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 >= 2"), false);
- CHECK_XPATH_BOOLEAN(c, "1 < 1", false);
- CHECK_XPATH_BOOLEAN(c, "1 <= 1", true);
- CHECK_XPATH_BOOLEAN(c, "1 > 1", false);
- CHECK_XPATH_BOOLEAN(c, "1 >= 1", true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 < 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 <= 1"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 > 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 >= 1"), true);
// infinity/nan
- CHECK_XPATH_BOOLEAN(c, "1 div 0 <= 2 div 0", true);
- CHECK_XPATH_BOOLEAN(c, "1 div 0 < 2 div 0", false);
- CHECK_XPATH_BOOLEAN(c, "-1 div 0 < 2 div 0", true);
- CHECK_XPATH_BOOLEAN(c, "-1 div 0 > 2 div 0", false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 div 0 <= 2 div 0"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 div 0 < 2 div 0"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("-1 div 0 < 2 div 0"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("-1 div 0 > 2 div 0"), false);
#ifndef MSVC6_NAN_BUG
- CHECK_XPATH_BOOLEAN(c, "0 div 0 < 1", false);
- CHECK_XPATH_BOOLEAN(c, "0 div 0 <= 1", false);
- CHECK_XPATH_BOOLEAN(c, "0 div 0 > 1", false);
- CHECK_XPATH_BOOLEAN(c, "0 div 0 >= 1", false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 div 0 < 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 div 0 <= 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 div 0 > 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 div 0 >= 1"), false);
#endif
// upcast to number
- CHECK_XPATH_BOOLEAN(c, "2 < '2'", false);
- CHECK_XPATH_BOOLEAN(c, "1 < '2'", true);
- CHECK_XPATH_BOOLEAN(c, "2 <= '2'", true);
- CHECK_XPATH_BOOLEAN(c, "3 <= '2'", false);
- CHECK_XPATH_BOOLEAN(c, "2 > '2'", false);
- CHECK_XPATH_BOOLEAN(c, "3 > '2'", true);
- CHECK_XPATH_BOOLEAN(c, "2 >= '2'", true);
- CHECK_XPATH_BOOLEAN(c, "3 >= '2'", true);
- CHECK_XPATH_BOOLEAN(c, "1 >= true()", true);
- CHECK_XPATH_BOOLEAN(c, "1 > true()", false);
+ CHECK_XPATH_BOOLEAN(c, STR("2 < '2'"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 < '2'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("2 <= '2'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("3 <= '2'"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("2 > '2'"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("3 > '2'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("2 >= '2'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("3 >= '2'"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 >= true()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 > true()"), false);
}
TEST_XML(xpath_operators_inequality_node_set_node_set, "<node><c1><v>1</v><v>-1</v><v>-100</v></c1><c2><v>1</v><v>nan</v></c2><c3><v>1</v><v>-4</v></c3></node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// node set vs node set
- CHECK_XPATH_BOOLEAN(c, "x < x", false);
- CHECK_XPATH_BOOLEAN(c, "x > x", false);
- CHECK_XPATH_BOOLEAN(c, "x <= x", false);
- CHECK_XPATH_BOOLEAN(c, "x >= x", false);
-
- CHECK_XPATH_BOOLEAN(n, "c1/v > x", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v < x", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v >= x", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v <= x", false);
-
- CHECK_XPATH_BOOLEAN(n, "x > c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "x < c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "x >= c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "x <= c1/v", false);
-
- CHECK_XPATH_BOOLEAN(n, "c1/v > c3/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v >= c3/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v < c3/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v <= c3/v", true);
+ CHECK_XPATH_BOOLEAN(c, STR("x < x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x > x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x <= x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x >= x"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > x"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v < x"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v >= x"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v <= x"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("x > c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("x < c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("x >= c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("x <= c1/v"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > c3/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v >= c3/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v < c3/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v <= c3/v"), true);
#ifndef MSVC6_NAN_BUG
- CHECK_XPATH_BOOLEAN(n, "c1/v > c2/v", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v >= c2/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v < c2/v", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v <= c2/v", true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > c2/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v >= c2/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v < c2/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v <= c2/v"), true);
#endif
}
TEST_XML(xpath_operators_inequality_node_set_primitive, "<node><c1><v>1</v><v>-1</v><v>-100</v></c1><c2><v>1</v><v>nan</v></c2></node>")
{
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// node set vs number
- CHECK_XPATH_BOOLEAN(c, "x < 0", false);
- CHECK_XPATH_BOOLEAN(c, "x > 0", false);
- CHECK_XPATH_BOOLEAN(c, "x <= 0", false);
- CHECK_XPATH_BOOLEAN(c, "x >= 0", false);
-
- CHECK_XPATH_BOOLEAN(c, "0 < x", false);
- CHECK_XPATH_BOOLEAN(c, "0 > x", false);
- CHECK_XPATH_BOOLEAN(c, "0 <= x", false);
- CHECK_XPATH_BOOLEAN(c, "0 >= x", false);
-
- CHECK_XPATH_BOOLEAN(n, "c1/v > 0", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v > 1", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v >= 0", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v < 0", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v <= 0", true);
-
- CHECK_XPATH_BOOLEAN(n, "0 < c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "1 < c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "0 <= c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "0 > c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "0 >= c1/v", true);
+ CHECK_XPATH_BOOLEAN(c, STR("x < 0"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x > 0"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x <= 0"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("x >= 0"), false);
+
+ CHECK_XPATH_BOOLEAN(c, STR("0 < x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 > x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 <= x"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("0 >= x"), false);
+
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > 0"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > 1"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v >= 0"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v < 0"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v <= 0"), true);
+
+ CHECK_XPATH_BOOLEAN(n, STR("0 < c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("1 < c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("0 <= c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("0 > c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("0 >= c1/v"), true);
// node set vs string
- CHECK_XPATH_BOOLEAN(n, "c1/v > '0'", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v > '1'", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v >= '0'", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v < '0'", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v <= '0'", true);
-
- CHECK_XPATH_BOOLEAN(n, "'0' < c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "'1' < c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "'0' <= c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "'0' > c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "'0' >= c1/v", true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > '0'"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > '1'"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v >= '0'"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v < '0'"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v <= '0'"), true);
+
+ CHECK_XPATH_BOOLEAN(n, STR("'0' < c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("'1' < c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("'0' <= c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("'0' > c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("'0' >= c1/v"), true);
// node set vs boolean
- CHECK_XPATH_BOOLEAN(n, "c1/v > false()", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v > true()", false);
- CHECK_XPATH_BOOLEAN(n, "c1/v >= false()", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v < false()", true);
- CHECK_XPATH_BOOLEAN(n, "c1/v <= false()", true);
-
- CHECK_XPATH_BOOLEAN(n, "false() < c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "true() < c1/v", false);
- CHECK_XPATH_BOOLEAN(n, "false() <= c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "false() > c1/v", true);
- CHECK_XPATH_BOOLEAN(n, "false() >= c1/v", true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > false()"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v > true()"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v >= false()"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v < false()"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v <= false()"), true);
+
+ CHECK_XPATH_BOOLEAN(n, STR("false() < c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("true() < c1/v"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("false() <= c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("false() > c1/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("false() >= c1/v"), true);
}
TEST(xpath_operators_boolean_precedence)
{
xml_node c;
- CHECK_XPATH_BOOLEAN(c, "1 = 0 or 2 = 2", true);
- CHECK_XPATH_BOOLEAN(c, "1 = (0 or 2) = false()", false);
- CHECK_XPATH_BOOLEAN(c, "1 < 0 or 2 > 2", false);
- CHECK_XPATH_BOOLEAN(c, "2 < 1 = false()", true);
- CHECK_XPATH_BOOLEAN(c, "2 < (1 = false())", false);
- CHECK_XPATH_BOOLEAN(c, "3 > 2 > 1", false);
- CHECK_XPATH_BOOLEAN(c, "(3 > 2) > 1", false);
- CHECK_XPATH_BOOLEAN(c, "3 > (2 > 1)", true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 = 0 or 2 = 2"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("1 = (0 or 2) = false()"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("1 < 0 or 2 > 2"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("2 < 1 = false()"), true);
+ CHECK_XPATH_BOOLEAN(c, STR("2 < (1 = false())"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("3 > 2 > 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("(3 > 2) > 1"), false);
+ CHECK_XPATH_BOOLEAN(c, STR("3 > (2 > 1)"), true);
}
TEST_XML(xpath_operators_union, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/><tail/></node>")
@@ -407,15 +407,15 @@ TEST_XML(xpath_operators_union, "<node><employee/><employee secretary=''/><emplo
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
-
- CHECK_XPATH_NODESET(n, "employee | .") % 2 % 3 % 4 % 6 % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@secretary] | employee[@assistant]") % 4 % 6 % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@assistant] | employee[@secretary]") % 4 % 6 % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@secretary] | employee[@nobody]") % 4 % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@nobody] | employee[@secretary]") % 4 % 8 % 11;
- CHECK_XPATH_NODESET(n, "tail/preceding-sibling::employee | .") % 2 % 3 % 4 % 6 % 8 % 11;
- CHECK_XPATH_NODESET(n, ". | tail/preceding-sibling::employee | .") % 2 % 3 % 4 % 6 % 8 % 11;
+ xml_node n = doc.child(STR("node"));
+
+ CHECK_XPATH_NODESET(n, STR("employee | .")) % 2 % 3 % 4 % 6 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@secretary] | employee[@assistant]")) % 4 % 6 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@assistant] | employee[@secretary]")) % 4 % 6 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@secretary] | employee[@nobody]")) % 4 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@nobody] | employee[@secretary]")) % 4 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("tail/preceding-sibling::employee | .")) % 2 % 3 % 4 % 6 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR(". | tail/preceding-sibling::employee | .")) % 2 % 3 % 4 % 6 % 8 % 11;
}
#endif
diff --git a/tests/test_xpath_parse.cpp b/tests/test_xpath_parse.cpp
index 8eee552..6dcd02b 100644
--- a/tests/test_xpath_parse.cpp
+++ b/tests/test_xpath_parse.cpp
@@ -5,88 +5,88 @@
TEST(xpath_literal_parse)
{
xml_node c;
- CHECK_XPATH_STRING(c, "'a\"b'", "a\"b");
- CHECK_XPATH_STRING(c, "\"a'b\"", "a'b");
- CHECK_XPATH_STRING(c, "\"\"", "");
- CHECK_XPATH_STRING(c, "\'\'", "");
+ CHECK_XPATH_STRING(c, STR("'a\"b'"), STR("a\"b"));
+ CHECK_XPATH_STRING(c, STR("\"a'b\""), STR("a'b"));
+ CHECK_XPATH_STRING(c, STR("\"\""), STR(""));
+ CHECK_XPATH_STRING(c, STR("\'\'"), STR(""));
}
TEST(xpath_literal_error)
{
- CHECK_XPATH_FAIL("\"");
- CHECK_XPATH_FAIL("\'");
+ CHECK_XPATH_FAIL(STR("\""));
+ CHECK_XPATH_FAIL(STR("\'"));
}
TEST(xpath_number_parse)
{
xml_node c;
- CHECK_XPATH_NUMBER(c, "0", 0);
- CHECK_XPATH_NUMBER(c, "123", 123);
- CHECK_XPATH_NUMBER(c, "123.456", 123.456);
- CHECK_XPATH_NUMBER(c, ".123", 0.123);
- CHECK_XPATH_NUMBER(c, "123.4567890123456789012345", 123.4567890123456789012345);
+ CHECK_XPATH_NUMBER(c, STR("0"), 0);
+ CHECK_XPATH_NUMBER(c, STR("123"), 123);
+ CHECK_XPATH_NUMBER(c, STR("123.456"), 123.456);
+ CHECK_XPATH_NUMBER(c, STR(".123"), 0.123);
+ CHECK_XPATH_NUMBER(c, STR("123.4567890123456789012345"), 123.4567890123456789012345);
}
TEST(xpath_number_error)
{
- CHECK_XPATH_FAIL("123a");
- CHECK_XPATH_FAIL("123.a");
- CHECK_XPATH_FAIL(".123a");
+ CHECK_XPATH_FAIL(STR("123a"));
+ CHECK_XPATH_FAIL(STR("123.a"));
+ CHECK_XPATH_FAIL(STR(".123a"));
}
TEST(xpath_variables)
{
- CHECK_XPATH_FAIL("$var"); // not implemented
- CHECK_XPATH_FAIL("$1");
+ CHECK_XPATH_FAIL(STR("$var")); // not implemented
+ CHECK_XPATH_FAIL(STR("$1"));
}
TEST(xpath_empty_expression)
{
- CHECK_XPATH_FAIL("");
+ CHECK_XPATH_FAIL(STR(""));
}
TEST(xpath_lexer_error)
{
- CHECK_XPATH_FAIL("!");
- CHECK_XPATH_FAIL("&");
+ CHECK_XPATH_FAIL(STR("!"));
+ CHECK_XPATH_FAIL(STR("&"));
}
TEST(xpath_unmatched_braces)
{
- CHECK_XPATH_FAIL("node[");
- CHECK_XPATH_FAIL("node[1");
- CHECK_XPATH_FAIL("node[]]");
- CHECK_XPATH_FAIL("node(");
- CHECK_XPATH_FAIL("node(()");
- CHECK_XPATH_FAIL("(node)[1");
- CHECK_XPATH_FAIL("(1");
+ CHECK_XPATH_FAIL(STR("node["));
+ CHECK_XPATH_FAIL(STR("node[1"));
+ CHECK_XPATH_FAIL(STR("node[]]"));
+ CHECK_XPATH_FAIL(STR("node("));
+ CHECK_XPATH_FAIL(STR("node(()"));
+ CHECK_XPATH_FAIL(STR("(node)[1"));
+ CHECK_XPATH_FAIL(STR("(1"));
}
TEST(xpath_incorrect_step)
{
- CHECK_XPATH_FAIL("child::1");
- CHECK_XPATH_FAIL("something::*");
- CHECK_XPATH_FAIL("a::*");
- CHECK_XPATH_FAIL("c::*");
- CHECK_XPATH_FAIL("d::*");
- CHECK_XPATH_FAIL("f::*");
- CHECK_XPATH_FAIL("n::*");
- CHECK_XPATH_FAIL("p::*");
+ CHECK_XPATH_FAIL(STR("child::1"));
+ CHECK_XPATH_FAIL(STR("something::*"));
+ CHECK_XPATH_FAIL(STR("a::*"));
+ CHECK_XPATH_FAIL(STR("c::*"));
+ CHECK_XPATH_FAIL(STR("d::*"));
+ CHECK_XPATH_FAIL(STR("f::*"));
+ CHECK_XPATH_FAIL(STR("n::*"));
+ CHECK_XPATH_FAIL(STR("p::*"));
}
TEST(xpath_semantics_error)
{
- CHECK_XPATH_FAIL("1[1]");
- CHECK_XPATH_FAIL("1 | 1");
+ CHECK_XPATH_FAIL(STR("1[1]"));
+ CHECK_XPATH_FAIL(STR("1 | 1"));
}
TEST(xpath_semantics_posinv) // coverage for contains()
{
- xpath_query("(node)[substring(1, 2, 3)]");
- xpath_query("(node)[concat(1, 2, 3, 4)]");
- xpath_query("(node)[count(foo)]");
- xpath_query("(node)[local-name()]");
- xpath_query("(node)[(node)[1]]");
+ xpath_query(STR("(node)[substring(1, 2, 3)]"));
+ xpath_query(STR("(node)[concat(1, 2, 3, 4)]"));
+ xpath_query(STR("(node)[count(foo)]"));
+ xpath_query(STR("(node)[local-name()]"));
+ xpath_query(STR("(node)[(node)[1]]"));
}
#endif
diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp
index d64fdc6..47ebada 100644
--- a/tests/test_xpath_paths.cpp
+++ b/tests/test_xpath_paths.cpp
@@ -7,12 +7,12 @@ TEST_XML(xpath_paths_axes_child, "<node attr='value'><child attr='value'><subchi
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child:: node()");
+ CHECK_XPATH_NODESET(c, STR("child:: node()"));
- CHECK_XPATH_NODESET(n, "child:: node()") % 4 % 7 % 8; // child, another, last
- CHECK_XPATH_NODESET(n, "another/child:: node()");
+ CHECK_XPATH_NODESET(n, STR("child:: node()")) % 4 % 7 % 8; // child, another, last
+ CHECK_XPATH_NODESET(n, STR("another/child:: node()"));
}
TEST_XML(xpath_paths_axes_descendant, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -20,14 +20,14 @@ TEST_XML(xpath_paths_axes_descendant, "<node attr='value'><child attr='value'><s
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "descendant:: node()");
+ CHECK_XPATH_NODESET(c, STR("descendant:: node()"));
- CHECK_XPATH_NODESET(n, "descendant:: node()") % 4 % 6 % 7 % 8 % 9; // child, subchild, another, subchild, last
- CHECK_XPATH_NODESET(doc, "descendant:: node()") % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
- CHECK_XPATH_NODESET(n, "another/descendant:: node()") % 8; // subchild
- CHECK_XPATH_NODESET(n, "last/descendant:: node()");
+ CHECK_XPATH_NODESET(n, STR("descendant:: node()")) % 4 % 6 % 7 % 8 % 9; // child, subchild, another, subchild, last
+ CHECK_XPATH_NODESET(doc, STR("descendant:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
+ CHECK_XPATH_NODESET(n, STR("another/descendant:: node()")) % 8; // subchild
+ CHECK_XPATH_NODESET(n, STR("last/descendant:: node()"));
}
TEST_XML(xpath_paths_axes_parent, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -35,15 +35,15 @@ TEST_XML(xpath_paths_axes_parent, "<node attr='value'><child attr='value'><subch
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "parent:: node()");
+ CHECK_XPATH_NODESET(c, STR("parent:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "parent:: node()") % 2; // node
- CHECK_XPATH_NODESET(n, "child/subchild/parent:: node()") % 4; // child
- CHECK_XPATH_NODESET(n, "@attr/parent:: node()") % 2; // node
- CHECK_XPATH_NODESET(n, "parent:: node()") % 1; // root
- CHECK_XPATH_NODESET(doc, "parent:: node()");
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("parent:: node()")) % 2; // node
+ CHECK_XPATH_NODESET(n, STR("child/subchild/parent:: node()")) % 4; // child
+ CHECK_XPATH_NODESET(n, STR("@attr/parent:: node()")) % 2; // node
+ CHECK_XPATH_NODESET(n, STR("parent:: node()")) % 1; // root
+ CHECK_XPATH_NODESET(doc, STR("parent:: node()"));
}
TEST_XML(xpath_paths_axes_ancestor, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -51,15 +51,15 @@ TEST_XML(xpath_paths_axes_ancestor, "<node attr='value'><child attr='value'><sub
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "ancestor:: node()");
+ CHECK_XPATH_NODESET(c, STR("ancestor:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "ancestor:: node()") % 2 % 1; // node, root
- CHECK_XPATH_NODESET(n, "child/subchild/ancestor:: node()") % 4 % 2 % 1; // child, node, root
- CHECK_XPATH_NODESET(n, "child/@attr/ancestor:: node()") % 4 % 2 % 1; // child, node, root
- CHECK_XPATH_NODESET(n, "ancestor:: node()") % 1; // root
- CHECK_XPATH_NODESET(doc, "ancestor:: node()");
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor:: node()")) % 2 % 1; // node, root
+ CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
+ CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
+ CHECK_XPATH_NODESET(n, STR("ancestor:: node()")) % 1; // root
+ CHECK_XPATH_NODESET(doc, STR("ancestor:: node()"));
}
TEST_XML(xpath_paths_axes_following_sibling, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -67,13 +67,13 @@ TEST_XML(xpath_paths_axes_following_sibling, "<node attr1='value' attr2='value'>
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "following-sibling:: node()");
+ CHECK_XPATH_NODESET(c, STR("following-sibling:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "following-sibling:: node()") % 8 % 10; // another, last
- CHECK_XPATH_NODESET(n.child("last"), "following-sibling:: node()");
- CHECK_XPATH_NODESET(n, "@attr1/following-sibling:: node()"); // attributes are not siblings
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("following-sibling:: node()")) % 8 % 10; // another, last
+ CHECK_XPATH_NODESET(n.child(STR("last")), STR("following-sibling:: node()"));
+ CHECK_XPATH_NODESET(n, STR("@attr1/following-sibling:: node()")); // attributes are not siblings
}
TEST_XML(xpath_paths_axes_preceding_sibling, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -81,13 +81,13 @@ TEST_XML(xpath_paths_axes_preceding_sibling, "<node attr1='value' attr2='value'>
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "preceding-sibling:: node()");
+ CHECK_XPATH_NODESET(c, STR("preceding-sibling:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "preceding-sibling:: node()");
- CHECK_XPATH_NODESET(n.child("last"), "preceding-sibling:: node()") % 8 % 5; // another, child
- CHECK_XPATH_NODESET(n, "@attr2/following-sibling:: node()"); // attributes are not siblings
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding-sibling:: node()"));
+ CHECK_XPATH_NODESET(n.child(STR("last")), STR("preceding-sibling:: node()")) % 8 % 5; // another, child
+ CHECK_XPATH_NODESET(n, STR("@attr2/following-sibling:: node()")); // attributes are not siblings
}
TEST_XML(xpath_paths_axes_following, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><almost/><last/></node>")
@@ -95,14 +95,14 @@ TEST_XML(xpath_paths_axes_following, "<node attr1='value' attr2='value'><child a
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "following:: node()");
+ CHECK_XPATH_NODESET(c, STR("following:: node()"));
- CHECK_XPATH_NODESET(n, "following:: node()"); // no descendants
- CHECK_XPATH_NODESET(n.child("child"), "following:: node()") % 8 % 9 % 10 % 11; // another, subchild, almost, last
- CHECK_XPATH_NODESET(n.child("child").child("subchild"), "following:: node()") % 8 % 9 % 10 % 11; // another, subchild, almost, last
- CHECK_XPATH_NODESET(n.child("last"), "following:: node()");
+ CHECK_XPATH_NODESET(n, STR("following:: node()")); // no descendants
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("following:: node()")) % 8 % 9 % 10 % 11; // another, subchild, almost, last
+ CHECK_XPATH_NODESET(n.child(STR("child")).child(STR("subchild")), STR("following:: node()")) % 8 % 9 % 10 % 11; // another, subchild, almost, last
+ CHECK_XPATH_NODESET(n.child(STR("last")), STR("following:: node()"));
}
TEST_XML(xpath_paths_axes_preceding, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><almost/><last/></node>")
@@ -110,14 +110,14 @@ TEST_XML(xpath_paths_axes_preceding, "<node attr1='value' attr2='value'><child a
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "preceding:: node()");
+ CHECK_XPATH_NODESET(c, STR("preceding:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "preceding:: node()"); // no ancestors
- CHECK_XPATH_NODESET(n.child("last"), "preceding:: node()") % 10 % 9 % 8 % 7 % 5; // almost, subchild, another, subchild, child
- CHECK_XPATH_NODESET(n.child("another").child("subchild"), "preceding:: node()") % 7 % 5; // subchild, child
- CHECK_XPATH_NODESET(n, "preceding:: node()");
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding:: node()")); // no ancestors
+ CHECK_XPATH_NODESET(n.child(STR("last")), STR("preceding:: node()")) % 10 % 9 % 8 % 7 % 5; // almost, subchild, another, subchild, child
+ CHECK_XPATH_NODESET(n.child(STR("another")).child(STR("subchild")), STR("preceding:: node()")) % 7 % 5; // subchild, child
+ CHECK_XPATH_NODESET(n, STR("preceding:: node()"));
}
TEST_XML(xpath_paths_axes_attribute, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another xmlns:foo='bar'><subchild/></another><last/></node>")
@@ -125,22 +125,22 @@ TEST_XML(xpath_paths_axes_attribute, "<node attr1='value' attr2='value'><child a
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "attribute:: node()");
+ CHECK_XPATH_NODESET(c, STR("attribute:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "attribute:: node()") % 6; // child/@attr
- CHECK_XPATH_NODESET(n.child("last"), "attribute:: node()");
- CHECK_XPATH_NODESET(n, "attribute:: node()") % 3 % 4; // node/@attr1 node/@attr2
- CHECK_XPATH_NODESET(doc, "descendant-or-self:: node()/attribute:: node()") % 3 % 4 % 6; // all attributes
- CHECK_XPATH_NODESET(n.child("another"), "attribute:: node()"); // namespace nodes are not attributes
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("attribute:: node()")) % 6; // child/@attr
+ CHECK_XPATH_NODESET(n.child(STR("last")), STR("attribute:: node()"));
+ CHECK_XPATH_NODESET(n, STR("attribute:: node()")) % 3 % 4; // node/@attr1 node/@attr2
+ CHECK_XPATH_NODESET(doc, STR("descendant-or-self:: node()/attribute:: node()")) % 3 % 4 % 6; // all attributes
+ CHECK_XPATH_NODESET(n.child(STR("another")), STR("attribute:: node()")); // namespace nodes are not attributes
}
TEST_XML(xpath_paths_axes_namespace, "<node xmlns:foo='bar'/>")
{
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(n, "namespace:: node()"); // namespace nodes are not supported
+ CHECK_XPATH_NODESET(n, STR("namespace:: node()")); // namespace nodes are not supported
}
TEST_XML(xpath_paths_axes_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -148,15 +148,15 @@ TEST_XML(xpath_paths_axes_self, "<node attr='value'><child attr='value'><subchil
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "self:: node()");
+ CHECK_XPATH_NODESET(c, STR("self:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "self:: node()") % 4; // child
- CHECK_XPATH_NODESET(n, "self:: node()") % 2; // node
- CHECK_XPATH_NODESET(n, "child/self:: node()") % 4; // child
- CHECK_XPATH_NODESET(n, "child/@attr/self:: node()") % 5; // @attr
- CHECK_XPATH_NODESET(doc, "self:: node()") % 1; // root
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("self:: node()")) % 4; // child
+ CHECK_XPATH_NODESET(n, STR("self:: node()")) % 2; // node
+ CHECK_XPATH_NODESET(n, STR("child/self:: node()")) % 4; // child
+ CHECK_XPATH_NODESET(n, STR("child/@attr/self:: node()")) % 5; // @attr
+ CHECK_XPATH_NODESET(doc, STR("self:: node()")) % 1; // root
}
TEST_XML(xpath_paths_axes_descendant_or_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -164,14 +164,14 @@ TEST_XML(xpath_paths_axes_descendant_or_self, "<node attr='value'><child attr='v
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "descendant-or-self:: node()");
+ CHECK_XPATH_NODESET(c, STR("descendant-or-self:: node()"));
- CHECK_XPATH_NODESET(n, "descendant-or-self:: node()") % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
- CHECK_XPATH_NODESET(doc, "descendant-or-self:: node()") % 1 % 2 % 4 % 6 % 7 % 8 % 9; // root, node, child, subchild, another, subchild, last
- CHECK_XPATH_NODESET(n, "another/descendant-or-self:: node()") % 7 % 8; // another, subchild
- CHECK_XPATH_NODESET(n, "last/descendant-or-self:: node()") % 9; // last
+ CHECK_XPATH_NODESET(n, STR("descendant-or-self:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
+ CHECK_XPATH_NODESET(doc, STR("descendant-or-self:: node()")) % 1 % 2 % 4 % 6 % 7 % 8 % 9; // root, node, child, subchild, another, subchild, last
+ CHECK_XPATH_NODESET(n, STR("another/descendant-or-self:: node()")) % 7 % 8; // another, subchild
+ CHECK_XPATH_NODESET(n, STR("last/descendant-or-self:: node()")) % 9; // last
}
TEST_XML(xpath_paths_axes_ancestor_or_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@@ -179,15 +179,15 @@ TEST_XML(xpath_paths_axes_ancestor_or_self, "<node attr='value'><child attr='val
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "ancestor-or-self:: node()");
+ CHECK_XPATH_NODESET(c, STR("ancestor-or-self:: node()"));
- CHECK_XPATH_NODESET(n.child("child"), "ancestor-or-self:: node()") % 4 % 2 % 1; // child, node, root
- CHECK_XPATH_NODESET(n, "child/subchild/ancestor-or-self:: node()") % 6 % 4 % 2 % 1; // subchild, child, node, root
- CHECK_XPATH_NODESET(n, "child/@attr/ancestor-or-self:: node()") % 5 % 4 % 2 % 1; // @attr, child, node, root
- CHECK_XPATH_NODESET(n, "ancestor-or-self:: node()") % 2 % 1; // root, node
- CHECK_XPATH_NODESET(doc, "ancestor-or-self:: node()") % 1; // root
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor-or-self:: node()")) % 4 % 2 % 1; // child, node, root
+ CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor-or-self:: node()")) % 6 % 4 % 2 % 1; // subchild, child, node, root
+ CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor-or-self:: node()")) % 5 % 4 % 2 % 1; // @attr, child, node, root
+ CHECK_XPATH_NODESET(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
+ CHECK_XPATH_NODESET(doc, STR("ancestor-or-self:: node()")) % 1; // root
}
TEST_XML(xpath_paths_axes_abbrev, "<node attr='value'><foo/></node>")
@@ -195,20 +195,20 @@ TEST_XML(xpath_paths_axes_abbrev, "<node attr='value'><foo/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// @ axis
- CHECK_XPATH_NODESET(c, "@attr");
- CHECK_XPATH_NODESET(n, "@attr") % 3;
+ CHECK_XPATH_NODESET(c, STR("@attr"));
+ CHECK_XPATH_NODESET(n, STR("@attr")) % 3;
// no axis - child implied
- CHECK_XPATH_NODESET(c, "foo");
- CHECK_XPATH_NODESET(n, "foo") % 4;
- CHECK_XPATH_NODESET(doc, "node()") % 2;
+ CHECK_XPATH_NODESET(c, STR("foo"));
+ CHECK_XPATH_NODESET(n, STR("foo")) % 4;
+ CHECK_XPATH_NODESET(doc, STR("node()")) % 2;
// @ axis should disable all other axis specifiers
- CHECK_XPATH_FAIL("@child::foo");
- CHECK_XPATH_FAIL("@attribute::foo");
+ CHECK_XPATH_FAIL(STR("@child::foo"));
+ CHECK_XPATH_FAIL(STR("@attribute::foo"));
}
TEST_XML(xpath_paths_nodetest_all, "<node a1='v1' x:a2='v2'><c1/><x:c2/><c3/><x:c4/></node>")
@@ -216,14 +216,14 @@ TEST_XML(xpath_paths_nodetest_all, "<node a1='v1' x:a2='v2'><c1/><x:c2/><c3/><x:
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "*");
- CHECK_XPATH_NODESET(c, "child::*");
+ CHECK_XPATH_NODESET(c, STR("*"));
+ CHECK_XPATH_NODESET(c, STR("child::*"));
- CHECK_XPATH_NODESET(n, "*") % 5 % 6 % 7 % 8;
- CHECK_XPATH_NODESET(n, "child::*") % 5 % 6 % 7 % 8;
- CHECK_XPATH_NODESET(n, "attribute::*") % 3 % 4;
+ CHECK_XPATH_NODESET(n, STR("*")) % 5 % 6 % 7 % 8;
+ CHECK_XPATH_NODESET(n, STR("child::*")) % 5 % 6 % 7 % 8;
+ CHECK_XPATH_NODESET(n, STR("attribute::*")) % 3 % 4;
}
TEST_XML_FLAGS(xpath_paths_nodetest_name, "<node a1='v1' x:a2='v2'><c1/><x:c2/><c3/><x:c4/><?c1?></node>", parse_default | parse_pi)
@@ -231,20 +231,20 @@ TEST_XML_FLAGS(xpath_paths_nodetest_name, "<node a1='v1' x:a2='v2'><c1/><x:c2/><
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "c1");
- CHECK_XPATH_NODESET(c, "child::c1");
+ CHECK_XPATH_NODESET(c, STR("c1"));
+ CHECK_XPATH_NODESET(c, STR("child::c1"));
- CHECK_XPATH_NODESET(n, "c1") % 5;
- CHECK_XPATH_NODESET(n, "x:c2") % 6;
+ CHECK_XPATH_NODESET(n, STR("c1")) % 5;
+ CHECK_XPATH_NODESET(n, STR("x:c2")) % 6;
- CHECK_XPATH_NODESET(n, "child::c1") % 5;
- CHECK_XPATH_NODESET(n, "child::x:c2") % 6;
+ CHECK_XPATH_NODESET(n, STR("child::c1")) % 5;
+ CHECK_XPATH_NODESET(n, STR("child::x:c2")) % 6;
- CHECK_XPATH_NODESET(n, "attribute::a1") % 3;
- CHECK_XPATH_NODESET(n, "attribute::x:a2") % 4;
- CHECK_XPATH_NODESET(n, "@x:a2") % 4;
+ CHECK_XPATH_NODESET(n, STR("attribute::a1")) % 3;
+ CHECK_XPATH_NODESET(n, STR("attribute::x:a2")) % 4;
+ CHECK_XPATH_NODESET(n, STR("@x:a2")) % 4;
}
TEST_XML(xpath_paths_nodetest_all_in_namespace, "<node a1='v1' x:a2='v2'><c1/><x:c2/><c3/><x:c4/></node>")
@@ -252,19 +252,19 @@ TEST_XML(xpath_paths_nodetest_all_in_namespace, "<node a1='v1' x:a2='v2'><c1/><x
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "x:*");
- CHECK_XPATH_NODESET(c, "child::x:*");
+ CHECK_XPATH_NODESET(c, STR("x:*"));
+ CHECK_XPATH_NODESET(c, STR("child::x:*"));
- CHECK_XPATH_NODESET(n, "x:*") % 6 % 8;
- CHECK_XPATH_NODESET(n, "child::x:*") % 6 % 8;
+ CHECK_XPATH_NODESET(n, STR("x:*")) % 6 % 8;
+ CHECK_XPATH_NODESET(n, STR("child::x:*")) % 6 % 8;
- CHECK_XPATH_NODESET(n, "attribute::x:*") % 4;
- CHECK_XPATH_NODESET(n, "@x:*") % 4;
+ CHECK_XPATH_NODESET(n, STR("attribute::x:*")) % 4;
+ CHECK_XPATH_NODESET(n, STR("@x:*")) % 4;
- CHECK_XPATH_FAIL(":*");
- CHECK_XPATH_FAIL("@:*");
+ CHECK_XPATH_FAIL(STR(":*"));
+ CHECK_XPATH_FAIL(STR("@:*"));
}
TEST_XML_FLAGS(xpath_paths_nodetest_type, "<node attr='value'>pcdata<child/><?pi1 value?><?pi2 value?><!--comment--><![CDATA[cdata]]></node>", parse_default | parse_pi | parse_comments)
@@ -272,35 +272,35 @@ TEST_XML_FLAGS(xpath_paths_nodetest_type, "<node attr='value'>pcdata<child/><?pi
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
// check on empty nodes
- CHECK_XPATH_NODESET(c, "node()");
- CHECK_XPATH_NODESET(c, "text()");
- CHECK_XPATH_NODESET(c, "comment()");
- CHECK_XPATH_NODESET(c, "processing-instruction()");
- CHECK_XPATH_NODESET(c, "processing-instruction('foobar')");
+ CHECK_XPATH_NODESET(c, STR("node()"));
+ CHECK_XPATH_NODESET(c, STR("text()"));
+ CHECK_XPATH_NODESET(c, STR("comment()"));
+ CHECK_XPATH_NODESET(c, STR("processing-instruction()"));
+ CHECK_XPATH_NODESET(c, STR("processing-instruction('foobar')"));
// child axis
- CHECK_XPATH_NODESET(n, "node()") % 4 % 5 % 6 % 7 % 8 % 9;
- CHECK_XPATH_NODESET(n, "text()") % 4 % 9;
- CHECK_XPATH_NODESET(n, "comment()") % 8;
- CHECK_XPATH_NODESET(n, "processing-instruction()") % 6 % 7;
- CHECK_XPATH_NODESET(n, "processing-instruction('pi2')") % 7;
+ CHECK_XPATH_NODESET(n, STR("node()")) % 4 % 5 % 6 % 7 % 8 % 9;
+ CHECK_XPATH_NODESET(n, STR("text()")) % 4 % 9;
+ CHECK_XPATH_NODESET(n, STR("comment()")) % 8;
+ CHECK_XPATH_NODESET(n, STR("processing-instruction()")) % 6 % 7;
+ CHECK_XPATH_NODESET(n, STR("processing-instruction('pi2')")) % 7;
// attribute axis
- CHECK_XPATH_NODESET(n, "@node()") % 3;
- CHECK_XPATH_NODESET(n, "@text()");
- CHECK_XPATH_NODESET(n, "@comment()");
- CHECK_XPATH_NODESET(n, "@processing-instruction()");
- CHECK_XPATH_NODESET(n, "@processing-instruction('pi2')");
+ CHECK_XPATH_NODESET(n, STR("@node()")) % 3;
+ CHECK_XPATH_NODESET(n, STR("@text()"));
+ CHECK_XPATH_NODESET(n, STR("@comment()"));
+ CHECK_XPATH_NODESET(n, STR("@processing-instruction()"));
+ CHECK_XPATH_NODESET(n, STR("@processing-instruction('pi2')"));
// incorrect 'argument' number
- CHECK_XPATH_FAIL("node('')");
- CHECK_XPATH_FAIL("text('')");
- CHECK_XPATH_FAIL("comment('')");
- CHECK_XPATH_FAIL("processing-instruction(1)");
- CHECK_XPATH_FAIL("processing-instruction('', '')");
+ CHECK_XPATH_FAIL(STR("node('')"));
+ CHECK_XPATH_FAIL(STR("text('')"));
+ CHECK_XPATH_FAIL(STR("comment('')"));
+ CHECK_XPATH_FAIL(STR("processing-instruction(1)"));
+ CHECK_XPATH_FAIL(STR("processing-instruction('', '')"));
}
TEST_XML(xpath_paths_absolute, "<node><foo><foo/><foo/></foo></node>")
@@ -308,16 +308,16 @@ TEST_XML(xpath_paths_absolute, "<node><foo><foo/><foo/></foo></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "/foo");
- CHECK_XPATH_NODESET(n, "/foo");
- CHECK_XPATH_NODESET(n, "/node/foo") % 3;
- CHECK_XPATH_NODESET(n.child("foo"), "/node/foo") % 3;
+ CHECK_XPATH_NODESET(c, STR("/foo"));
+ CHECK_XPATH_NODESET(n, STR("/foo"));
+ CHECK_XPATH_NODESET(n, STR("/node/foo")) % 3;
+ CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/node/foo")) % 3;
- CHECK_XPATH_NODESET(c, "/");
- CHECK_XPATH_NODESET(n, "/") % 1;
- CHECK_XPATH_NODESET(n.child("foo"), "/") % 1;
+ CHECK_XPATH_NODESET(c, STR("/"));
+ CHECK_XPATH_NODESET(n, STR("/")) % 1;
+ CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/")) % 1;
}
TEST_XML(xpath_paths_step_abbrev, "<node><foo/></node>")
@@ -325,18 +325,18 @@ TEST_XML(xpath_paths_step_abbrev, "<node><foo/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, ".");
- CHECK_XPATH_NODESET(c, "..");
+ CHECK_XPATH_NODESET(c, STR("."));
+ CHECK_XPATH_NODESET(c, STR(".."));
- CHECK_XPATH_NODESET(n, ".") % 2;
- CHECK_XPATH_NODESET(n, "..") % 1;
- CHECK_XPATH_NODESET(n, "../node") % 2;
- CHECK_XPATH_NODESET(n.child("foo"), "..") % 2;
+ CHECK_XPATH_NODESET(n, STR(".")) % 2;
+ CHECK_XPATH_NODESET(n, STR("..")) % 1;
+ CHECK_XPATH_NODESET(n, STR("../node")) % 2;
+ CHECK_XPATH_NODESET(n.child(STR("foo")), STR("..")) % 2;
- CHECK_XPATH_FAIL(".node");
- CHECK_XPATH_FAIL("..node");
+ CHECK_XPATH_FAIL(STR(".node"));
+ CHECK_XPATH_FAIL(STR("..node"));
}
TEST_XML(xpath_paths_relative_abbrev, "<node><foo><foo/><foo/></foo></node>")
@@ -344,13 +344,13 @@ TEST_XML(xpath_paths_relative_abbrev, "<node><foo><foo/><foo/></foo></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "foo//bar");
+ CHECK_XPATH_NODESET(c, STR("foo//bar"));
- CHECK_XPATH_NODESET(n, "foo/foo") % 4 % 5;
- CHECK_XPATH_NODESET(n, "foo//foo") % 4 % 5;
- CHECK_XPATH_NODESET(n, ".//foo") % 3 % 4 % 5;
+ CHECK_XPATH_NODESET(n, STR("foo/foo")) % 4 % 5;
+ CHECK_XPATH_NODESET(n, STR("foo//foo")) % 4 % 5;
+ CHECK_XPATH_NODESET(n, STR(".//foo")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_absolute_abbrev, "<node><foo><foo/><foo/></foo></node>")
@@ -358,117 +358,117 @@ TEST_XML(xpath_paths_absolute_abbrev, "<node><foo><foo/><foo/></foo></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "//bar");
+ CHECK_XPATH_NODESET(c, STR("//bar"));
- CHECK_XPATH_NODESET(n, "//foo") % 3 % 4 % 5;
- CHECK_XPATH_NODESET(n.child("foo"), "//foo") % 3 % 4 % 5;
- CHECK_XPATH_NODESET(doc, "//foo") % 3 % 4 % 5;
+ CHECK_XPATH_NODESET(n, STR("//foo")) % 3 % 4 % 5;
+ CHECK_XPATH_NODESET(n.child(STR("foo")), STR("//foo")) % 3 % 4 % 5;
+ CHECK_XPATH_NODESET(doc, STR("//foo")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_predicate_boolean, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node").child("chapter").next_sibling().next_sibling();
+ xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
- CHECK_XPATH_NODESET(n, "following-sibling::chapter[position()=1]") % 6;
- CHECK_XPATH_NODESET(n, "following-sibling::chapter[position()=2]") % 7;
- CHECK_XPATH_NODESET(n, "preceding-sibling::chapter[position()=1]") % 4;
- CHECK_XPATH_NODESET(n, "preceding-sibling::chapter[position()=2]") % 3;
+ CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[position()=1]")) % 6;
+ CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[position()=2]")) % 7;
+ CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[position()=1]")) % 4;
+ CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[position()=2]")) % 3;
}
TEST_XML(xpath_paths_predicate_number, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node").child("chapter").next_sibling().next_sibling();
+ xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
- CHECK_XPATH_NODESET(n, "following-sibling::chapter[1]") % 6;
- CHECK_XPATH_NODESET(n, "following-sibling::chapter[2]") % 7;
- CHECK_XPATH_NODESET(n, "preceding-sibling::chapter[1]") % 4;
- CHECK_XPATH_NODESET(n, "preceding-sibling::chapter[2]") % 3;
+ CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1]")) % 6;
+ CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[2]")) % 7;
+ CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[1]")) % 4;
+ CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[2]")) % 3;
}
TEST_XML(xpath_paths_predicate_several, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(n, "employee") % 3 % 4 % 6 % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@secretary]") % 4 % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@assistant]") % 6 % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@secretary][@assistant]") % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@assistant][@secretary]") % 8 % 11;
- CHECK_XPATH_NODESET(n, "employee[@secretary and @assistant]") % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee")) % 3 % 4 % 6 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@secretary]")) % 4 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@assistant]")) % 6 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@secretary][@assistant]")) % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@assistant][@secretary]")) % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee[@secretary and @assistant]")) % 8 % 11;
}
TEST_XML(xpath_paths_predicate_filter_boolean, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node").child("chapter").next_sibling().next_sibling();
+ xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
- CHECK_XPATH_NODESET(n, "(following-sibling::chapter)[position()=1]") % 6;
- CHECK_XPATH_NODESET(n, "(following-sibling::chapter)[position()=2]") % 7;
- CHECK_XPATH_NODESET(n, "(preceding-sibling::chapter)[position()=1]") % 3;
- CHECK_XPATH_NODESET(n, "(preceding-sibling::chapter)[position()=2]") % 4;
+ CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[position()=1]")) % 6;
+ CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[position()=2]")) % 7;
+ CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[position()=1]")) % 3;
+ CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[position()=2]")) % 4;
}
TEST_XML(xpath_paths_predicate_filter_number, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node").child("chapter").next_sibling().next_sibling();
+ xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
- CHECK_XPATH_NODESET(n, "(following-sibling::chapter)[1]") % 6;
- CHECK_XPATH_NODESET(n, "(following-sibling::chapter)[2]") % 7;
- CHECK_XPATH_NODESET(n, "(preceding-sibling::chapter)[1]") % 3;
- CHECK_XPATH_NODESET(n, "(preceding-sibling::chapter)[2]") % 4;
+ CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[1]")) % 6;
+ CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[2]")) % 7;
+ CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[1]")) % 3;
+ CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[2]")) % 4;
}
TEST_XML(xpath_paths_predicate_filter_posinv, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(n, "employee") % 3 % 4 % 6 % 8 % 11;
- CHECK_XPATH_NODESET(n, "(employee[@secretary])[@assistant]") % 8 % 11;
- CHECK_XPATH_NODESET(n, "((employee)[@assistant])[@secretary]") % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("employee")) % 3 % 4 % 6 % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("(employee[@secretary])[@assistant]")) % 8 % 11;
+ CHECK_XPATH_NODESET(n, STR("((employee)[@assistant])[@secretary]")) % 8 % 11;
}
TEST_XML(xpath_paths_step_compose, "<node><foo><foo/><foo/></foo><foo/></node>")
{
doc.precompute_document_order();
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(n, "(.)/foo") % 3 % 6;
- CHECK_XPATH_NODESET(n, "(.)//foo") % 3 % 4 % 5 % 6;
- CHECK_XPATH_NODESET(n, "(./..)//*") % 2 % 3 % 4 % 5 % 6;
+ CHECK_XPATH_NODESET(n, STR("(.)/foo")) % 3 % 6;
+ CHECK_XPATH_NODESET(n, STR("(.)//foo")) % 3 % 4 % 5 % 6;
+ CHECK_XPATH_NODESET(n, STR("(./..)//*")) % 2 % 3 % 4 % 5 % 6;
- CHECK_XPATH_FAIL("(1)/foo");
- CHECK_XPATH_FAIL("(1)//foo");
+ CHECK_XPATH_FAIL(STR("(1)/foo"));
+ CHECK_XPATH_FAIL(STR("(1)//foo"));
}
TEST_XML(xpath_paths_descendant_double_slash_w3c, "<node><para><para/><para/><para><para/></para></para><para/></node>")
{
doc.precompute_document_order();
- CHECK_XPATH_NODESET(doc, "//para") % 3 % 4 % 5 % 6 % 7 % 8;
- CHECK_XPATH_NODESET(doc, "/descendant::para") % 3 % 4 % 5 % 6 % 7 % 8;
- CHECK_XPATH_NODESET(doc, "//para[1]") % 3 % 4 % 7;
- CHECK_XPATH_NODESET(doc, "/descendant::para[1]") % 3;
+ CHECK_XPATH_NODESET(doc, STR("//para")) % 3 % 4 % 5 % 6 % 7 % 8;
+ CHECK_XPATH_NODESET(doc, STR("/descendant::para")) % 3 % 4 % 5 % 6 % 7 % 8;
+ CHECK_XPATH_NODESET(doc, STR("//para[1]")) % 3 % 4 % 7;
+ CHECK_XPATH_NODESET(doc, STR("/descendant::para[1]")) % 3;
}
TEST_XML(xpath_paths_needs_sorting, "<node><child/><child/><child><subchild/><subchild/></child></node>")
{
doc.precompute_document_order();
- CHECK_XPATH_NODESET(doc, "(node/child/subchild)[2]") % 7;
+ CHECK_XPATH_NODESET(doc, STR("(node/child/subchild)[2]")) % 7;
}
#endif
diff --git a/tests/test_xpath_paths_abbrev_w3c.cpp b/tests/test_xpath_paths_abbrev_w3c.cpp
index 9d4e810..7fd092c 100644
--- a/tests/test_xpath_paths_abbrev_w3c.cpp
+++ b/tests/test_xpath_paths_abbrev_w3c.cpp
@@ -7,10 +7,10 @@ TEST_XML(xpath_paths_abbrev_w3c_1, "<node><para/><foo/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "para");
- CHECK_XPATH_NODESET(n, "para") % 3 % 5;
+ CHECK_XPATH_NODESET(c, STR("para"));
+ CHECK_XPATH_NODESET(n, STR("para")) % 3 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_2, "<node><para/><foo/><para/></node>")
@@ -18,10 +18,10 @@ TEST_XML(xpath_paths_abbrev_w3c_2, "<node><para/><foo/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "*");
- CHECK_XPATH_NODESET(n, "*") % 3 % 4 % 5;
+ CHECK_XPATH_NODESET(c, STR("*"));
+ CHECK_XPATH_NODESET(n, STR("*")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>")
@@ -29,10 +29,10 @@ TEST_XML(xpath_paths_abbrev_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "text()");
- CHECK_XPATH_NODESET(n, "text()") % 3 % 5;
+ CHECK_XPATH_NODESET(c, STR("text()"));
+ CHECK_XPATH_NODESET(n, STR("text()")) % 3 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_4, "<node name='value' foo='bar' />")
@@ -40,10 +40,10 @@ TEST_XML(xpath_paths_abbrev_w3c_4, "<node name='value' foo='bar' />")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "@name");
- CHECK_XPATH_NODESET(n, "@name") % 3;
+ CHECK_XPATH_NODESET(c, STR("@name"));
+ CHECK_XPATH_NODESET(n, STR("@name")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_5, "<node name='value' foo='bar' />")
@@ -51,10 +51,10 @@ TEST_XML(xpath_paths_abbrev_w3c_5, "<node name='value' foo='bar' />")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "@*");
- CHECK_XPATH_NODESET(n, "@*") % 3 % 4;
+ CHECK_XPATH_NODESET(c, STR("@*"));
+ CHECK_XPATH_NODESET(n, STR("@*")) % 3 % 4;
}
TEST_XML(xpath_paths_abbrev_w3c_6, "<node><para/><para/><para/><para/></node>")
@@ -62,10 +62,10 @@ TEST_XML(xpath_paths_abbrev_w3c_6, "<node><para/><para/><para/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "para[1]");
- CHECK_XPATH_NODESET(n, "para[1]") % 3;
+ CHECK_XPATH_NODESET(c, STR("para[1]"));
+ CHECK_XPATH_NODESET(n, STR("para[1]")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_7, "<node><para/><para/><para/><para/></node>")
@@ -73,10 +73,10 @@ TEST_XML(xpath_paths_abbrev_w3c_7, "<node><para/><para/><para/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "para[last()]");
- CHECK_XPATH_NODESET(n, "para[last()]") % 6;
+ CHECK_XPATH_NODESET(c, STR("para[last()]"));
+ CHECK_XPATH_NODESET(n, STR("para[last()]")) % 6;
}
TEST_XML(xpath_paths_abbrev_w3c_8, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -85,8 +85,8 @@ TEST_XML(xpath_paths_abbrev_w3c_8, "<node><para><para/><para/><foo><para/></foo>
xml_node c;
- CHECK_XPATH_NODESET(c, "*/para");
- CHECK_XPATH_NODESET(doc, "*/para") % 3 % 9;
+ CHECK_XPATH_NODESET(c, STR("*/para"));
+ CHECK_XPATH_NODESET(doc, STR("*/para")) % 3 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_9, "<doc><chapter/><chapter/><chapter/><chapter/><chapter><section/><section/><section/></chapter><chapter/></doc>")
@@ -94,11 +94,11 @@ TEST_XML(xpath_paths_abbrev_w3c_9, "<doc><chapter/><chapter/><chapter/><chapter/
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("doc").child("chapter");
+ xml_node n = doc.child(STR("doc")).child(STR("chapter"));
- CHECK_XPATH_NODESET(c, "/doc/chapter[5]/section[2]");
- CHECK_XPATH_NODESET(n, "/doc/chapter[5]/section[2]") % 9;
- CHECK_XPATH_NODESET(doc, "/doc/chapter[5]/section[2]") % 9;
+ CHECK_XPATH_NODESET(c, STR("/doc/chapter[5]/section[2]"));
+ CHECK_XPATH_NODESET(n, STR("/doc/chapter[5]/section[2]")) % 9;
+ CHECK_XPATH_NODESET(doc, STR("/doc/chapter[5]/section[2]")) % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_10, "<chapter><para><para/><para/><foo><para/></foo></para><foo/><para/></chapter>")
@@ -107,8 +107,8 @@ TEST_XML(xpath_paths_abbrev_w3c_10, "<chapter><para><para/><para/><foo><para/></
xml_node c;
- CHECK_XPATH_NODESET(c, "chapter//para");
- CHECK_XPATH_NODESET(doc, "chapter//para") % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(c, STR("chapter//para"));
+ CHECK_XPATH_NODESET(doc, STR("chapter//para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_11, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -116,11 +116,11 @@ TEST_XML(xpath_paths_abbrev_w3c_11, "<node><para><para/><para/><foo><para/></foo
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "//para");
- CHECK_XPATH_NODESET(n, "//para") % 3 % 4 % 5 % 7 % 9;
- CHECK_XPATH_NODESET(n.child("para"), "//para") % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(c, STR("//para"));
+ CHECK_XPATH_NODESET(n, STR("//para")) % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(n.child(STR("para")), STR("//para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_12, "<node><olist><item/></olist><item/><olist><olist><item/><item/></olist></olist></node>")
@@ -128,11 +128,11 @@ TEST_XML(xpath_paths_abbrev_w3c_12, "<node><olist><item/></olist><item/><olist><
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "//olist/item");
- CHECK_XPATH_NODESET(n, "//olist/item") % 4 % 8 % 9;
- CHECK_XPATH_NODESET(n.child("olist"), "//olist/item") % 4 % 8 % 9;
+ CHECK_XPATH_NODESET(c, STR("//olist/item"));
+ CHECK_XPATH_NODESET(n, STR("//olist/item")) % 4 % 8 % 9;
+ CHECK_XPATH_NODESET(n.child(STR("olist")), STR("//olist/item")) % 4 % 8 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_13, "<node><child/></node>")
@@ -140,11 +140,11 @@ TEST_XML(xpath_paths_abbrev_w3c_13, "<node><child/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, ".");
- CHECK_XPATH_NODESET(n, ".") % 2;
- CHECK_XPATH_NODESET(n.child("child"), ".") % 3;
+ CHECK_XPATH_NODESET(c, STR("."));
+ CHECK_XPATH_NODESET(n, STR(".")) % 2;
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR(".")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_14, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -152,11 +152,11 @@ TEST_XML(xpath_paths_abbrev_w3c_14, "<node><para><para/><para/><foo><para/></foo
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, ".//para");
- CHECK_XPATH_NODESET(n, ".//para") % 3 % 4 % 5 % 7 % 9;
- CHECK_XPATH_NODESET(n.child("para"), ".//para") % 4 % 5 % 7;
+ CHECK_XPATH_NODESET(c, STR(".//para"));
+ CHECK_XPATH_NODESET(n, STR(".//para")) % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(n.child(STR("para")), STR(".//para")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_abbrev_w3c_15, "<node lang='en'><child/></node>")
@@ -164,11 +164,11 @@ TEST_XML(xpath_paths_abbrev_w3c_15, "<node lang='en'><child/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "..");
- CHECK_XPATH_NODESET(n, "..") % 1;
- CHECK_XPATH_NODESET(n.child("child"), "..") % 2;
+ CHECK_XPATH_NODESET(c, STR(".."));
+ CHECK_XPATH_NODESET(n, STR("..")) % 1;
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("..")) % 2;
}
TEST_XML(xpath_paths_abbrev_w3c_16, "<node lang='en'><child/></node>")
@@ -176,11 +176,11 @@ TEST_XML(xpath_paths_abbrev_w3c_16, "<node lang='en'><child/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "../@lang");
- CHECK_XPATH_NODESET(n, "../@lang");
- CHECK_XPATH_NODESET(n.child("child"), "../@lang") % 3;
+ CHECK_XPATH_NODESET(c, STR("../@lang"));
+ CHECK_XPATH_NODESET(n, STR("../@lang"));
+ CHECK_XPATH_NODESET(n.child(STR("child")), STR("../@lang")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_17, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -188,10 +188,10 @@ TEST_XML(xpath_paths_abbrev_w3c_17, "<node><para/><para type='warning'/><para ty
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "para[@type=\"warning\"]");
- CHECK_XPATH_NODESET(n, "para[@type=\"warning\"]") % 4 % 6 % 11 % 13 % 15;
+ CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"]"));
+ CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"]")) % 4 % 6 % 11 % 13 % 15;
}
TEST_XML(xpath_paths_abbrev_w3c_18, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -199,10 +199,10 @@ TEST_XML(xpath_paths_abbrev_w3c_18, "<node><para/><para type='warning'/><para ty
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "para[@type=\"warning\"][5]");
- CHECK_XPATH_NODESET(n, "para[@type=\"warning\"][5]") % 15;
+ CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"][5]"));
+ CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"][5]")) % 15;
}
TEST_XML(xpath_paths_abbrev_w3c_19a, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -210,10 +210,10 @@ TEST_XML(xpath_paths_abbrev_w3c_19a, "<node><para/><para type='warning'/><para t
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "para[5][@type=\"warning\"]");
- CHECK_XPATH_NODESET(n, "para[5][@type=\"warning\"]");
+ CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]"));
+ CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]"));
}
TEST_XML(xpath_paths_abbrev_w3c_19b, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -221,10 +221,10 @@ TEST_XML(xpath_paths_abbrev_w3c_19b, "<node><para/><para type='warning'/><para t
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "para[5][@type=\"warning\"]");
- CHECK_XPATH_NODESET(n, "para[5][@type=\"warning\"]") % 9;
+ CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]"));
+ CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]")) % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_20, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
@@ -232,10 +232,10 @@ TEST_XML(xpath_paths_abbrev_w3c_20, "<node><chapter><title>foo</title></chapter>
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "chapter[title=\"Introduction\"]");
- CHECK_XPATH_NODESET(n, "chapter[title=\"Introduction\"]") % 6 % 13;
+ CHECK_XPATH_NODESET(c, STR("chapter[title=\"Introduction\"]"));
+ CHECK_XPATH_NODESET(n, STR("chapter[title=\"Introduction\"]")) % 6 % 13;
}
TEST_XML(xpath_paths_abbrev_w3c_21, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
@@ -243,10 +243,10 @@ TEST_XML(xpath_paths_abbrev_w3c_21, "<node><chapter><title>foo</title></chapter>
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "chapter[title]");
- CHECK_XPATH_NODESET(n, "chapter[title]") % 3 % 6 % 9 % 13;
+ CHECK_XPATH_NODESET(c, STR("chapter[title]"));
+ CHECK_XPATH_NODESET(n, STR("chapter[title]")) % 3 % 6 % 9 % 13;
}
TEST_XML(xpath_paths_abbrev_w3c_22, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
@@ -254,10 +254,10 @@ TEST_XML(xpath_paths_abbrev_w3c_22, "<node><employee/><employee secretary=''/><e
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "employee[@secretary and @assistant]");
- CHECK_XPATH_NODESET(n, "employee[@secretary and @assistant]") % 8 % 11;
+ CHECK_XPATH_NODESET(c, STR("employee[@secretary and @assistant]"));
+ CHECK_XPATH_NODESET(n, STR("employee[@secretary and @assistant]")) % 8 % 11;
}
#endif
diff --git a/tests/test_xpath_paths_w3c.cpp b/tests/test_xpath_paths_w3c.cpp
index fb5bf6b..75b9637 100644
--- a/tests/test_xpath_paths_w3c.cpp
+++ b/tests/test_xpath_paths_w3c.cpp
@@ -7,10 +7,10 @@ TEST_XML(xpath_paths_w3c_1, "<node><para/><foo/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para");
- CHECK_XPATH_NODESET(n, "child::para") % 3 % 5;
+ CHECK_XPATH_NODESET(c, STR("child::para"));
+ CHECK_XPATH_NODESET(n, STR("child::para")) % 3 % 5;
}
TEST_XML(xpath_paths_w3c_2, "<node><para/><foo/><para/></node>")
@@ -18,10 +18,10 @@ TEST_XML(xpath_paths_w3c_2, "<node><para/><foo/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::*");
- CHECK_XPATH_NODESET(n, "child::*") % 3 % 4 % 5;
+ CHECK_XPATH_NODESET(c, STR("child::*"));
+ CHECK_XPATH_NODESET(n, STR("child::*")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>")
@@ -29,10 +29,10 @@ TEST_XML(xpath_paths_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::text()");
- CHECK_XPATH_NODESET(n, "child::text()") % 3 % 5;
+ CHECK_XPATH_NODESET(c, STR("child::text()"));
+ CHECK_XPATH_NODESET(n, STR("child::text()")) % 3 % 5;
}
TEST_XML(xpath_paths_w3c_4, "<node>pcdata<child/><![CDATA[cdata]]></node>")
@@ -40,10 +40,10 @@ TEST_XML(xpath_paths_w3c_4, "<node>pcdata<child/><![CDATA[cdata]]></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::node()");
- CHECK_XPATH_NODESET(n, "child::node()") % 3 % 4 % 5;
+ CHECK_XPATH_NODESET(c, STR("child::node()"));
+ CHECK_XPATH_NODESET(n, STR("child::node()")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_w3c_5, "<node name='value' foo='bar' />")
@@ -51,10 +51,10 @@ TEST_XML(xpath_paths_w3c_5, "<node name='value' foo='bar' />")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "attribute::name");
- CHECK_XPATH_NODESET(n, "attribute::name") % 3;
+ CHECK_XPATH_NODESET(c, STR("attribute::name"));
+ CHECK_XPATH_NODESET(n, STR("attribute::name")) % 3;
}
TEST_XML(xpath_paths_w3c_6, "<node name='value' foo='bar' />")
@@ -62,10 +62,10 @@ TEST_XML(xpath_paths_w3c_6, "<node name='value' foo='bar' />")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "attribute::*");
- CHECK_XPATH_NODESET(n, "attribute::*") % 3 % 4;
+ CHECK_XPATH_NODESET(c, STR("attribute::*"));
+ CHECK_XPATH_NODESET(n, STR("attribute::*")) % 3 % 4;
}
TEST_XML(xpath_paths_w3c_7, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -73,11 +73,11 @@ TEST_XML(xpath_paths_w3c_7, "<node><para><para/><para/><foo><para/></foo></para>
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "descendant::para");
- CHECK_XPATH_NODESET(n, "descendant::para") % 3 % 4 % 5 % 7 % 9;
- CHECK_XPATH_NODESET(n.child("para"), "descendant::para") % 4 % 5 % 7;
+ CHECK_XPATH_NODESET(c, STR("descendant::para"));
+ CHECK_XPATH_NODESET(n, STR("descendant::para")) % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(n.child(STR("para")), STR("descendant::para")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_8, "<node><div><font><div><div/></div></font></div></node>")
@@ -85,10 +85,10 @@ TEST_XML(xpath_paths_w3c_8, "<node><div><font><div><div/></div></font></div></no
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "ancestor::div");
- CHECK_XPATH_NODESET(n.child("div").child("font").child("div").child("div"), "ancestor::div") % 5 % 3;
+ CHECK_XPATH_NODESET(c, STR("ancestor::div"));
+ CHECK_XPATH_NODESET(n.child(STR("div")).child(STR("font")).child(STR("div")).child(STR("div")), STR("ancestor::div")) % 5 % 3;
}
TEST_XML(xpath_paths_w3c_9, "<node><div><font><div><div/></div></font></div></node>")
@@ -96,10 +96,10 @@ TEST_XML(xpath_paths_w3c_9, "<node><div><font><div><div/></div></font></div></no
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "ancestor-or-self::div");
- CHECK_XPATH_NODESET(n.child("div").child("font").child("div").child("div"), "ancestor-or-self::div") % 6 % 5 % 3;
+ CHECK_XPATH_NODESET(c, STR("ancestor-or-self::div"));
+ CHECK_XPATH_NODESET(n.child(STR("div")).child(STR("font")).child(STR("div")).child(STR("div")), STR("ancestor-or-self::div")) % 6 % 5 % 3;
}
TEST_XML(xpath_paths_w3c_10, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -107,11 +107,11 @@ TEST_XML(xpath_paths_w3c_10, "<node><para><para/><para/><foo><para/></foo></para
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "descendant-or-self::para");
- CHECK_XPATH_NODESET(n, "descendant-or-self::para") % 3 % 4 % 5 % 7 % 9;
- CHECK_XPATH_NODESET(n.child("para"), "descendant-or-self::para") % 3 % 4 % 5 % 7;
+ CHECK_XPATH_NODESET(c, STR("descendant-or-self::para"));
+ CHECK_XPATH_NODESET(n, STR("descendant-or-self::para")) % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(n.child(STR("para")), STR("descendant-or-self::para")) % 3 % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_11, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -119,11 +119,11 @@ TEST_XML(xpath_paths_w3c_11, "<node><para><para/><para/><foo><para/></foo></para
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "self::para");
- CHECK_XPATH_NODESET(n, "self::para");
- CHECK_XPATH_NODESET(n.child("para"), "self::para") % 3;
+ CHECK_XPATH_NODESET(c, STR("self::para"));
+ CHECK_XPATH_NODESET(n, STR("self::para"));
+ CHECK_XPATH_NODESET(n.child(STR("para")), STR("self::para")) % 3;
}
TEST_XML(xpath_paths_w3c_12, "<chapter><para><para/><para/><foo><para/></foo></para><foo/><para/></chapter>")
@@ -132,8 +132,8 @@ TEST_XML(xpath_paths_w3c_12, "<chapter><para><para/><para/><foo><para/></foo></p
xml_node c;
- CHECK_XPATH_NODESET(c, "child::chapter/descendant::para");
- CHECK_XPATH_NODESET(doc, "child::chapter/descendant::para") % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(c, STR("child::chapter/descendant::para"));
+ CHECK_XPATH_NODESET(doc, STR("child::chapter/descendant::para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_w3c_13, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -142,8 +142,8 @@ TEST_XML(xpath_paths_w3c_13, "<node><para><para/><para/><foo><para/></foo></para
xml_node c;
- CHECK_XPATH_NODESET(c, "child::*/child::para");
- CHECK_XPATH_NODESET(doc, "child::*/child::para") % 3 % 9;
+ CHECK_XPATH_NODESET(c, STR("child::*/child::para"));
+ CHECK_XPATH_NODESET(doc, STR("child::*/child::para")) % 3 % 9;
}
TEST_XML(xpath_paths_w3c_14, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -151,13 +151,13 @@ TEST_XML(xpath_paths_w3c_14, "<node><para><para/><para/><foo><para/></foo></para
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "/");
+ CHECK_XPATH_NODESET(c, STR("/"));
- CHECK_XPATH_NODESET(doc, "/") % 1;
- CHECK_XPATH_NODESET(n, "/") % 1;
- CHECK_XPATH_NODESET(n.child("para"), "/") % 1;
+ CHECK_XPATH_NODESET(doc, STR("/")) % 1;
+ CHECK_XPATH_NODESET(n, STR("/")) % 1;
+ CHECK_XPATH_NODESET(n.child(STR("para")), STR("/")) % 1;
}
TEST_XML(xpath_paths_w3c_15, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
@@ -165,11 +165,11 @@ TEST_XML(xpath_paths_w3c_15, "<node><para><para/><para/><foo><para/></foo></para
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "/descendant::para");
- CHECK_XPATH_NODESET(n, "/descendant::para") % 3 % 4 % 5 % 7 % 9;
- CHECK_XPATH_NODESET(n.child("para"), "/descendant::para") % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(c, STR("/descendant::para"));
+ CHECK_XPATH_NODESET(n, STR("/descendant::para")) % 3 % 4 % 5 % 7 % 9;
+ CHECK_XPATH_NODESET(n.child(STR("para")), STR("/descendant::para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_w3c_16, "<node><olist><item/></olist><item/><olist><olist><item/><item/></olist></olist></node>")
@@ -177,11 +177,11 @@ TEST_XML(xpath_paths_w3c_16, "<node><olist><item/></olist><item/><olist><olist><
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "/descendant::olist/child::item");
- CHECK_XPATH_NODESET(n, "/descendant::olist/child::item") % 4 % 8 % 9;
- CHECK_XPATH_NODESET(n.child("olist"), "/descendant::olist/child::item") % 4 % 8 % 9;
+ CHECK_XPATH_NODESET(c, STR("/descendant::olist/child::item"));
+ CHECK_XPATH_NODESET(n, STR("/descendant::olist/child::item")) % 4 % 8 % 9;
+ CHECK_XPATH_NODESET(n.child(STR("olist")), STR("/descendant::olist/child::item")) % 4 % 8 % 9;
}
TEST_XML(xpath_paths_w3c_17, "<node><para/><para/><para/><para/></node>")
@@ -189,10 +189,10 @@ TEST_XML(xpath_paths_w3c_17, "<node><para/><para/><para/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[position()=1]");
- CHECK_XPATH_NODESET(n, "child::para[position()=1]") % 3;
+ CHECK_XPATH_NODESET(c, STR("child::para[position()=1]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[position()=1]")) % 3;
}
TEST_XML(xpath_paths_w3c_18, "<node><para/><para/><para/><para/></node>")
@@ -200,10 +200,10 @@ TEST_XML(xpath_paths_w3c_18, "<node><para/><para/><para/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[position()=last()]");
- CHECK_XPATH_NODESET(n, "child::para[position()=last()]") % 6;
+ CHECK_XPATH_NODESET(c, STR("child::para[position()=last()]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[position()=last()]")) % 6;
}
TEST_XML(xpath_paths_w3c_19, "<node><para/><para/><para/><para/></node>")
@@ -211,10 +211,10 @@ TEST_XML(xpath_paths_w3c_19, "<node><para/><para/><para/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[position()=last()-1]");
- CHECK_XPATH_NODESET(n, "child::para[position()=last()-1]") % 5;
+ CHECK_XPATH_NODESET(c, STR("child::para[position()=last()-1]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[position()=last()-1]")) % 5;
}
TEST_XML(xpath_paths_w3c_20, "<node><para/><para/><para/><para/></node>")
@@ -222,10 +222,10 @@ TEST_XML(xpath_paths_w3c_20, "<node><para/><para/><para/><para/></node>")
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[position()>1]");
- CHECK_XPATH_NODESET(n, "child::para[position()>1]") % 4 % 5 % 6;
+ CHECK_XPATH_NODESET(c, STR("child::para[position()>1]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[position()>1]")) % 4 % 5 % 6;
}
TEST_XML(xpath_paths_w3c_21, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
@@ -233,10 +233,10 @@ TEST_XML(xpath_paths_w3c_21, "<node><chapter/><chapter/><chapter/><chapter/><cha
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node").child("chapter").next_sibling().next_sibling();
+ xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
- CHECK_XPATH_NODESET(c, "following-sibling::chapter[position()=1]");
- CHECK_XPATH_NODESET(n, "following-sibling::chapter[position()=1]") % 6;
+ CHECK_XPATH_NODESET(c, STR("following-sibling::chapter[position()=1]"));
+ CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[position()=1]")) % 6;
}
TEST_XML(xpath_paths_w3c_22, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
@@ -244,10 +244,10 @@ TEST_XML(xpath_paths_w3c_22, "<node><chapter/><chapter/><chapter/><chapter/><cha
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node").child("chapter").next_sibling().next_sibling();
+ xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
- CHECK_XPATH_NODESET(c, "preceding-sibling::chapter[position()=1]");
- CHECK_XPATH_NODESET(n, "preceding-sibling::chapter[position()=1]") % 4;
+ CHECK_XPATH_NODESET(c, STR("preceding-sibling::chapter[position()=1]"));
+ CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[position()=1]")) % 4;
}
TEST_XML(xpath_paths_w3c_23, "<node><figure><figure/><figure/><foo><figure/></foo></figure><foo/><figure/></node>")
@@ -255,11 +255,11 @@ TEST_XML(xpath_paths_w3c_23, "<node><figure><figure/><figure/><foo><figure/></fo
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "/descendant::figure[position()=4]");
- CHECK_XPATH_NODESET(n, "/descendant::figure[position()=4]") % 7;
- CHECK_XPATH_NODESET(n.child("figure"), "/descendant::figure[position()=4]") % 7;
+ CHECK_XPATH_NODESET(c, STR("/descendant::figure[position()=4]"));
+ CHECK_XPATH_NODESET(n, STR("/descendant::figure[position()=4]")) % 7;
+ CHECK_XPATH_NODESET(n.child(STR("figure")), STR("/descendant::figure[position()=4]")) % 7;
}
TEST_XML(xpath_paths_w3c_24, "<doc><chapter/><chapter/><chapter/><chapter/><chapter><section/><section/><section/></chapter><chapter/></doc>")
@@ -267,11 +267,11 @@ TEST_XML(xpath_paths_w3c_24, "<doc><chapter/><chapter/><chapter/><chapter/><chap
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("doc").child("chapter");
+ xml_node n = doc.child(STR("doc")).child(STR("chapter"));
- CHECK_XPATH_NODESET(c, "/child::doc/child::chapter[position()=5]/child::section[position()=2]");
- CHECK_XPATH_NODESET(n, "/child::doc/child::chapter[position()=5]/child::section[position()=2]") % 9;
- CHECK_XPATH_NODESET(doc, "/child::doc/child::chapter[position()=5]/child::section[position()=2]") % 9;
+ CHECK_XPATH_NODESET(c, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]"));
+ CHECK_XPATH_NODESET(n, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]")) % 9;
+ CHECK_XPATH_NODESET(doc, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]")) % 9;
}
TEST_XML(xpath_paths_w3c_25, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -279,10 +279,10 @@ TEST_XML(xpath_paths_w3c_25, "<node><para/><para type='warning'/><para type='war
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[attribute::type=\"warning\"]");
- CHECK_XPATH_NODESET(n, "child::para[attribute::type=\"warning\"]") % 4 % 6 % 11 % 13 % 15;
+ CHECK_XPATH_NODESET(c, STR("child::para[attribute::type=\"warning\"]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[attribute::type=\"warning\"]")) % 4 % 6 % 11 % 13 % 15;
}
TEST_XML(xpath_paths_w3c_26, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -290,10 +290,10 @@ TEST_XML(xpath_paths_w3c_26, "<node><para/><para type='warning'/><para type='war
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[attribute::type=\"warning\"][position()=5]");
- CHECK_XPATH_NODESET(n, "child::para[attribute::type=\"warning\"][position()=5]") % 15;
+ CHECK_XPATH_NODESET(c, STR("child::para[attribute::type=\"warning\"][position()=5]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[attribute::type=\"warning\"][position()=5]")) % 15;
}
TEST_XML(xpath_paths_w3c_27a, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -301,10 +301,10 @@ TEST_XML(xpath_paths_w3c_27a, "<node><para/><para type='warning'/><para type='wa
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[position()=5][attribute::type=\"warning\"]");
- CHECK_XPATH_NODESET(n, "child::para[position()=5][attribute::type=\"warning\"]");
+ CHECK_XPATH_NODESET(c, STR("child::para[position()=5][attribute::type=\"warning\"]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[position()=5][attribute::type=\"warning\"]"));
}
TEST_XML(xpath_paths_w3c_27b, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
@@ -312,10 +312,10 @@ TEST_XML(xpath_paths_w3c_27b, "<node><para/><para type='warning'/><para type='wa
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::para[position()=5][attribute::type=\"warning\"]");
- CHECK_XPATH_NODESET(n, "child::para[position()=5][attribute::type=\"warning\"]") % 9;
+ CHECK_XPATH_NODESET(c, STR("child::para[position()=5][attribute::type=\"warning\"]"));
+ CHECK_XPATH_NODESET(n, STR("child::para[position()=5][attribute::type=\"warning\"]")) % 9;
}
TEST_XML(xpath_paths_w3c_28, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
@@ -323,10 +323,10 @@ TEST_XML(xpath_paths_w3c_28, "<node><chapter><title>foo</title></chapter><chapte
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::chapter[child::title='Introduction']");
- CHECK_XPATH_NODESET(n, "child::chapter[child::title='Introduction']") % 6 % 13;
+ CHECK_XPATH_NODESET(c, STR("child::chapter[child::title='Introduction']"));
+ CHECK_XPATH_NODESET(n, STR("child::chapter[child::title='Introduction']")) % 6 % 13;
}
TEST_XML(xpath_paths_w3c_29, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
@@ -334,10 +334,10 @@ TEST_XML(xpath_paths_w3c_29, "<node><chapter><title>foo</title></chapter><chapte
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::chapter[child::title]");
- CHECK_XPATH_NODESET(n, "child::chapter[child::title]") % 3 % 6 % 9 % 13;
+ CHECK_XPATH_NODESET(c, STR("child::chapter[child::title]"));
+ CHECK_XPATH_NODESET(n, STR("child::chapter[child::title]")) % 3 % 6 % 9 % 13;
}
TEST_XML(xpath_paths_w3c_30, "<node><abstract/><chapter/><chapter/><references/><appendix/></node>")
@@ -345,10 +345,10 @@ TEST_XML(xpath_paths_w3c_30, "<node><abstract/><chapter/><chapter/><references/>
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::*[self::chapter or self::appendix]");
- CHECK_XPATH_NODESET(n, "child::*[self::chapter or self::appendix]") % 4 % 5 % 7;
+ CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix]"));
+ CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix]")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_31a, "<node><abstract/><chapter/><chapter/><references/><appendix/></node>")
@@ -356,10 +356,10 @@ TEST_XML(xpath_paths_w3c_31a, "<node><abstract/><chapter/><chapter/><references/
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::*[self::chapter or self::appendix][position()=last()]");
- CHECK_XPATH_NODESET(n, "child::*[self::chapter or self::appendix][position()=last()]") % 7;
+ CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix][position()=last()]"));
+ CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix][position()=last()]")) % 7;
}
TEST_XML(xpath_paths_w3c_31b, "<node><abstract/><chapter/><chapter/><references/><appendix/><chapter/></node>")
@@ -367,10 +367,10 @@ TEST_XML(xpath_paths_w3c_31b, "<node><abstract/><chapter/><chapter/><references/
doc.precompute_document_order();
xml_node c;
- xml_node n = doc.child("node");
+ xml_node n = doc.child(STR("node"));
- CHECK_XPATH_NODESET(c, "child::*[self::chapter or self::appendix][position()=last()]");
- CHECK_XPATH_NODESET(n, "child::*[self::chapter or self::appendix][position()=last()]") % 8;
+ CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix][position()=last()]"));
+ CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix][position()=last()]")) % 8;
}
#endif
diff --git a/tests/writer_string.cpp b/tests/writer_string.cpp
new file mode 100644
index 0000000..b2c089f
--- /dev/null
+++ b/tests/writer_string.cpp
@@ -0,0 +1,77 @@
+#include "writer_string.hpp"
+
+#include "test.hpp"
+
+static bool test_narrow(const std::string& result, const char* expected, size_t length)
+{
+ // check result
+ if (result != std::string(expected, expected + length)) return false;
+
+ // check comparison operator (incorrect implementation can theoretically early-out on zero terminators...)
+ if (length > 0 && result == std::string(expected, expected + length - 1) + "?") return false;
+
+ return true;
+}
+
+void xml_writer_string::write(const void* data, size_t size)
+{
+ contents += std::string(static_cast<const char*>(data), size);
+}
+
+std::string xml_writer_string::as_narrow() const
+{
+ return contents;
+}
+
+std::wstring xml_writer_string::as_wide() const
+{
+ CHECK(contents.size() % sizeof(wchar_t) == 0);
+
+ return std::wstring(reinterpret_cast<const wchar_t*>(contents.data()), contents.size() / sizeof(wchar_t));
+}
+
+std::basic_string<pugi::char_t> xml_writer_string::as_string() const
+{
+#ifdef PUGIXML_WCHAR_MODE // to avoid "condition is always true" warning in BCC
+ CHECK(contents.size() % sizeof(pugi::char_t) == 0);
+#endif
+
+ return std::basic_string<pugi::char_t>(reinterpret_cast<const pugi::char_t*>(contents.data()), contents.size() / sizeof(pugi::char_t));
+}
+
+std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::encoding_t encoding)
+{
+ xml_writer_string writer;
+
+ doc.save(writer, STR(""), flags, encoding);
+
+ return writer.as_narrow();
+}
+
+bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::encoding_t encoding, const char* expected, size_t length)
+{
+ return test_narrow(save_narrow(doc, flags, encoding), expected, length);
+}
+
+std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::encoding_t encoding)
+{
+ xml_writer_string writer;
+
+ node.print(writer, STR(""), flags, encoding);
+
+ return writer.as_narrow();
+}
+
+bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::encoding_t encoding, const char* expected, size_t length)
+{
+ return test_narrow(write_narrow(node, flags, encoding), expected, length);
+}
+
+std::wstring write_wide(pugi::xml_node node, unsigned int flags, pugi::encoding_t encoding)
+{
+ xml_writer_string writer;
+
+ node.print(writer, STR(""), flags, encoding);
+
+ return writer.as_wide();
+}
diff --git a/tests/writer_string.hpp b/tests/writer_string.hpp
new file mode 100644
index 0000000..1004fa0
--- /dev/null
+++ b/tests/writer_string.hpp
@@ -0,0 +1,27 @@
+#ifndef HEADER_WRITER_STRING_HPP
+#define HEADER_WRITER_STRING_HPP
+
+#include "../src/pugixml.hpp"
+
+#include <string>
+
+struct xml_writer_string: public pugi::xml_writer
+{
+ std::string contents;
+
+ virtual void write(const void* data, size_t size);
+
+ std::string as_narrow() const;
+ std::wstring as_wide() const;
+ std::basic_string<pugi::char_t> as_string() const;
+};
+
+std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::encoding_t encoding);
+bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::encoding_t encoding, const char* expected, size_t length);
+
+std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::encoding_t encoding);
+bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::encoding_t encoding, const char* expected, size_t length);
+
+std::wstring write_wide(pugi::xml_node node, unsigned int flags, pugi::encoding_t encoding);
+
+#endif