├── tests ├── data │ ├── empty.xml │ ├── small.xml │ ├── тест.xml │ ├── multiline.xml │ ├── latintest_latin1.xml │ ├── utftest_utf16_be.xml │ ├── utftest_utf16_le.xml │ ├── utftest_utf32_be.xml │ ├── utftest_utf32_le.xml │ ├── utftest_utf16_be_bom.xml │ ├── utftest_utf16_le_bom.xml │ ├── utftest_utf32_be_bom.xml │ ├── utftest_utf32_le_bom.xml │ ├── utftest_utf16_be_clean.xml │ ├── utftest_utf16_be_nodecl.xml │ ├── utftest_utf16_le_clean.xml │ ├── utftest_utf16_le_nodecl.xml │ ├── utftest_utf32_be_clean.xml │ ├── utftest_utf32_be_nodecl.xml │ ├── utftest_utf32_le_clean.xml │ ├── utftest_utf32_le_nodecl.xml │ ├── truncation.xml │ ├── latintest_utf8.xml │ ├── utftest_utf8_clean.xml │ ├── utftest_utf8_nodecl.xml │ ├── utftest_utf8.xml │ └── utftest_utf8_bom.xml ├── data_fuzz_xpath │ ├── basic.xpath │ ├── math.xpath │ ├── path.xpath │ ├── predicate.xpath │ └── functions.xpath ├── data_fuzz_parse │ ├── basic.xml │ ├── utf16.xml │ ├── utf32.xml │ ├── types.xml │ ├── refs.xml │ └── doctype.xml ├── test_header_guard.cpp ├── test_header_iosfwd_1.cpp ├── test_header_iosfwd_2.cpp ├── test_header_string_1.cpp ├── test_header_string_2.cpp ├── test_header_iostream_1.cpp ├── test_header_iostream_2.cpp ├── test_version.cpp ├── test_header_string_iostream.cpp ├── allocator.hpp ├── fuzz_parse.cpp ├── fuzz_setup.sh ├── test_header_only_1.cpp ├── test_header_only_2.cpp ├── fuzz_xpath.cpp ├── test_deprecated.cpp ├── fuzz_xpath.dict ├── writer_string.hpp ├── fuzz_parse.dict ├── helpers.hpp ├── writer_string.cpp ├── autotest-appveyor.ps1 ├── test_unicode.cpp ├── allocator.cpp ├── test_compact.cpp ├── test.cpp ├── main.cpp ├── test_memory.cpp ├── test_xpath_paths_abbrev_w3c.cpp └── test.hpp ├── .gitattributes ├── .gitignore ├── docs ├── images │ ├── dom_tree.png │ ├── vs2005_link1.png │ ├── vs2005_link2.png │ ├── vs2005_pch1.png │ ├── vs2005_pch2.png │ ├── vs2005_pch3.png │ ├── vs2005_pch4.png │ ├── vs2010_link1.png │ └── vs2010_link2.png ├── samples │ ├── weekly-utf-16.xml │ ├── weekly-shift_jis.xml │ ├── character.xml │ ├── transitions.xml │ ├── tree.xml │ ├── load_file.cpp │ ├── save_stream.cpp │ ├── save_file.cpp │ ├── custom_memory_management.cpp │ ├── traverse_iter.cpp │ ├── xgconsole.xml │ ├── save_declaration.cpp │ ├── modify_remove.cpp │ ├── traverse_rangefor.cpp │ ├── modify_add.cpp │ ├── save_subtree.cpp │ ├── xpath_select.cpp │ ├── traverse_walker.cpp │ ├── xpath_error.cpp │ ├── load_error_handling.cpp │ ├── text.cpp │ ├── xpath_variables.cpp │ ├── xpath_query.cpp │ ├── save_options.cpp │ ├── traverse_predicate.cpp │ ├── load_options.cpp │ ├── modify_base.cpp │ ├── traverse_base.cpp │ ├── weekly-utf-8.xml │ ├── include.cpp │ ├── load_memory.cpp │ ├── save_custom_writer.cpp │ └── load_stream.cpp └── config.adoc ├── .codecov.yml ├── scripts ├── cocoapods_push.sh ├── pugixml_airplay.mkf ├── pugixml.pc.in ├── pugixml.podspec ├── pugixml-config.cmake.in ├── nuget │ ├── build │ │ └── native │ │ │ ├── pugixml-propertiesui.xml │ │ │ └── pugixml.targets │ └── pugixml.nuspec ├── pugixml_codeblocks.cbp ├── pugixml_dll.rc ├── archive.py ├── nuget_build.ps1 ├── pugixml_codelite.project ├── premake4.lua ├── natvis │ └── pugixml.natvis ├── pugixml.xcodeproj │ └── project.pbxproj ├── pugixml_vs2008.vcproj ├── pugixml_vs2008_static.vcproj ├── pugixml_vs2005.vcproj ├── pugixml_vs2005_static.vcproj └── pugixml_vs2015.vcxproj ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── config.yml │ └── bug_report.md └── workflows │ └── build.yml ├── SECURITY.md ├── LICENSE.md ├── appveyor.yml ├── readme.txt ├── Makefile ├── src └── pugiconfig.hpp └── README.md /tests/data/empty.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/data/small.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/data/тест.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | tests/data/* -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /.vscode/ 3 | -------------------------------------------------------------------------------- /tests/data_fuzz_xpath/basic.xpath: -------------------------------------------------------------------------------- 1 | a/b/c -------------------------------------------------------------------------------- /tests/data_fuzz_parse/basic.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/data_fuzz_xpath/math.xpath: -------------------------------------------------------------------------------- 1 | 1+2*3 div 4 mod 5-6 -------------------------------------------------------------------------------- /tests/data/multiline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/data_fuzz_xpath/path.xpath: -------------------------------------------------------------------------------- 1 | @*/ancestor::*/near-north/*[4]/@*/preceding::text() -------------------------------------------------------------------------------- /tests/data_fuzz_xpath/predicate.xpath: -------------------------------------------------------------------------------- 1 | library/nodes[@id=12]/element[@type='translate'][1] -------------------------------------------------------------------------------- /docs/images/dom_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/dom_tree.png -------------------------------------------------------------------------------- /tests/data_fuzz_xpath/functions.xpath: -------------------------------------------------------------------------------- 1 | sum(nodes) + round(concat(//a[translate(@id, 'abc', '012')])) 2 | -------------------------------------------------------------------------------- /docs/images/vs2005_link1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2005_link1.png -------------------------------------------------------------------------------- /docs/images/vs2005_link2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2005_link2.png -------------------------------------------------------------------------------- /docs/images/vs2005_pch1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2005_pch1.png -------------------------------------------------------------------------------- /docs/images/vs2005_pch2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2005_pch2.png -------------------------------------------------------------------------------- /docs/images/vs2005_pch3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2005_pch3.png -------------------------------------------------------------------------------- /docs/images/vs2005_pch4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2005_pch4.png -------------------------------------------------------------------------------- /docs/images/vs2010_link1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2010_link1.png -------------------------------------------------------------------------------- /docs/images/vs2010_link2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/images/vs2010_link2.png -------------------------------------------------------------------------------- /docs/samples/weekly-utf-16.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/samples/weekly-utf-16.xml -------------------------------------------------------------------------------- /docs/samples/weekly-shift_jis.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/docs/samples/weekly-shift_jis.xml -------------------------------------------------------------------------------- /tests/data/latintest_latin1.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/latintest_latin1.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf16_be.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_be.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf16_le.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_le.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_be.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_be.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_le.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_le.xml -------------------------------------------------------------------------------- /tests/data_fuzz_parse/utf16.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data_fuzz_parse/utf16.xml -------------------------------------------------------------------------------- /tests/data_fuzz_parse/utf32.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data_fuzz_parse/utf32.xml -------------------------------------------------------------------------------- /tests/test_header_guard.cpp: -------------------------------------------------------------------------------- 1 | // Tests header guards 2 | #include "../src/pugixml.hpp" 3 | #include "../src/pugixml.hpp" 4 | -------------------------------------------------------------------------------- /tests/data/utftest_utf16_be_bom.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_be_bom.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf16_le_bom.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_le_bom.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_be_bom.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_be_bom.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_le_bom.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_le_bom.xml -------------------------------------------------------------------------------- /tests/test_header_iosfwd_1.cpp: -------------------------------------------------------------------------------- 1 | // Tests compatibility with iosfwd 2 | #include "../src/pugixml.hpp" 3 | #include 4 | -------------------------------------------------------------------------------- /tests/test_header_iosfwd_2.cpp: -------------------------------------------------------------------------------- 1 | // Tests compatibility with iosfwd 2 | #include 3 | #include "../src/pugixml.hpp" 4 | -------------------------------------------------------------------------------- /tests/test_header_string_1.cpp: -------------------------------------------------------------------------------- 1 | // Tests compatibility with string 2 | #include "../src/pugixml.hpp" 3 | #include 4 | -------------------------------------------------------------------------------- /tests/test_header_string_2.cpp: -------------------------------------------------------------------------------- 1 | // Tests compatibility with string 2 | #include 3 | #include "../src/pugixml.hpp" 4 | -------------------------------------------------------------------------------- /tests/data/utftest_utf16_be_clean.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_be_clean.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf16_be_nodecl.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_be_nodecl.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf16_le_clean.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_le_clean.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf16_le_nodecl.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf16_le_nodecl.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_be_clean.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_be_clean.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_be_nodecl.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_be_nodecl.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_le_clean.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_le_clean.xml -------------------------------------------------------------------------------- /tests/data/utftest_utf32_le_nodecl.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinghRajenM/pugixml/master/tests/data/utftest_utf32_le_nodecl.xml -------------------------------------------------------------------------------- /tests/test_header_iostream_1.cpp: -------------------------------------------------------------------------------- 1 | // Tests compatibility with iostream 2 | #include "../src/pugixml.hpp" 3 | #include 4 | -------------------------------------------------------------------------------- /tests/test_header_iostream_2.cpp: -------------------------------------------------------------------------------- 1 | // Tests compatibility with iostream 2 | #include 3 | #include "../src/pugixml.hpp" 4 | -------------------------------------------------------------------------------- /tests/test_version.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/pugixml.hpp" 2 | 3 | #if PUGIXML_VERSION != 1120 4 | #error Unexpected pugixml version 5 | #endif 6 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | coverage: 3 | status: 4 | project: 5 | default: 6 | informational: true 7 | patch: off 8 | -------------------------------------------------------------------------------- /scripts/cocoapods_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Push to igagis repo for now 4 | pod repo push igagis pugixml.podspec --use-libraries --verbose 5 | -------------------------------------------------------------------------------- /tests/data_fuzz_parse/types.xml: -------------------------------------------------------------------------------- 1 | pcdata -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /tests/data_fuzz_parse/refs.xml: -------------------------------------------------------------------------------- 1 | pcdata < > & " ' « &unknown; %entity; -------------------------------------------------------------------------------- /tests/test_header_string_iostream.cpp: -------------------------------------------------------------------------------- 1 | // Tests compatibility with string/iostream 2 | #include 3 | #include "../src/pugixml.hpp" 4 | #include 5 | #include 6 | -------------------------------------------------------------------------------- /scripts/pugixml_airplay.mkf: -------------------------------------------------------------------------------- 1 | includepaths 2 | { 3 | "../src" 4 | } 5 | 6 | files 7 | { 8 | ("../src") 9 | pugiconfig.hpp 10 | pugixml.cpp 11 | pugixml.hpp 12 | } 13 | 14 | -------------------------------------------------------------------------------- /docs/config.adoc: -------------------------------------------------------------------------------- 1 | website ; repository 2 | :toc: right 3 | :source-highlighter: pygments 4 | :source-language: c++ 5 | :sectanchors: 6 | :sectlinks: 7 | :imagesdir: images 8 | -------------------------------------------------------------------------------- /docs/samples/character.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Help and support 4 | url: https://github.com/zeux/pugixml/discussions 5 | about: Please use GitHub Discussions if you have questions or need help. 6 | -------------------------------------------------------------------------------- /docs/samples/transitions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/allocator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_TEST_ALLOCATOR_HPP 2 | #define HEADER_TEST_ALLOCATOR_HPP 3 | 4 | #include 5 | 6 | void* memory_allocate(size_t size); 7 | size_t memory_size(void* ptr); 8 | void memory_deallocate(void* ptr); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report if you believe you've found a bug in this project; please use GitHub Discussions instead if you think the bug may be in your code. 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /docs/samples/tree.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | some text 5 | 6 | some more text 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Please verify that the vulnerabilities reported can be reproduced on the [latest released version](https://github.com/zeux/pugixml/releases). 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Vulnerabilities can be reported via e-mail to the [project maintainer](https://github.com/zeux). 10 | -------------------------------------------------------------------------------- /tests/fuzz_parse.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/pugixml.hpp" 2 | 3 | #include 4 | 5 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) 6 | { 7 | pugi::xml_document doc; 8 | 9 | doc.load_buffer(Data, Size); 10 | doc.load_buffer(Data, Size, pugi::parse_minimal); 11 | doc.load_buffer(Data, Size, pugi::parse_full); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /docs/samples/load_file.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | // tag::code[] 8 | pugi::xml_document doc; 9 | 10 | pugi::xml_parse_result result = doc.load_file("tree.xml"); 11 | 12 | std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; 13 | // end::code[] 14 | } 15 | 16 | // vim:et 17 | -------------------------------------------------------------------------------- /docs/samples/save_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | // get a test document 8 | pugi::xml_document doc; 9 | doc.load_string("hey"); 10 | 11 | // tag::code[] 12 | // save document to standard output 13 | std::cout << "Document:\n"; 14 | doc.save(std::cout); 15 | // end::code[] 16 | } 17 | 18 | // vim:et 19 | -------------------------------------------------------------------------------- /tests/data_fuzz_parse/doctype.xml: -------------------------------------------------------------------------------- 1 | ]> ]]> ]> ]> -------------------------------------------------------------------------------- /docs/samples/save_file.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | // get a test document 8 | pugi::xml_document doc; 9 | doc.load_string("hey"); 10 | 11 | // tag::code[] 12 | // save document to file 13 | std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl; 14 | // end::code[] 15 | } 16 | 17 | // vim:et 18 | -------------------------------------------------------------------------------- /scripts/pugixml.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@@INSTALL_SUFFIX@ 4 | libdir=@CMAKE_INSTALL_FULL_LIBDIR@@INSTALL_SUFFIX@ 5 | 6 | Name: pugixml 7 | Description: Light-weight, simple and fast XML parser for C++ with XPath support. 8 | URL: https://pugixml.org/ 9 | Version: @pugixml_VERSION@ 10 | Cflags: -I${includedir} 11 | Libs: -L${libdir} -lpugixml@LIB_POSTFIX@ 12 | -------------------------------------------------------------------------------- /tests/data/truncation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | some text 7 | 8 | some more text 9 | 10 | 11 | <汉语 名字="name" 价值="value">世界有很多语言𤭢 12 | 13 | 14 | <氏名> 15 | <氏>山田 16 | <名>太郎 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/fuzz_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo apt-get --yes install subversion screen gcc g++ cmake ninja-build golang autoconf libtool apache2 python-dev pkg-config zlib1g-dev libgcrypt11-dev 4 | 5 | mkdir -p clang 6 | cd clang 7 | git clone https://chromium.googlesource.com/chromium/src/tools/clang 8 | cd .. 9 | clang/clang/scripts/update.py 10 | sudo cp -rf third_party/llvm-build/Release+Asserts/lib/* /usr/local/lib/ 11 | sudo cp -rf third_party/llvm-build/Release+Asserts/bin/* /usr/local/bin 12 | -------------------------------------------------------------------------------- /tests/test_header_only_1.cpp: -------------------------------------------------------------------------------- 1 | #define PUGIXML_HEADER_ONLY 2 | #define pugi pugih 3 | 4 | #include "test.hpp" 5 | 6 | // Check header guards 7 | #include "../src/pugixml.hpp" 8 | #include "../src/pugixml.hpp" 9 | 10 | using namespace pugi; 11 | 12 | TEST(header_only_1) 13 | { 14 | xml_document doc; 15 | CHECK(doc.load_string(STR(""))); 16 | CHECK_STRING(doc.first_child().name(), STR("node")); 17 | 18 | #ifndef PUGIXML_NO_XPATH 19 | CHECK(doc.first_child() == doc.select_node(STR("//*")).node()); 20 | #endif 21 | } 22 | -------------------------------------------------------------------------------- /tests/test_header_only_2.cpp: -------------------------------------------------------------------------------- 1 | #define PUGIXML_HEADER_ONLY 2 | #define pugi pugih 3 | 4 | #include "test.hpp" 5 | 6 | // Check header guards 7 | #include "../src/pugixml.hpp" 8 | #include "../src/pugixml.hpp" 9 | 10 | using namespace pugi; 11 | 12 | TEST(header_only_2) 13 | { 14 | xml_document doc; 15 | CHECK(doc.load_string(STR(""))); 16 | CHECK_STRING(doc.first_child().name(), STR("node")); 17 | 18 | #ifndef PUGIXML_NO_XPATH 19 | CHECK(doc.first_child() == doc.select_node(STR("//*")).node()); 20 | #endif 21 | } 22 | -------------------------------------------------------------------------------- /tests/fuzz_xpath.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) 7 | { 8 | char* text = new char[Size + 1]; 9 | memcpy(text, Data, Size); 10 | text[Size] = 0; 11 | 12 | #ifdef PUGIXML_NO_EXCEPTIONS 13 | pugi::xpath_query q(text); 14 | #else 15 | try 16 | { 17 | pugi::xpath_query q(text); 18 | } 19 | catch (pugi::xpath_exception&) 20 | { 21 | } 22 | #endif 23 | 24 | delete[] text; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /scripts/pugixml.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "pugixml" 3 | s.version = "1.12" 4 | s.summary = "C++ XML parser library." 5 | s.homepage = "https://pugixml.org" 6 | s.license = "MIT" 7 | s.author = { "Arseny Kapoulkine" => "arseny.kapoulkine@gmail.com" } 8 | s.platform = :ios, "7.0" 9 | 10 | s.source = { :git => "https://github.com/zeux/pugixml.git", :tag => "v" + s.version.to_s } 11 | 12 | s.source_files = "src/**/*.{hpp,cpp}" 13 | s.header_mappings_dir = "src" 14 | end 15 | -------------------------------------------------------------------------------- /tests/data/latintest_utf8.xml: -------------------------------------------------------------------------------- 1 |
00000535351010MüllerJörg
<Test>
10
<Test 2>
20
This is a text.
-------------------------------------------------------------------------------- /docs/samples/custom_memory_management.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | // tag::decl[] 6 | void* custom_allocate(size_t size) 7 | { 8 | return new (std::nothrow) char[size]; 9 | } 10 | 11 | void custom_deallocate(void* ptr) 12 | { 13 | delete[] static_cast(ptr); 14 | } 15 | // end::decl[] 16 | 17 | int main() 18 | { 19 | // tag::call[] 20 | pugi::set_memory_management_functions(custom_allocate, custom_deallocate); 21 | // end::call[] 22 | 23 | pugi::xml_document doc; 24 | doc.load_string(""); 25 | } 26 | 27 | // vim:et 28 | -------------------------------------------------------------------------------- /scripts/pugixml-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/pugixml-targets.cmake") 4 | 5 | # If the user is not requiring 1.11 (either by explicitly requesting an older 6 | # version or not requesting one at all), provide the old imported target name 7 | # for compatibility. 8 | if (NOT TARGET pugixml AND (NOT DEFINED PACKAGE_FIND_VERSION OR PACKAGE_FIND_VERSION VERSION_LESS "1.11")) 9 | add_library(pugixml INTERFACE IMPORTED) 10 | # Equivalent to target_link_libraries INTERFACE, but compatible with CMake 3.10 11 | set_target_properties(pugixml PROPERTIES INTERFACE_LINK_LIBRARIES pugixml::pugixml) 12 | endif () 13 | -------------------------------------------------------------------------------- /docs/samples/traverse_iter.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | if (!doc.load_file("xgconsole.xml")) return -1; 9 | 10 | pugi::xml_node tools = doc.child("Profile").child("Tools"); 11 | 12 | // tag::code[] 13 | for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it) 14 | { 15 | std::cout << "Tool:"; 16 | 17 | for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait) 18 | { 19 | std::cout << " " << ait->name() << "=" << ait->value(); 20 | } 21 | 22 | std::cout << std::endl; 23 | } 24 | // end::code[] 25 | } 26 | 27 | // vim:et 28 | -------------------------------------------------------------------------------- /tests/test_deprecated.cpp: -------------------------------------------------------------------------------- 1 | #define PUGIXML_DEPRECATED // Suppress deprecated declarations to avoid warnings 2 | 3 | #include "test.hpp" 4 | 5 | using namespace pugi; 6 | 7 | TEST(document_deprecated_load) 8 | { 9 | xml_document doc; 10 | CHECK(doc.load(STR(""))); 11 | CHECK_NODE(doc, STR("")); 12 | } 13 | 14 | #ifndef PUGIXML_NO_XPATH 15 | TEST_XML(xpath_api_deprecated_select_single_node, "") 16 | { 17 | xpath_node n1 = doc.select_single_node(STR("node/foo")); 18 | 19 | xpath_query q(STR("node/foo")); 20 | xpath_node n2 = doc.select_single_node(q); 21 | 22 | CHECK(n1.node().attribute(STR("id")).as_int() == 1); 23 | CHECK(n2.node().attribute(STR("id")).as_int() == 1); 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /docs/samples/xgconsole.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jamplus build system 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/samples/save_declaration.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | // tag::code[] 8 | // get a test document 9 | pugi::xml_document doc; 10 | doc.load_string("hey"); 11 | 12 | // add a custom declaration node 13 | pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); 14 | decl.append_attribute("version") = "1.0"; 15 | decl.append_attribute("encoding") = "UTF-8"; 16 | decl.append_attribute("standalone") = "no"; 17 | 18 | // 19 | // 20 | // hey 21 | // 22 | doc.save(std::cout); 23 | std::cout << std::endl; 24 | // end::code[] 25 | } 26 | 27 | // vim:et 28 | -------------------------------------------------------------------------------- /docs/samples/modify_remove.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | if (!doc.load_string("Simple node")) return -1; 9 | 10 | // tag::code[] 11 | // remove description node with the whole subtree 12 | pugi::xml_node node = doc.child("node"); 13 | node.remove_child("description"); 14 | 15 | // remove id attribute 16 | pugi::xml_node param = node.child("param"); 17 | param.remove_attribute("value"); 18 | 19 | // we can also remove nodes/attributes by handles 20 | pugi::xml_attribute id = param.attribute("name"); 21 | param.remove_attribute(id); 22 | // end::code[] 23 | 24 | doc.print(std::cout); 25 | } 26 | 27 | // vim:et 28 | -------------------------------------------------------------------------------- /docs/samples/traverse_rangefor.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | if (!doc.load_file("xgconsole.xml")) return -1; 9 | 10 | pugi::xml_node tools = doc.child("Profile").child("Tools"); 11 | 12 | // tag::code[] 13 | for (pugi::xml_node tool: tools.children("Tool")) 14 | { 15 | std::cout << "Tool:"; 16 | 17 | for (pugi::xml_attribute attr: tool.attributes()) 18 | { 19 | std::cout << " " << attr.name() << "=" << attr.value(); 20 | } 21 | 22 | for (pugi::xml_node child: tool.children()) 23 | { 24 | std::cout << ", child " << child.name(); 25 | } 26 | 27 | std::cout << std::endl; 28 | } 29 | // end::code[] 30 | } 31 | 32 | // vim:et 33 | -------------------------------------------------------------------------------- /docs/samples/modify_add.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | 9 | // tag::code[] 10 | // add node with some name 11 | pugi::xml_node node = doc.append_child("node"); 12 | 13 | // add description node with text child 14 | pugi::xml_node descr = node.append_child("description"); 15 | descr.append_child(pugi::node_pcdata).set_value("Simple node"); 16 | 17 | // add param node before the description 18 | pugi::xml_node param = node.insert_child_before("param", descr); 19 | 20 | // add attributes to param node 21 | param.append_attribute("name") = "version"; 22 | param.append_attribute("value") = 1.1; 23 | param.insert_attribute_after("type", param.attribute("name")) = "float"; 24 | // end::code[] 25 | 26 | doc.print(std::cout); 27 | } 28 | 29 | // vim:et 30 | -------------------------------------------------------------------------------- /docs/samples/save_subtree.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | // tag::code[] 8 | // get a test document 9 | pugi::xml_document doc; 10 | doc.load_string("hey"); 11 | 12 | // print document to standard output (prints hey) 13 | doc.save(std::cout, "", pugi::format_raw); 14 | std::cout << std::endl; 15 | 16 | // print document to standard output as a regular node (prints hey) 17 | doc.print(std::cout, "", pugi::format_raw); 18 | std::cout << std::endl; 19 | 20 | // print a subtree to standard output (prints hey) 21 | doc.child("foo").child("call").print(std::cout, "", pugi::format_raw); 22 | std::cout << std::endl; 23 | // end::code[] 24 | } 25 | 26 | // vim:et 27 | -------------------------------------------------------------------------------- /docs/samples/xpath_select.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | if (!doc.load_file("xgconsole.xml")) return -1; 9 | 10 | // tag::code[] 11 | pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']"); 12 | 13 | std::cout << "Tools:\n"; 14 | 15 | for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it) 16 | { 17 | pugi::xpath_node node = *it; 18 | std::cout << node.node().attribute("Filename").value() << "\n"; 19 | } 20 | 21 | pugi::xpath_node build_tool = doc.select_node("//Tool[contains(Description, 'build system')]"); 22 | 23 | if (build_tool) 24 | std::cout << "Build tool: " << build_tool.node().attribute("Filename").value() << "\n"; 25 | // end::code[] 26 | } 27 | 28 | // vim:et 29 | -------------------------------------------------------------------------------- /docs/samples/traverse_walker.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | const char* node_types[] = 6 | { 7 | "null", "document", "element", "pcdata", "cdata", "comment", "pi", "declaration" 8 | }; 9 | 10 | // tag::impl[] 11 | struct simple_walker: pugi::xml_tree_walker 12 | { 13 | virtual bool for_each(pugi::xml_node& node) 14 | { 15 | for (int i = 0; i < depth(); ++i) std::cout << " "; // indentation 16 | 17 | std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n"; 18 | 19 | return true; // continue traversal 20 | } 21 | }; 22 | // end::impl[] 23 | 24 | int main() 25 | { 26 | pugi::xml_document doc; 27 | if (!doc.load_file("tree.xml")) return -1; 28 | 29 | // tag::traverse[] 30 | simple_walker walker; 31 | doc.traverse(walker); 32 | // end::traverse[] 33 | } 34 | 35 | // vim:et 36 | -------------------------------------------------------------------------------- /tests/fuzz_xpath.dict: -------------------------------------------------------------------------------- 1 | "boolean" 2 | "count" 3 | "contains" 4 | "concat" 5 | "ceiling" 6 | "false" 7 | "floor" 8 | "id" 9 | "last" 10 | "lang" 11 | "local-name" 12 | "name" 13 | "namespace-uri" 14 | "normalize-space" 15 | "not" 16 | "number" 17 | "position" 18 | "round" 19 | "string" 20 | "string-length" 21 | "starts-with" 22 | "substring-before" 23 | "substring-after" 24 | "substring" 25 | "sum" 26 | "translate" 27 | "true" 28 | "ancestor" 29 | "ancestor-or-self" 30 | "attribute" 31 | "child" 32 | "descendant" 33 | "descendant-or-self" 34 | "following" 35 | "following-sibling" 36 | "namespace" 37 | "parent" 38 | "preceding" 39 | "preceding-sibling" 40 | "self" 41 | "comment" 42 | "node" 43 | "processing-instruction" 44 | "text" 45 | "or" 46 | "and" 47 | "div" 48 | "mod" 49 | ">" 50 | ">=" 51 | "<" 52 | "<=" 53 | "!" 54 | "!=" 55 | "=" 56 | "+" 57 | "-" 58 | "*" 59 | "|" 60 | "$" 61 | "(" 62 | ")" 63 | "[" 64 | "]" 65 | "," 66 | "//" 67 | "/" 68 | ".." 69 | "." 70 | "@" 71 | "::" 72 | ":" 73 | -------------------------------------------------------------------------------- /docs/samples/xpath_error.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | if (!doc.load_file("xgconsole.xml")) return -1; 9 | 10 | // tag::code[] 11 | // Exception is thrown for incorrect query syntax 12 | try 13 | { 14 | doc.select_nodes("//nodes[#true()]"); 15 | } 16 | catch (const pugi::xpath_exception& e) 17 | { 18 | std::cout << "Select failed: " << e.what() << std::endl; 19 | } 20 | 21 | // Exception is thrown for incorrect query semantics 22 | try 23 | { 24 | doc.select_nodes("(123)/next"); 25 | } 26 | catch (const pugi::xpath_exception& e) 27 | { 28 | std::cout << "Select failed: " << e.what() << std::endl; 29 | } 30 | 31 | // Exception is thrown for query with incorrect return type 32 | try 33 | { 34 | doc.select_nodes("123"); 35 | } 36 | catch (const pugi::xpath_exception& e) 37 | { 38 | std::cout << "Select failed: " << e.what() << std::endl; 39 | } 40 | // end::code[] 41 | } 42 | 43 | // vim:et 44 | -------------------------------------------------------------------------------- /scripts/nuget/build/native/pugixml-propertiesui.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/writer_string.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_TEST_WRITER_STRING_HPP 2 | #define HEADER_TEST_WRITER_STRING_HPP 3 | 4 | #include "../src/pugixml.hpp" 5 | 6 | #include 7 | 8 | struct xml_writer_string: public pugi::xml_writer 9 | { 10 | std::string contents; 11 | 12 | virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; 13 | 14 | std::string as_narrow() const; 15 | std::basic_string as_wide() const; 16 | std::basic_string as_string() const; 17 | }; 18 | 19 | std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding); 20 | bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length); 21 | 22 | std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding); 23 | bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length); 24 | 25 | std::basic_string write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2006-2022 Arseny Kapoulkine 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /docs/samples/load_error_handling.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | void check_xml(const char* source) 6 | { 7 | // tag::code[] 8 | pugi::xml_document doc; 9 | pugi::xml_parse_result result = doc.load_string(source); 10 | 11 | if (result) 12 | { 13 | std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n"; 14 | } 15 | else 16 | { 17 | std::cout << "XML [" << source << "] parsed with errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n"; 18 | std::cout << "Error description: " << result.description() << "\n"; 19 | std::cout << "Error offset: " << result.offset << " (error at [..." << (source + result.offset) << "]\n\n"; 20 | } 21 | // end::code[] 22 | } 23 | 24 | int main() 25 | { 26 | check_xml("text"); 27 | check_xml("text"); 28 | check_xml("text"); 29 | check_xml("<#tag />"); 31 | } 32 | 33 | // vim:et 34 | -------------------------------------------------------------------------------- /docs/samples/text.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | 9 | // get a test document 10 | doc.load_string("test1.1yes"); 11 | 12 | pugi::xml_node project = doc.child("project"); 13 | 14 | // tag::access[] 15 | std::cout << "Project name: " << project.child("name").text().get() << std::endl; 16 | std::cout << "Project version: " << project.child("version").text().as_double() << std::endl; 17 | std::cout << "Project visibility: " << (project.child("public").text().as_bool(/* def= */ true) ? "public" : "private") << std::endl; 18 | std::cout << "Project description: " << project.child("description").text().get() << std::endl; 19 | // end::access[] 20 | 21 | std::cout << std::endl; 22 | 23 | // tag::modify[] 24 | // change project version 25 | project.child("version").text() = 1.2; 26 | 27 | // add description element and set the contents 28 | // note that we do not have to explicitly add the node_pcdata child 29 | project.append_child("description").text().set("a test project"); 30 | // end::modify[] 31 | 32 | doc.save(std::cout); 33 | } 34 | 35 | // vim:et 36 | -------------------------------------------------------------------------------- /docs/samples/xpath_variables.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | pugi::xml_document doc; 9 | if (!doc.load_file("xgconsole.xml")) return -1; 10 | 11 | // tag::code[] 12 | // Select nodes via compiled query 13 | pugi::xpath_variable_set vars; 14 | vars.add("remote", pugi::xpath_type_boolean); 15 | 16 | pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars); 17 | 18 | vars.set("remote", true); 19 | pugi::xpath_node_set tools_remote = query_remote_tools.evaluate_node_set(doc); 20 | 21 | vars.set("remote", false); 22 | pugi::xpath_node_set tools_local = query_remote_tools.evaluate_node_set(doc); 23 | 24 | std::cout << "Remote tool: "; 25 | tools_remote[2].node().print(std::cout); 26 | 27 | std::cout << "Local tool: "; 28 | tools_local[0].node().print(std::cout); 29 | 30 | // You can pass the context directly to select_nodes/select_node 31 | pugi::xpath_node_set tools_local_imm = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars); 32 | 33 | std::cout << "Local tool imm: "; 34 | tools_local_imm[0].node().print(std::cout); 35 | // end::code[] 36 | } 37 | 38 | // vim:et 39 | -------------------------------------------------------------------------------- /scripts/pugixml_codeblocks.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/samples/xpath_query.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | pugi::xml_document doc; 9 | if (!doc.load_file("xgconsole.xml")) return -1; 10 | 11 | // tag::code[] 12 | // Select nodes via compiled query 13 | pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote='true']"); 14 | 15 | pugi::xpath_node_set tools = query_remote_tools.evaluate_node_set(doc); 16 | std::cout << "Remote tool: "; 17 | tools[2].node().print(std::cout); 18 | 19 | // Evaluate numbers via compiled query 20 | pugi::xpath_query query_timeouts("sum(//Tool/@Timeout)"); 21 | std::cout << query_timeouts.evaluate_number(doc) << std::endl; 22 | 23 | // Evaluate strings via compiled query for different context nodes 24 | pugi::xpath_query query_name_valid("string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks"); 25 | pugi::xpath_query query_name("concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)"); 26 | 27 | for (pugi::xml_node tool = doc.first_element_by_path("Profile/Tools/Tool"); tool; tool = tool.next_sibling()) 28 | { 29 | std::string s = query_name.evaluate_string(tool); 30 | 31 | if (query_name_valid.evaluate_boolean(tool)) std::cout << s << std::endl; 32 | } 33 | // end::code[] 34 | } 35 | 36 | // vim:et 37 | -------------------------------------------------------------------------------- /docs/samples/save_options.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | // tag::code[] 8 | // get a test document 9 | pugi::xml_document doc; 10 | doc.load_string("hey"); 11 | 12 | // default options; prints 13 | // 14 | // 15 | // hey 16 | // 17 | doc.save(std::cout); 18 | std::cout << std::endl; 19 | 20 | // default options with custom indentation string; prints 21 | // 22 | // 23 | // --hey 24 | // 25 | doc.save(std::cout, "--"); 26 | std::cout << std::endl; 27 | 28 | // default options without indentation; prints 29 | // 30 | // 31 | // hey 32 | // 33 | doc.save(std::cout, "\t", pugi::format_default & ~pugi::format_indent); // can also pass "" instead of indentation string for the same effect 34 | std::cout << std::endl; 35 | 36 | // raw output; prints 37 | // hey 38 | doc.save(std::cout, "\t", pugi::format_raw); 39 | std::cout << std::endl << std::endl; 40 | 41 | // raw output without declaration; prints 42 | // hey 43 | doc.save(std::cout, "\t", pugi::format_raw | pugi::format_no_declaration); 44 | std::cout << std::endl; 45 | // end::code[] 46 | } 47 | 48 | // vim:et 49 | -------------------------------------------------------------------------------- /docs/samples/traverse_predicate.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | // tag::decl[] 7 | bool small_timeout(pugi::xml_node node) 8 | { 9 | return node.attribute("Timeout").as_int() < 20; 10 | } 11 | 12 | struct allow_remote_predicate 13 | { 14 | bool operator()(pugi::xml_attribute attr) const 15 | { 16 | return strcmp(attr.name(), "AllowRemote") == 0; 17 | } 18 | 19 | bool operator()(pugi::xml_node node) const 20 | { 21 | return node.attribute("AllowRemote").as_bool(); 22 | } 23 | }; 24 | // end::decl[] 25 | 26 | int main() 27 | { 28 | pugi::xml_document doc; 29 | if (!doc.load_file("xgconsole.xml")) return -1; 30 | 31 | pugi::xml_node tools = doc.child("Profile").child("Tools"); 32 | 33 | // tag::find[] 34 | // Find child via predicate (looks for direct children only) 35 | std::cout << tools.find_child(allow_remote_predicate()).attribute("Filename").value() << std::endl; 36 | 37 | // Find node via predicate (looks for all descendants in depth-first order) 38 | std::cout << doc.find_node(allow_remote_predicate()).attribute("Filename").value() << std::endl; 39 | 40 | // Find attribute via predicate 41 | std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl; 42 | 43 | // We can use simple functions instead of function objects 44 | std::cout << tools.find_child(small_timeout).attribute("Filename").value() << std::endl; 45 | // end::find[] 46 | } 47 | 48 | // vim:et 49 | -------------------------------------------------------------------------------- /docs/samples/load_options.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | pugi::xml_document doc; 8 | 9 | // tag::code[] 10 | const char* source = "<"; 11 | 12 | // Parsing with default options; note that comment node is not added to the tree, and entity reference < is expanded 13 | doc.load_string(source); 14 | std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; 15 | 16 | // Parsing with additional parse_comments option; comment node is now added to the tree 17 | doc.load_string(source, pugi::parse_default | pugi::parse_comments); 18 | std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; 19 | 20 | // Parsing with additional parse_comments option and without the (default) parse_escapes option; < is not expanded 21 | doc.load_string(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes); 22 | std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; 23 | 24 | // Parsing with minimal option mask; comment node is not added to the tree, and < is not expanded 25 | doc.load_string(source, pugi::parse_minimal); 26 | std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; 27 | // end::code[] 28 | } 29 | 30 | // vim:et 31 | -------------------------------------------------------------------------------- /docs/samples/modify_base.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | pugi::xml_document doc; 9 | if (!doc.load_string("text", pugi::parse_default | pugi::parse_comments)) return -1; 10 | 11 | // tag::node[] 12 | pugi::xml_node node = doc.child("node"); 13 | 14 | // change node name 15 | std::cout << node.set_name("notnode"); 16 | std::cout << ", new node name: " << node.name() << std::endl; 17 | 18 | // change comment text 19 | std::cout << doc.last_child().set_value("useless comment"); 20 | std::cout << ", new comment text: " << doc.last_child().value() << std::endl; 21 | 22 | // we can't change value of the element or name of the comment 23 | std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl; 24 | // end::node[] 25 | 26 | // tag::attr[] 27 | pugi::xml_attribute attr = node.attribute("id"); 28 | 29 | // change attribute name/value 30 | std::cout << attr.set_name("key") << ", " << attr.set_value("345"); 31 | std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl; 32 | 33 | // we can use numbers or booleans 34 | attr.set_value(1.234); 35 | std::cout << "new attribute value: " << attr.value() << std::endl; 36 | 37 | // we can also use assignment operators for more concise code 38 | attr = true; 39 | std::cout << "final attribute value: " << attr.value() << std::endl; 40 | // end::attr[] 41 | } 42 | 43 | // vim:et 44 | -------------------------------------------------------------------------------- /scripts/pugixml_dll.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PUGIXML_VERSION_MAJOR 1 4 | #define PUGIXML_VERSION_MINOR 12 5 | #define PUGIXML_VERSION_PATCH 0 6 | #define PUGIXML_VERSION_NUMBER "1.12.0\0" 7 | 8 | #if defined(GCC_WINDRES) || defined(__MINGW32__) || defined(__CYGWIN__) 9 | VS_VERSION_INFO VERSIONINFO 10 | #else 11 | VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE 12 | #endif 13 | FILEVERSION PUGIXML_VERSION_MAJOR,PUGIXML_VERSION_MINOR,PUGIXML_VERSION_PATCH,0 14 | PRODUCTVERSION PUGIXML_VERSION_MAJOR,PUGIXML_VERSION_MINOR,PUGIXML_VERSION_PATCH,0 15 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 16 | #ifdef _DEBUG 17 | FILEFLAGS 1 18 | #else 19 | FILEFLAGS 0 20 | #endif 21 | FILEOS VOS__WINDOWS32 22 | FILETYPE VFT_DLL 23 | FILESUBTYPE 0 // not used 24 | BEGIN 25 | BLOCK "StringFileInfo" 26 | BEGIN 27 | BLOCK "040904E4" 28 | //language ID = U.S. English, char set = Windows, Multilingual 29 | BEGIN 30 | VALUE "CompanyName", "zeux/pugixml\0" 31 | VALUE "FileDescription", "pugixml library\0" 32 | VALUE "FileVersion", PUGIXML_VERSION_NUMBER 33 | VALUE "InternalName", "pugixml.dll\0" 34 | VALUE "LegalCopyright", "Copyright (C) 2006-2022, by Arseny Kapoulkine\0" 35 | VALUE "OriginalFilename", "pugixml.dll\0" 36 | VALUE "ProductName", "pugixml\0" 37 | VALUE "ProductVersion", PUGIXML_VERSION_NUMBER 38 | VALUE "Comments", "For more information visit https://github.com/zeux/pugixml/\0" 39 | END 40 | END 41 | BLOCK "VarFileInfo" 42 | BEGIN 43 | VALUE "Translation", 0x0409, 1252 44 | END 45 | END 46 | -------------------------------------------------------------------------------- /scripts/nuget/pugixml.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pugixml 5 | 1.12.0-appveyor 6 | pugixml 7 | Arseny Kapoulkine 8 | Arseny Kapoulkine 9 | false 10 | MIT 11 | https://pugixml.org/ 12 | pugixml is a C++ XML processing library, which consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven tree queries. Full Unicode support is also available, with Unicode interface variants and conversions between different Unicode encodings (which happen automatically during parsing/saving). 13 | pugixml is used by a lot of projects, both open-source and proprietary, for performance and easy-to-use interface. 14 | This package contains builds for VS2013, VS2015, VS2017, VS2019 and VS2022, for both statically linked and DLL CRT; you can switch the CRT linkage in Project -> Properties -> Referenced Packages -> pugixml. 15 | Light-weight, simple and fast XML parser for C++ with XPath support 16 | https://pugixml.org/docs/manual.html#changes 17 | Copyright (c) 2006-2022 Arseny Kapoulkine 18 | native nativepackage 19 | 20 | 21 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: 2 | - Visual Studio 2022 3 | - Visual Studio 2019 4 | - Visual Studio 2017 5 | - Visual Studio 2015 6 | 7 | version: "{branch}-{build}" 8 | 9 | build_script: 10 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2013") { .\scripts\nuget_build.ps1 2013} 11 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") { .\scripts\nuget_build.ps1 2015} 12 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2017") { .\scripts\nuget_build.ps1 2017} 13 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") { .\scripts\nuget_build.ps1 2019} 14 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2022") { .\scripts\nuget_build.ps1 2022} 15 | 16 | test_script: 17 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") { .\tests\autotest-appveyor.ps1 9 10 11 12 14 } 18 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2017") { .\tests\autotest-appveyor.ps1 15 } 19 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") { .\tests\autotest-appveyor.ps1 19 } 20 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2022") { .\tests\autotest-appveyor.ps1 22 } 21 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") { & C:\cygwin\bin\bash.exe -c "PATH=/usr/bin:/usr/local/bin:$PATH; make config=coverage test && bash <(curl -s https://codecov.io/bash) -f pugixml.cpp.gcov 2>&1" } 22 | - ps: if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") { & C:\cygwin\bin\bash.exe -c "PATH=/usr/bin:/usr/local/bin:$PATH; make config=coverage defines=PUGIXML_WCHAR_MODE test && bash <(curl -s https://codecov.io/bash) -f pugixml.cpp.gcov 2>&1" } 23 | 24 | artifacts: 25 | - path: .\scripts\*.nupkg 26 | -------------------------------------------------------------------------------- /docs/samples/traverse_base.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | pugi::xml_document doc; 9 | if (!doc.load_file("xgconsole.xml")) return -1; 10 | 11 | pugi::xml_node tools = doc.child("Profile").child("Tools"); 12 | 13 | // tag::basic[] 14 | for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling()) 15 | { 16 | std::cout << "Tool:"; 17 | 18 | for (pugi::xml_attribute attr = tool.first_attribute(); attr; attr = attr.next_attribute()) 19 | { 20 | std::cout << " " << attr.name() << "=" << attr.value(); 21 | } 22 | 23 | std::cout << std::endl; 24 | } 25 | // end::basic[] 26 | 27 | std::cout << std::endl; 28 | 29 | // tag::data[] 30 | for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool")) 31 | { 32 | std::cout << "Tool " << tool.attribute("Filename").value(); 33 | std::cout << ": AllowRemote " << tool.attribute("AllowRemote").as_bool(); 34 | std::cout << ", Timeout " << tool.attribute("Timeout").as_int(); 35 | std::cout << ", Description '" << tool.child_value("Description") << "'\n"; 36 | } 37 | // end::data[] 38 | 39 | std::cout << std::endl; 40 | 41 | // tag::contents[] 42 | std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n"; 43 | 44 | for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool")) 45 | { 46 | std::cout << "Tool " << tool.attribute("Filename").value() << "\n"; 47 | } 48 | // end::contents[] 49 | } 50 | 51 | // vim:et 52 | -------------------------------------------------------------------------------- /docs/samples/weekly-utf-8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <週報> 5 | <年月週> 6 | <年度>1997 7 | <月度>1 8 | <週>1 9 | 10 | 11 | <氏名> 12 | <氏>山田 13 | <名>太郎 14 | 15 | 16 | <業務報告リスト> 17 | <業務報告> 18 | <業務名>XMLエディターの作成 19 | <業務コード>X3355-23 20 | <工数管理> 21 | <見積もり工数>1600 22 | <実績工数>320 23 | <当月見積もり工数>160 24 | <当月実績工数>24 25 | 26 | <予定項目リスト> 27 | <予定項目> 28 |

XMLエディターの基本仕様の作成

29 | 30 | 31 | <実施事項リスト> 32 | <実施事項> 33 |

XMLエディターの基本仕様の作成

34 | 35 | <実施事項> 36 |

競合他社製品の機能調査

37 | 38 | 39 | <上長への要請事項リスト> 40 | <上長への要請事項> 41 |

特になし

42 | 43 | 44 | <問題点対策> 45 |

XMLとは何かわからない。

46 | 47 | 48 | 49 | <業務報告> 50 | <業務名>検索エンジンの開発 51 | <業務コード>S8821-76 52 | <工数管理> 53 | <見積もり工数>120 54 | <実績工数>6 55 | <当月見積もり工数>32 56 | <当月実績工数>2 57 | 58 | <予定項目リスト> 59 | <予定項目> 60 |

gooの機能を調べてみる

61 | 62 | 63 | <実施事項リスト> 64 | <実施事項> 65 |

更に、どういう検索エンジンがあるか調査する

66 | 67 | 68 | <上長への要請事項リスト> 69 | <上長への要請事項> 70 |

開発をするのはめんどうなので、Yahoo!を買収して下さい。

71 | 72 | 73 | <問題点対策> 74 |

検索エンジンで車を走らせることができない。(要調査)

75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /scripts/nuget/build/native/pugixml.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dynamic 5 | Debug 6 | Release 7 | 8 | 9 | 10 | 11 | 12 | 13 | PUGIXML_HEADER_ONLY;%(PreprocessorDefinitions) 14 | $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories) 15 | 16 | 17 | $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories) 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | $(MSBuildThisFileDirectory)lib/$(Platform)\$(PlatformToolset.Split('_')[0])\$(Linkage-pugixml)\$(Configuration-pugixml)\pugixml.lib;%(AdditionalDependencies) 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /scripts/archive.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os.path 3 | import sys 4 | import tarfile 5 | import time 6 | import zipfile 7 | 8 | def read_file(path, use_crlf): 9 | with open(path, 'rb') as file: 10 | data = file.read() 11 | 12 | if b'\0' not in data: 13 | data = data.replace(b'\r', b'') 14 | if use_crlf: 15 | data = data.replace(b'\n', b'\r\n') 16 | 17 | return data 18 | 19 | def write_zip(target, arcprefix, timestamp, sources): 20 | with zipfile.ZipFile(target, 'w') as archive: 21 | for source in sorted(sources): 22 | data = read_file(source, use_crlf = True) 23 | path = os.path.join(arcprefix, source) 24 | info = zipfile.ZipInfo(path) 25 | info.date_time = time.localtime(timestamp) 26 | info.compress_type = zipfile.ZIP_DEFLATED 27 | info.external_attr = 0o644 << 16 28 | archive.writestr(info, data) 29 | 30 | def write_tar(target, arcprefix, timestamp, sources, compression): 31 | with tarfile.open(target, 'w:' + compression) as archive: 32 | for source in sorted(sources): 33 | data = read_file(source, use_crlf = False) 34 | path = os.path.join(arcprefix, source) 35 | info = tarfile.TarInfo(path) 36 | info.size = len(data) 37 | info.mtime = timestamp 38 | archive.addfile(info, io.BytesIO(data)) 39 | 40 | if len(sys.argv) < 5: 41 | raise RuntimeError('Usage: python archive.py ') 42 | 43 | target, arcprefix, timestamp = sys.argv[1:4] 44 | sources = sys.argv[4:] 45 | 46 | # tarfile._Stream._init_write_gz always writes current time to gzip header 47 | time.time = lambda: timestamp 48 | 49 | if target.endswith('.zip'): 50 | write_zip(target, arcprefix, int(timestamp), sources) 51 | elif target.endswith('.tar.gz') or target.endswith('.tar.bz2'): 52 | write_tar(target, arcprefix, int(timestamp), sources, compression = os.path.splitext(target)[1][1:]) 53 | else: 54 | raise NotImplementedError('File type not supported: ' + target) 55 | -------------------------------------------------------------------------------- /tests/fuzz_parse.dict: -------------------------------------------------------------------------------- 1 | # 2 | # AFL dictionary for XML 3 | # ---------------------- 4 | # 5 | # Several basic syntax elements and attributes, modeled on libxml2. 6 | # 7 | # Created by Michal Zalewski 8 | # 9 | 10 | attr_encoding=" encoding=\"1\"" 11 | attr_generic=" a=\"1\"" 12 | attr_href=" href=\"1\"" 13 | attr_standalone=" standalone=\"no\"" 14 | attr_version=" version=\"1\"" 15 | attr_xml_base=" xml:base=\"1\"" 16 | attr_xml_id=" xml:id=\"1\"" 17 | attr_xml_lang=" xml:lang=\"1\"" 18 | attr_xml_space=" xml:space=\"1\"" 19 | attr_xmlns=" xmlns=\"1\"" 20 | 21 | entity_builtin="<" 22 | entity_decimal="" 23 | entity_external="&a;" 24 | entity_hex="" 25 | 26 | string_any="ANY" 27 | string_brackets="[]" 28 | string_cdata="CDATA" 29 | string_col_fallback=":fallback" 30 | string_col_generic=":a" 31 | string_col_include=":include" 32 | string_dashes="--" 33 | string_empty="EMPTY" 34 | string_empty_dblquotes="\"\"" 35 | string_empty_quotes="''" 36 | string_entities="ENTITIES" 37 | string_entity="ENTITY" 38 | string_fixed="#FIXED" 39 | string_id="ID" 40 | string_idref="IDREF" 41 | string_idrefs="IDREFS" 42 | string_implied="#IMPLIED" 43 | string_nmtoken="NMTOKEN" 44 | string_nmtokens="NMTOKENS" 45 | string_notation="NOTATION" 46 | string_parentheses="()" 47 | string_pcdata="#PCDATA" 48 | string_percent="%a" 49 | string_public="PUBLIC" 50 | string_required="#REQUIRED" 51 | string_schema=":schema" 52 | string_system="SYSTEM" 53 | string_ucs4="UCS-4" 54 | string_utf16="UTF-16" 55 | string_utf8="UTF-8" 56 | string_xmlns="xmlns:" 57 | 58 | tag_attlist="" 61 | tag_doctype="" 68 | tag_open_close="" 69 | tag_open_exclamation="" 72 | tag_xml_q="" 73 | -------------------------------------------------------------------------------- /docs/samples/include.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | // tag::code[] 7 | bool load_preprocess(pugi::xml_document& doc, const char* path); 8 | 9 | bool preprocess(pugi::xml_node node) 10 | { 11 | for (pugi::xml_node child = node.first_child(); child; ) 12 | { 13 | if (child.type() == pugi::node_pi && strcmp(child.name(), "include") == 0) 14 | { 15 | pugi::xml_node include = child; 16 | 17 | // load new preprocessed document (note: ideally this should handle relative paths) 18 | const char* path = include.value(); 19 | 20 | pugi::xml_document doc; 21 | if (!load_preprocess(doc, path)) return false; 22 | 23 | // insert the comment marker above include directive 24 | node.insert_child_before(pugi::node_comment, include).set_value(path); 25 | 26 | // copy the document above the include directive (this retains the original order!) 27 | for (pugi::xml_node ic = doc.first_child(); ic; ic = ic.next_sibling()) 28 | { 29 | node.insert_copy_before(ic, include); 30 | } 31 | 32 | // remove the include node and move to the next child 33 | child = child.next_sibling(); 34 | 35 | node.remove_child(include); 36 | } 37 | else 38 | { 39 | if (!preprocess(child)) return false; 40 | 41 | child = child.next_sibling(); 42 | } 43 | } 44 | 45 | return true; 46 | } 47 | 48 | bool load_preprocess(pugi::xml_document& doc, const char* path) 49 | { 50 | pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for 51 | 52 | return result ? preprocess(doc) : false; 53 | } 54 | // end::code[] 55 | 56 | int main() 57 | { 58 | pugi::xml_document doc; 59 | if (!load_preprocess(doc, "character.xml")) return -1; 60 | 61 | doc.print(std::cout); 62 | } 63 | 64 | // vim:et 65 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | pull_request: 8 | 9 | jobs: 10 | unix: 11 | strategy: 12 | matrix: 13 | os: [ubuntu, macos] 14 | compiler: [g++, clang++] 15 | defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS] 16 | exclude: 17 | - os: macos 18 | compiler: g++ 19 | name: ${{matrix.os}} (${{matrix.compiler}}, ${{matrix.defines}}) 20 | runs-on: ${{matrix.os}}-latest 21 | steps: 22 | - uses: actions/checkout@v1 23 | - name: make test 24 | run: | 25 | export CXX=${{matrix.compiler}} 26 | make test cxxstd=c++11 defines=${{matrix.defines}} config=release -j2 27 | make test cxxstd=c++98 defines=${{matrix.defines}} config=debug -j2 28 | make test defines=${{matrix.defines}} config=sanitize -j2 29 | - name: make coverage 30 | if: ${{!(matrix.os == 'ubuntu' && matrix.compiler == 'clang++')}} # linux/clang produces coverage info gcov can't parse 31 | run: | 32 | export CXX=${{matrix.compiler}} 33 | make test defines=${{matrix.defines}} config=coverage -j2 34 | bash <(curl -s https://codecov.io/bash) -f pugixml.cpp.gcov -X search -t ${{secrets.CODECOV_TOKEN}} -B ${{github.ref}} 35 | 36 | windows: 37 | runs-on: windows-latest 38 | strategy: 39 | matrix: 40 | arch: [Win32, x64] 41 | defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS] 42 | steps: 43 | - uses: actions/checkout@v1 44 | - name: cmake configure 45 | run: cmake . -DPUGIXML_BUILD_TESTS=ON -D${{matrix.defines}}=ON -A ${{matrix.arch}} 46 | - name: cmake test 47 | shell: bash # necessary for fail-fast 48 | run: | 49 | cmake --build . -- -property:Configuration=Debug -verbosity:minimal 50 | Debug/pugixml-check.exe 51 | cmake --build . -- -property:Configuration=Release -verbosity:minimal 52 | Release/pugixml-check.exe 53 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | pugixml 1.12 - an XML processing library 2 | 3 | Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) 4 | Report bugs and download new versions at https://pugixml.org/ 5 | 6 | This is the distribution of pugixml, which is a C++ XML processing library, 7 | which consists of a DOM-like interface with rich traversal/modification 8 | capabilities, an extremely fast XML parser which constructs the DOM tree from 9 | an XML file/buffer, and an XPath 1.0 implementation for complex data-driven 10 | tree queries. Full Unicode support is also available, with Unicode interface 11 | variants and conversions between different Unicode encodings (which happen 12 | automatically during parsing/saving). 13 | 14 | The distribution contains the following folders: 15 | 16 | docs/ - documentation 17 | docs/samples - pugixml usage examples 18 | docs/quickstart.html - quick start guide 19 | docs/manual.html - complete manual 20 | 21 | scripts/ - project files for IDE/build systems 22 | 23 | src/ - header and source files 24 | 25 | readme.txt - this file. 26 | 27 | This library is distributed under the MIT License: 28 | 29 | Copyright (c) 2006-2022 Arseny Kapoulkine 30 | 31 | Permission is hereby granted, free of charge, to any person 32 | obtaining a copy of this software and associated documentation 33 | files (the "Software"), to deal in the Software without 34 | restriction, including without limitation the rights to use, 35 | copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the 37 | Software is furnished to do so, subject to the following 38 | conditions: 39 | 40 | The above copyright notice and this permission notice shall be 41 | included in all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 44 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 45 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 46 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 47 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 48 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 49 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 50 | OTHER DEALINGS IN THE SOFTWARE. 51 | -------------------------------------------------------------------------------- /tests/data/utftest_utf8_clean.xml: -------------------------------------------------------------------------------- 1 | <週報> 2 | The world has many languages 3 | Мир имеет много языков 4 | el mundo tiene muchos idiomas 5 | 世界有很多语言 6 | <Русский название="name" ценность="value"><имеет> 7 | <汉语 名字="name" 价值="value">世界有很多语言𤭢 8 | quot;Mëtæl!quot; 9 | <ä>Umlaut Element 10 | 11 | <年月週> 12 | <年度>1997 13 | <月度>1 14 | <週>1 15 | 16 | 17 | <氏名> 18 | <氏>山田 19 | <名>太郎 20 | 21 | 22 | <業務報告リスト> 23 | <業務報告> 24 | <業務名>XMLエディターの作成 25 | <業務コード>X3355-23 26 | <工数管理> 27 | <見積もり工数>1600 28 | <実績工数>320 29 | <当月見積もり工数>160 30 | <当月実績工数>24 31 | 32 | <予定項目リスト> 33 | <予定項目> 34 |

XMLエディターの基本仕様の作成

35 | 36 | 37 | <実施事項リスト> 38 | <実施事項> 39 |

XMLエディターの基本仕様の作成

40 | 41 | <実施事項> 42 |

競合他社製品の機能調査

43 | 44 | 45 | <上長への要請事項リスト> 46 | <上長への要請事項> 47 |

特になし

48 | 49 | 50 | <問題点対策> 51 |

XMLとは何かわからない。

52 | 53 | 54 | 55 | <業務報告> 56 | <業務名>検索エンジンの開発 57 | <業務コード>S8821-76 58 | <工数管理> 59 | <見積もり工数>120 60 | <実績工数>6 61 | <当月見積もり工数>32 62 | <当月実績工数>2 63 | 64 | <予定項目リスト> 65 | <予定項目> 66 |

gooの機能を調べてみる

67 | 68 | 69 | <実施事項リスト> 70 | <実施事項> 71 |

更に、どういう検索エンジンがあるか調査する

72 | 73 | 74 | <上長への要請事項リスト> 75 | <上長への要請事項> 76 |

開発をするのはめんどうなので、Yahoo!を買収して下さい。

77 | 78 | 79 | <問題点対策> 80 |

検索エンジンで車を走らせることができない。(要調査)

81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /tests/data/utftest_utf8_nodecl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | <週報> 4 | The world has many languages 5 | Мир имеет много языков 6 | el mundo tiene muchos idiomas 7 | 世界有很多语言 8 | <Русский название="name" ценность="value"><имеет> 9 | <汉语 名字="name" 价值="value">世界有很多语言𤭢 10 | "Mëtæl!" 11 | <ä>Umlaut Element 12 | 13 | <年月週> 14 | <年度>1997 15 | <月度>1 16 | <週>1 17 | 18 | 19 | <氏名> 20 | <氏>山田 21 | <名>太郎 22 | 23 | 24 | <業務報告リスト> 25 | <業務報告> 26 | <業務名>XMLエディターの作成 27 | <業務コード>X3355-23 28 | <工数管理> 29 | <見積もり工数>1600 30 | <実績工数>320 31 | <当月見積もり工数>160 32 | <当月実績工数>24 33 | 34 | <予定項目リスト> 35 | <予定項目> 36 |

XMLエディターの基本仕様の作成

37 | 38 | 39 | <実施事項リスト> 40 | <実施事項> 41 |

XMLエディターの基本仕様の作成

42 | 43 | <実施事項> 44 |

競合他社製品の機能調査

45 | 46 | 47 | <上長への要請事項リスト> 48 | <上長への要請事項> 49 |

特になし

50 | 51 | 52 | <問題点対策> 53 |

XMLとは何かわからない。

54 | 55 | 56 | 57 | <業務報告> 58 | <業務名>検索エンジンの開発 59 | <業務コード>S8821-76 60 | <工数管理> 61 | <見積もり工数>120 62 | <実績工数>6 63 | <当月見積もり工数>32 64 | <当月実績工数>2 65 | 66 | <予定項目リスト> 67 | <予定項目> 68 |

gooの機能を調べてみる

69 | 70 | 71 | <実施事項リスト> 72 | <実施事項> 73 |

更に、どういう検索エンジンがあるか調査する

74 | 75 | 76 | <上長への要請事項リスト> 77 | <上長への要請事項> 78 |

開発をするのはめんどうなので、Yahoo!を買収して下さい。

79 | 80 | 81 | <問題点対策> 82 |

検索エンジンで車を走らせることができない。(要調査)

83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /tests/data/utftest_utf8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <週報> 5 | The world has many languages 6 | Мир имеет много языков 7 | el mundo tiene muchos idiomas 8 | 世界有很多语言 9 | <Русский название="name" ценность="value"><имеет> 10 | <汉语 名字="name" 价值="value">世界有很多语言𤭢 11 | "Mëtæl!" 12 | <ä>Umlaut Element 13 | 14 | <年月週> 15 | <年度>1997 16 | <月度>1 17 | <週>1 18 | 19 | 20 | <氏名> 21 | <氏>山田 22 | <名>太郎 23 | 24 | 25 | <業務報告リスト> 26 | <業務報告> 27 | <業務名>XMLエディターの作成 28 | <業務コード>X3355-23 29 | <工数管理> 30 | <見積もり工数>1600 31 | <実績工数>320 32 | <当月見積もり工数>160 33 | <当月実績工数>24 34 | 35 | <予定項目リスト> 36 | <予定項目> 37 |

XMLエディターの基本仕様の作成

38 | 39 | 40 | <実施事項リスト> 41 | <実施事項> 42 |

XMLエディターの基本仕様の作成

43 | 44 | <実施事項> 45 |

競合他社製品の機能調査

46 | 47 | 48 | <上長への要請事項リスト> 49 | <上長への要請事項> 50 |

特になし

51 | 52 | 53 | <問題点対策> 54 |

XMLとは何かわからない。

55 | 56 | 57 | 58 | <業務報告> 59 | <業務名>検索エンジンの開発 60 | <業務コード>S8821-76 61 | <工数管理> 62 | <見積もり工数>120 63 | <実績工数>6 64 | <当月見積もり工数>32 65 | <当月実績工数>2 66 | 67 | <予定項目リスト> 68 | <予定項目> 69 |

gooの機能を調べてみる

70 | 71 | 72 | <実施事項リスト> 73 | <実施事項> 74 |

更に、どういう検索エンジンがあるか調査する

75 | 76 | 77 | <上長への要請事項リスト> 78 | <上長への要請事項> 79 |

開発をするのはめんどうなので、Yahoo!を買収して下さい。

80 | 81 | 82 | <問題点対策> 83 |

検索エンジンで車を走らせることができない。(要調査)

84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /tests/data/utftest_utf8_bom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <週報> 5 | The world has many languages 6 | Мир имеет много языков 7 | el mundo tiene muchos idiomas 8 | 世界有很多语言 9 | <Русский название="name" ценность="value"><имеет> 10 | <汉语 名字="name" 价值="value">世界有很多语言𤭢 11 | "Mëtæl!" 12 | <ä>Umlaut Element 13 | 14 | <年月週> 15 | <年度>1997 16 | <月度>1 17 | <週>1 18 | 19 | 20 | <氏名> 21 | <氏>山田 22 | <名>太郎 23 | 24 | 25 | <業務報告リスト> 26 | <業務報告> 27 | <業務名>XMLエディターの作成 28 | <業務コード>X3355-23 29 | <工数管理> 30 | <見積もり工数>1600 31 | <実績工数>320 32 | <当月見積もり工数>160 33 | <当月実績工数>24 34 | 35 | <予定項目リスト> 36 | <予定項目> 37 |

XMLエディターの基本仕様の作成

38 | 39 | 40 | <実施事項リスト> 41 | <実施事項> 42 |

XMLエディターの基本仕様の作成

43 | 44 | <実施事項> 45 |

競合他社製品の機能調査

46 | 47 | 48 | <上長への要請事項リスト> 49 | <上長への要請事項> 50 |

特になし

51 | 52 | 53 | <問題点対策> 54 |

XMLとは何かわからない。

55 | 56 | 57 | 58 | <業務報告> 59 | <業務名>検索エンジンの開発 60 | <業務コード>S8821-76 61 | <工数管理> 62 | <見積もり工数>120 63 | <実績工数>6 64 | <当月見積もり工数>32 65 | <当月実績工数>2 66 | 67 | <予定項目リスト> 68 | <予定項目> 69 |

gooの機能を調べてみる

70 | 71 | 72 | <実施事項リスト> 73 | <実施事項> 74 |

更に、どういう検索エンジンがあるか調査する

75 | 76 | 77 | <上長への要請事項リスト> 78 | <上長への要請事項> 79 |

開発をするのはめんどうなので、Yahoo!を買収して下さい。

80 | 81 | 82 | <問題点対策> 83 |

検索エンジンで車を走らせることができない。(要調査)

84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /scripts/nuget_build.ps1: -------------------------------------------------------------------------------- 1 | function Run-Command([string]$cmd) 2 | { 3 | Invoke-Expression $cmd 4 | if ($LastExitCode) { exit $LastExitCode } 5 | } 6 | 7 | function Force-Copy([string]$from, [string]$to) 8 | { 9 | Write-Host $from "->" $to 10 | New-Item -Force $to | Out-Null 11 | Copy-Item -Force $from $to 12 | if (! $?) { exit 1 } 13 | } 14 | 15 | function Build-Version([string]$vs, [string]$toolset, [string]$linkage) 16 | { 17 | $prjsuffix = if ($linkage -eq "static") { "_static" } else { "" } 18 | $cfgsuffix = if ($linkage -eq "static") { "Static" } else { "" } 19 | 20 | foreach ($configuration in "Debug","Release") 21 | { 22 | Run-Command "msbuild pugixml_$vs$prjsuffix.vcxproj /t:Rebuild /p:Configuration=$configuration /p:Platform=x86 /v:minimal /nologo" 23 | Run-Command "msbuild pugixml_$vs$prjsuffix.vcxproj /t:Rebuild /p:Configuration=$configuration /p:Platform=x64 /v:minimal /nologo" 24 | 25 | Force-Copy "$vs/Win32_$configuration$cfgsuffix/pugixml.lib" "nuget/build/native/lib/Win32/$toolset/$linkage/$configuration/pugixml.lib" 26 | Force-Copy "$vs/x64_$configuration$cfgsuffix/pugixml.lib" "nuget/build/native/lib/x64/$toolset/$linkage/$configuration/pugixml.lib" 27 | } 28 | } 29 | 30 | Push-Location 31 | $scriptdir = Split-Path $MyInvocation.MyCommand.Path 32 | cd $scriptdir 33 | 34 | Force-Copy "../src/pugiconfig.hpp" "nuget/build/native/include/pugiconfig.hpp" 35 | Force-Copy "../src/pugixml.hpp" "nuget/build/native/include/pugixml.hpp" 36 | Force-Copy "../src/pugixml.cpp" "nuget/build/native/include/pugixml.cpp" 37 | 38 | if ($args[0] -eq 2022){ 39 | Build-Version "vs2022" "v143" "dynamic" 40 | Build-Version "vs2022" "v143" "static" 41 | 42 | } elseif ($args[0] -eq 2019){ 43 | Build-Version "vs2019" "v142" "dynamic" 44 | Build-Version "vs2019" "v142" "static" 45 | 46 | } elseif ($args[0] -eq 2017){ 47 | Build-Version "vs2017" "v141" "dynamic" 48 | Build-Version "vs2017" "v141" "static" 49 | 50 | Build-Version "vs2015" "v140" "dynamic" 51 | Build-Version "vs2015" "v140" "static" 52 | 53 | Build-Version "vs2013" "v120" "dynamic" 54 | Build-Version "vs2013" "v120" "static" 55 | 56 | } elseif($args[0] -eq 2015){ 57 | Build-Version "vs2015" "v140" "dynamic" 58 | Build-Version "vs2015" "v140" "static" 59 | 60 | Build-Version "vs2013" "v120" "dynamic" 61 | Build-Version "vs2013" "v120" "static" 62 | 63 | } elseif($args[0] -eq 2013){ 64 | Build-Version "vs2013" "v120" "dynamic" 65 | Build-Version "vs2013" "v120" "static" 66 | } 67 | 68 | Run-Command "nuget pack nuget" 69 | 70 | Pop-Location 71 | -------------------------------------------------------------------------------- /scripts/pugixml_codelite.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | None 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | None 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tests/helpers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_TEST_HELPERS_HPP 2 | #define HEADER_TEST_HELPERS_HPP 3 | 4 | #include "test.hpp" 5 | 6 | #include 7 | 8 | template static void generic_bool_ops_test(const T& obj) 9 | { 10 | T null; 11 | 12 | CHECK(!null); 13 | CHECK(obj); 14 | CHECK(!!obj); 15 | 16 | #ifdef _MSC_VER 17 | # pragma warning(push) 18 | # pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) - we really want to just cast to bool instead of !! 19 | #endif 20 | 21 | bool b1 = null, b2 = obj; 22 | 23 | #ifdef _MSC_VER 24 | # pragma warning(pop) 25 | #endif 26 | 27 | CHECK(!b1); 28 | CHECK(b2); 29 | 30 | CHECK(obj && b2); 31 | CHECK(obj || b2); 32 | CHECK(obj && obj); 33 | CHECK(obj || obj); 34 | } 35 | 36 | template static void generic_eq_ops_test(const T& obj1, const T& obj2) 37 | { 38 | T null = T(); 39 | 40 | // operator== 41 | CHECK(null == null); 42 | CHECK(obj1 == obj1); 43 | CHECK(!(null == obj1)); 44 | CHECK(!(null == obj2)); 45 | CHECK(T(null) == null); 46 | CHECK(T(obj1) == obj1); 47 | 48 | // operator!= 49 | CHECK(!(null != null)); 50 | CHECK(!(obj1 != obj1)); 51 | CHECK(null != obj1); 52 | CHECK(null != obj2); 53 | CHECK(!(T(null) != null)); 54 | CHECK(!(T(obj1) != obj1)); 55 | } 56 | 57 | template static void generic_rel_ops_test(T obj1, T obj2) 58 | { 59 | T null = T(); 60 | 61 | // obj1 < obj2 (we use operator<, but there is no other choice 62 | if (obj1 > obj2) 63 | { 64 | T temp = obj1; 65 | obj1 = obj2; 66 | obj2 = temp; 67 | } 68 | 69 | // operator< 70 | CHECK(null < obj1); 71 | CHECK(null < obj2); 72 | CHECK(obj1 < obj2); 73 | CHECK(!(null < null)); 74 | CHECK(!(obj1 < obj1)); 75 | CHECK(!(obj1 < null)); 76 | CHECK(!(obj2 < obj1)); 77 | 78 | // operator<= 79 | CHECK(null <= obj1); 80 | CHECK(null <= obj2); 81 | CHECK(obj1 <= obj2); 82 | CHECK(null <= null); 83 | CHECK(obj1 <= obj1); 84 | CHECK(!(obj1 <= null)); 85 | CHECK(!(obj2 <= obj1)); 86 | 87 | // operator> 88 | CHECK(obj1 > null); 89 | CHECK(obj2 > null); 90 | CHECK(obj2 > obj1); 91 | CHECK(!(null > null)); 92 | CHECK(!(obj1 > obj1)); 93 | CHECK(!(null > obj1)); 94 | CHECK(!(obj1 > obj2)); 95 | 96 | // operator>= 97 | CHECK(obj1 >= null); 98 | CHECK(obj2 >= null); 99 | CHECK(obj2 >= obj1); 100 | CHECK(null >= null); 101 | CHECK(obj1 >= obj1); 102 | CHECK(!(null >= obj1)); 103 | CHECK(!(obj1 >= obj2)); 104 | } 105 | 106 | template static void generic_empty_test(const T& obj) 107 | { 108 | T null; 109 | 110 | CHECK(null.empty()); 111 | CHECK(!obj.empty()); 112 | } 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /scripts/premake4.lua: -------------------------------------------------------------------------------- 1 | -- Reset RNG seed to get consistent results across runs (i.e. XCode) 2 | math.randomseed(12345) 3 | 4 | local static = _ARGS[1] == 'static' 5 | local action = premake.action.current() 6 | 7 | if string.startswith(_ACTION, "vs") then 8 | if action then 9 | -- Disable solution generation 10 | function action.onsolution(sln) 11 | sln.vstudio_configs = premake.vstudio_buildconfigs(sln) 12 | end 13 | 14 | -- Rename output file 15 | function action.onproject(prj) 16 | local name = "%%_" .. _ACTION .. (static and "_static" or "") 17 | 18 | if static then 19 | for k, v in pairs(prj.project.__configs) do 20 | v.objectsdir = v.objectsdir .. "Static" 21 | end 22 | end 23 | 24 | if _ACTION == "vs2010" then 25 | premake.generate(prj, name .. ".vcxproj", premake.vs2010_vcxproj) 26 | else 27 | premake.generate(prj, name .. ".vcproj", premake.vs200x_vcproj) 28 | end 29 | end 30 | end 31 | elseif _ACTION == "codeblocks" then 32 | action.onsolution = nil 33 | 34 | function action.onproject(prj) 35 | premake.generate(prj, "%%_" .. _ACTION .. ".cbp", premake.codeblocks_cbp) 36 | end 37 | elseif _ACTION == "codelite" then 38 | action.onsolution = nil 39 | 40 | function action.onproject(prj) 41 | premake.generate(prj, "%%_" .. _ACTION .. ".project", premake.codelite_project) 42 | end 43 | end 44 | 45 | solution "pugixml" 46 | objdir(_ACTION) 47 | targetdir(_ACTION) 48 | 49 | if string.startswith(_ACTION, "vs") then 50 | if _ACTION ~= "vs2002" and _ACTION ~= "vs2003" then 51 | platforms { "x32", "x64" } 52 | 53 | configuration "x32" targetdir(_ACTION .. "/x32") 54 | configuration "x64" targetdir(_ACTION .. "/x64") 55 | end 56 | 57 | configurations { "Debug", "Release" } 58 | 59 | if static then 60 | configuration "Debug" targetsuffix "sd" 61 | configuration "Release" targetsuffix "s" 62 | else 63 | configuration "Debug" targetsuffix "d" 64 | end 65 | else 66 | if _ACTION == "xcode3" then 67 | platforms "universal" 68 | end 69 | 70 | configurations { "Debug", "Release" } 71 | 72 | configuration "Debug" targetsuffix "d" 73 | end 74 | 75 | project "pugixml" 76 | kind "StaticLib" 77 | language "C++" 78 | files { "../src/pugixml.hpp", "../src/pugiconfig.hpp", "../src/pugixml.cpp" } 79 | flags { "NoPCH", "NoMinimalRebuild", "NoEditAndContinue", "Symbols" } 80 | uuid "89A1E353-E2DC-495C-B403-742BE206ACED" 81 | 82 | configuration "Debug" 83 | defines { "_DEBUG" } 84 | 85 | configuration "Release" 86 | defines { "NDEBUG" } 87 | flags { "Optimize" } 88 | 89 | if static then 90 | configuration "*" 91 | flags { "StaticRuntime" } 92 | end 93 | -------------------------------------------------------------------------------- /docs/samples/load_memory.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | // tag::decl[] 9 | const char source[] = "0 0 1 1"; 10 | size_t size = sizeof(source); 11 | // end::decl[] 12 | 13 | pugi::xml_document doc; 14 | 15 | { 16 | // tag::load_buffer[] 17 | // You can use load_buffer to load document from immutable memory block: 18 | pugi::xml_parse_result result = doc.load_buffer(source, size); 19 | // end::load_buffer[] 20 | 21 | std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; 22 | } 23 | 24 | { 25 | // tag::load_buffer_inplace_begin[] 26 | // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document 27 | char* buffer = new char[size]; 28 | memcpy(buffer, source, size); 29 | 30 | // The block can be allocated by any method; the block is modified during parsing 31 | pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size); 32 | // end::load_buffer_inplace_begin[] 33 | 34 | std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; 35 | 36 | // tag::load_buffer_inplace_end[] 37 | // You have to destroy the block yourself after the document is no longer used 38 | delete[] buffer; 39 | // end::load_buffer_inplace_end[] 40 | } 41 | 42 | { 43 | // tag::load_buffer_inplace_own[] 44 | // You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block 45 | // The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect 46 | char* buffer = static_cast(pugi::get_memory_allocation_function()(size)); 47 | memcpy(buffer, source, size); 48 | 49 | // The block will be deleted by the document 50 | pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size); 51 | // end::load_buffer_inplace_own[] 52 | 53 | std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; 54 | } 55 | 56 | { 57 | // tag::load_string[] 58 | // You can use load to load document from null-terminated strings, for example literals: 59 | pugi::xml_parse_result result = doc.load_string("0 0 1 1"); 60 | // end::load_string[] 61 | 62 | std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; 63 | } 64 | } 65 | 66 | // vim:et 67 | -------------------------------------------------------------------------------- /tests/writer_string.cpp: -------------------------------------------------------------------------------- 1 | #include "writer_string.hpp" 2 | 3 | #include "test.hpp" 4 | 5 | static bool test_narrow(const std::string& result, const char* expected, size_t length) 6 | { 7 | // check result 8 | if (result != std::string(expected, expected + length)) return false; 9 | 10 | // check comparison operator (incorrect implementation can theoretically early-out on zero terminators...) 11 | if (length > 0 && result == std::string(expected, expected + length - 1) + "?") return false; 12 | 13 | return true; 14 | } 15 | 16 | void xml_writer_string::write(const void* data, size_t size) 17 | { 18 | contents.append(static_cast(data), size); 19 | } 20 | 21 | std::string xml_writer_string::as_narrow() const 22 | { 23 | return contents; 24 | } 25 | 26 | std::basic_string xml_writer_string::as_wide() const 27 | { 28 | CHECK(contents.size() % sizeof(wchar_t) == 0); 29 | 30 | // round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast 31 | return std::basic_string(static_cast(static_cast(contents.data())), contents.size() / sizeof(wchar_t)); 32 | } 33 | 34 | std::basic_string xml_writer_string::as_string() const 35 | { 36 | #ifdef PUGIXML_WCHAR_MODE // to avoid "condition is always true" warning in BCC 37 | CHECK(contents.size() % sizeof(pugi::char_t) == 0); 38 | #endif 39 | 40 | // round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast 41 | return std::basic_string(static_cast(static_cast(contents.data())), contents.size() / sizeof(pugi::char_t)); 42 | } 43 | 44 | std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding) 45 | { 46 | xml_writer_string writer; 47 | 48 | doc.save(writer, STR("\t"), flags, encoding); 49 | 50 | return writer.as_narrow(); 51 | } 52 | 53 | bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length) 54 | { 55 | return test_narrow(save_narrow(doc, flags, encoding), expected, length); 56 | } 57 | 58 | std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding) 59 | { 60 | xml_writer_string writer; 61 | 62 | node.print(writer, STR("\t"), flags, encoding); 63 | 64 | return writer.as_narrow(); 65 | } 66 | 67 | bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length) 68 | { 69 | return test_narrow(write_narrow(node, flags, encoding), expected, length); 70 | } 71 | 72 | std::basic_string write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding) 73 | { 74 | xml_writer_string writer; 75 | 76 | node.print(writer, STR("\t"), flags, encoding); 77 | 78 | return writer.as_wide(); 79 | } 80 | -------------------------------------------------------------------------------- /tests/autotest-appveyor.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-CmdScript($scriptName) 2 | { 3 | $cmdLine = """$scriptName"" $args & set" 4 | & $Env:SystemRoot\system32\cmd.exe /c $cmdLine | 5 | select-string '^([^=]*)=(.*)$' | foreach-object { 6 | $varName = $_.Matches[0].Groups[1].Value 7 | $varValue = $_.Matches[0].Groups[2].Value 8 | set-item Env:$varName $varValue 9 | } 10 | } 11 | 12 | $sources = @("src/pugixml.cpp") + (Get-ChildItem -Path "tests/*.cpp" -Exclude "fuzz_*.cpp") 13 | $failed = $FALSE 14 | 15 | foreach ($vs in $args) 16 | { 17 | foreach ($arch in "x86","x64") 18 | { 19 | Write-Output "# Setting up VS$vs $arch" 20 | 21 | if ($vs -eq 15) { 22 | $vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" } 23 | Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch" 24 | } 25 | elseif ($vs -eq 19) { 26 | $vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" } 27 | Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch" 28 | } 29 | elseif ($vs -eq 22) { 30 | $vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" } 31 | Invoke-CmdScript "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch" 32 | } 33 | else 34 | { 35 | Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio $vs.0\VC\vcvarsall.bat" $arch 36 | } 37 | 38 | if (! $?) { throw "Error setting up VS$vs $arch" } 39 | 40 | foreach ($defines in "standard", "PUGIXML_WCHAR_MODE", "PUGIXML_COMPACT") 41 | { 42 | $target = "tests_vs${vs}_${arch}_${defines}" 43 | $deflist = if ($defines -eq "standard") { "" } else { "/D$defines" } 44 | 45 | Add-AppveyorTest $target -Outcome Running 46 | 47 | Write-Output "# Building $target.exe" 48 | & cmd /c "cl.exe /Fe$target.exe /EHsc /W4 /WX $deflist $sources 2>&1" | Tee-Object -Variable buildOutput 49 | 50 | if ($?) 51 | { 52 | Write-Output "# Running $target.exe" 53 | 54 | $sw = [Diagnostics.Stopwatch]::StartNew() 55 | 56 | & .\$target | Tee-Object -Variable testOutput 57 | 58 | if ($?) 59 | { 60 | Write-Output "# Passed" 61 | 62 | Update-AppveyorTest $target -Outcome Passed -StdOut ($testOutput | out-string) -Duration $sw.ElapsedMilliseconds 63 | } 64 | else 65 | { 66 | Write-Output "# Failed" 67 | 68 | Update-AppveyorTest $target -Outcome Failed -StdOut ($testOutput | out-string) -ErrorMessage "Running failed" 69 | 70 | $failed = $TRUE 71 | } 72 | } 73 | else 74 | { 75 | Write-Output "# Failed to build" 76 | 77 | Update-AppveyorTest $target -Outcome Failed -StdOut ($buildOutput | out-string) -ErrorMessage "Compilation failed" 78 | 79 | $failed = $TRUE 80 | } 81 | } 82 | } 83 | } 84 | 85 | if ($failed) { throw "One or more build steps failed" } 86 | 87 | Write-Output "# End" 88 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .SUFFIXES: 2 | MAKEFLAGS+=-r 3 | 4 | config=debug 5 | defines=standard 6 | cxxstd=c++11 7 | # set cxxstd=any to disable use of -std=... 8 | 9 | BUILD=build/make-$(CXX)-$(config)-$(defines)-$(cxxstd) 10 | 11 | SOURCES=src/pugixml.cpp $(filter-out tests/fuzz_%,$(wildcard tests/*.cpp)) 12 | EXECUTABLE=$(BUILD)/test 13 | 14 | VERSION=$(shell sed -n 's/.*version \(.*\).*/\1/p' src/pugiconfig.hpp) 15 | RELEASE=$(filter-out scripts/archive.py docs/%.adoc,$(shell git ls-files docs scripts src CMakeLists.txt LICENSE.md readme.txt)) 16 | 17 | CXXFLAGS=-g -Wall -Wextra -Werror -pedantic -Wundef -Wshadow -Wcast-align -Wcast-qual -Wold-style-cast -Wdouble-promotion 18 | LDFLAGS= 19 | 20 | ifeq ($(config),release) 21 | CXXFLAGS+=-O3 -DNDEBUG 22 | endif 23 | 24 | ifeq ($(config),coverage) 25 | CXXFLAGS+=-coverage 26 | LDFLAGS+=-coverage 27 | endif 28 | 29 | ifeq ($(config),sanitize) 30 | CXXFLAGS+=-fsanitize=address,undefined -fno-sanitize=float-divide-by-zero,float-cast-overflow -fno-sanitize-recover=all 31 | LDFLAGS+=-fsanitize=address,undefined 32 | endif 33 | 34 | ifeq ($(config),analyze) 35 | CXXFLAGS+=--analyze 36 | endif 37 | 38 | ifneq ($(defines),standard) 39 | COMMA=, 40 | CXXFLAGS+=-D $(subst $(COMMA), -D ,$(defines)) 41 | endif 42 | 43 | ifneq ($(findstring PUGIXML_NO_EXCEPTIONS,$(defines)),) 44 | CXXFLAGS+=-fno-exceptions 45 | endif 46 | 47 | ifneq ($(cxxstd),any) 48 | CXXFLAGS+=-std=$(cxxstd) 49 | endif 50 | 51 | OBJECTS=$(SOURCES:%=$(BUILD)/%.o) 52 | 53 | all: $(EXECUTABLE) 54 | 55 | ifeq ($(config),coverage) 56 | test: $(EXECUTABLE) 57 | -@find $(BUILD) -name '*.gcda' -exec rm {} + 58 | ./$(EXECUTABLE) 59 | @gcov -b -o $(BUILD)/src/ pugixml.cpp.gcda | sed -e '/./{H;$!d;}' -e 'x;/pugixml.cpp/!d;' 60 | @find . -name '*.gcov' -and -not -name 'pugixml.cpp.gcov' -exec rm {} + 61 | @sed -i -e "s/#####\(.*\)\(\/\/ unreachable.*\)/ 1\1\2/" pugixml.cpp.gcov 62 | else 63 | test: $(EXECUTABLE) 64 | ./$(EXECUTABLE) 65 | endif 66 | 67 | fuzz_%: $(BUILD)/fuzz_% 68 | @mkdir -p build/$@ 69 | $< build/$@ tests/data_fuzz_$* -max_len=1024 -dict=tests/fuzz_$*.dict 70 | 71 | clean: 72 | rm -rf $(BUILD) 73 | 74 | release: build/pugixml-$(VERSION).tar.gz build/pugixml-$(VERSION).zip 75 | 76 | docs: docs/quickstart.html docs/manual.html 77 | 78 | build/pugixml-%: .FORCE | $(RELEASE) 79 | @mkdir -p $(BUILD) 80 | TIMESTAMP=`git show v$(VERSION) -s --format=%ct` && python3 scripts/archive.py $@ pugixml-$(VERSION) $$TIMESTAMP $| 81 | 82 | $(EXECUTABLE): $(OBJECTS) 83 | $(CXX) $(OBJECTS) $(LDFLAGS) -o $@ 84 | 85 | $(BUILD)/fuzz_%: tests/fuzz_%.cpp src/pugixml.cpp 86 | @mkdir -p $(BUILD) 87 | $(CXX) $(CXXFLAGS) -fsanitize=address,fuzzer $^ -o $@ 88 | 89 | $(BUILD)/%.o: % 90 | @mkdir -p $(dir $@) 91 | $(CXX) $< $(CXXFLAGS) -c -MMD -MP -o $@ 92 | 93 | -include $(OBJECTS:.o=.d) 94 | 95 | .SECONDEXPANSION: 96 | docs/%.html: docs/%.adoc $$(shell sed -n 's/include\:\:\(.*\)\[.*/docs\/\1/p' docs/%.adoc) 97 | asciidoctor -b html5 -a version=$(VERSION) $< -o $@ 98 | 99 | .PHONY: all test clean release .FORCE 100 | -------------------------------------------------------------------------------- /src/pugiconfig.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * pugixml parser - version 1.12 3 | * -------------------------------------------------------- 4 | * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) 5 | * Report bugs and download new versions at https://pugixml.org/ 6 | * 7 | * This library is distributed under the MIT License. See notice at the end 8 | * of this file. 9 | * 10 | * This work is based on the pugxml parser, which is: 11 | * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) 12 | */ 13 | 14 | #ifndef HEADER_PUGICONFIG_HPP 15 | #define HEADER_PUGICONFIG_HPP 16 | 17 | // Uncomment this to enable wchar_t mode 18 | // #define PUGIXML_WCHAR_MODE 19 | 20 | // Uncomment this to enable compact mode 21 | // #define PUGIXML_COMPACT 22 | 23 | // Uncomment this to disable XPath 24 | // #define PUGIXML_NO_XPATH 25 | 26 | // Uncomment this to disable STL 27 | // #define PUGIXML_NO_STL 28 | 29 | // Uncomment this to disable exceptions 30 | // #define PUGIXML_NO_EXCEPTIONS 31 | 32 | // Set this to control attributes for public classes/functions, i.e.: 33 | // #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL 34 | // #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL 35 | // #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall 36 | // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead 37 | 38 | // Tune these constants to adjust memory-related behavior 39 | // #define PUGIXML_MEMORY_PAGE_SIZE 32768 40 | // #define PUGIXML_MEMORY_OUTPUT_STACK 10240 41 | // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 42 | 43 | // Tune this constant to adjust max nesting for XPath queries 44 | // #define PUGIXML_XPATH_DEPTH_LIMIT 1024 45 | 46 | // Uncomment this to switch to header-only version 47 | // #define PUGIXML_HEADER_ONLY 48 | 49 | // Uncomment this to enable long long support 50 | // #define PUGIXML_HAS_LONG_LONG 51 | 52 | #endif 53 | 54 | /** 55 | * Copyright (c) 2006-2022 Arseny Kapoulkine 56 | * 57 | * Permission is hereby granted, free of charge, to any person 58 | * obtaining a copy of this software and associated documentation 59 | * files (the "Software"), to deal in the Software without 60 | * restriction, including without limitation the rights to use, 61 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 62 | * copies of the Software, and to permit persons to whom the 63 | * Software is furnished to do so, subject to the following 64 | * conditions: 65 | * 66 | * The above copyright notice and this permission notice shall be 67 | * included in all copies or substantial portions of the Software. 68 | * 69 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 70 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 71 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 72 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 73 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 74 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 75 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 76 | * OTHER DEALINGS IN THE SOFTWARE. 77 | */ 78 | -------------------------------------------------------------------------------- /docs/samples/save_custom_writer.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // tag::code[] 8 | struct xml_string_writer: pugi::xml_writer 9 | { 10 | std::string result; 11 | 12 | virtual void write(const void* data, size_t size) 13 | { 14 | result.append(static_cast(data), size); 15 | } 16 | }; 17 | // end::code[] 18 | 19 | struct xml_memory_writer: pugi::xml_writer 20 | { 21 | char* buffer; 22 | size_t capacity; 23 | 24 | size_t result; 25 | 26 | xml_memory_writer(): buffer(0), capacity(0), result(0) 27 | { 28 | } 29 | 30 | xml_memory_writer(char* buffer, size_t capacity): buffer(buffer), capacity(capacity), result(0) 31 | { 32 | } 33 | 34 | size_t written_size() const 35 | { 36 | return result < capacity ? result : capacity; 37 | } 38 | 39 | virtual void write(const void* data, size_t size) 40 | { 41 | if (result < capacity) 42 | { 43 | size_t chunk = (capacity - result < size) ? capacity - result : size; 44 | 45 | memcpy(buffer + result, data, chunk); 46 | } 47 | 48 | result += size; 49 | } 50 | }; 51 | 52 | std::string node_to_string(pugi::xml_node node) 53 | { 54 | xml_string_writer writer; 55 | node.print(writer); 56 | 57 | return writer.result; 58 | } 59 | 60 | char* node_to_buffer(pugi::xml_node node, char* buffer, size_t size) 61 | { 62 | if (size == 0) return buffer; 63 | 64 | // leave one character for null terminator 65 | xml_memory_writer writer(buffer, size - 1); 66 | node.print(writer); 67 | 68 | // null terminate 69 | buffer[writer.written_size()] = 0; 70 | 71 | return buffer; 72 | } 73 | 74 | char* node_to_buffer_heap(pugi::xml_node node) 75 | { 76 | // first pass: get required memory size 77 | xml_memory_writer counter; 78 | node.print(counter); 79 | 80 | // allocate necessary size (+1 for null termination) 81 | char* buffer = new char[counter.result + 1]; 82 | 83 | // second pass: actual printing 84 | xml_memory_writer writer(buffer, counter.result); 85 | node.print(writer); 86 | 87 | // null terminate 88 | buffer[writer.written_size()] = 0; 89 | 90 | return buffer; 91 | } 92 | 93 | int main() 94 | { 95 | // get a test document 96 | pugi::xml_document doc; 97 | doc.load_string("hey"); 98 | 99 | // get contents as std::string (single pass) 100 | std::cout << "contents: [" << node_to_string(doc) << "]\n"; 101 | 102 | // get contents into fixed-size buffer (single pass) 103 | char large_buf[128]; 104 | std::cout << "contents: [" << node_to_buffer(doc, large_buf, sizeof(large_buf)) << "]\n"; 105 | 106 | // get contents into fixed-size buffer (single pass, shows truncating behavior) 107 | char small_buf[22]; 108 | std::cout << "contents: [" << node_to_buffer(doc, small_buf, sizeof(small_buf)) << "]\n"; 109 | 110 | // get contents into heap-allocated buffer (two passes) 111 | char* heap_buf = node_to_buffer_heap(doc); 112 | std::cout << "contents: [" << heap_buf << "]\n"; 113 | delete[] heap_buf; 114 | } 115 | 116 | // vim:et 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pugixml [![Actions Status](https://github.com/zeux/pugixml/workflows/build/badge.svg)](https://github.com/zeux/pugixml/actions) [![Build status](https://ci.appveyor.com/api/projects/status/9hdks1doqvq8pwe7/branch/master?svg=true)](https://ci.appveyor.com/project/zeux/pugixml) [![codecov.io](https://codecov.io/github/zeux/pugixml/coverage.svg?branch=master)](https://codecov.io/github/zeux/pugixml?branch=master) ![MIT](https://img.shields.io/badge/license-MIT-blue.svg) 2 | ======= 3 | 4 | pugixml is a C++ XML processing library, which consists of a DOM-like interface with rich traversal/modification 5 | capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 6 | implementation for complex data-driven tree queries. Full Unicode support is also available, with Unicode interface 7 | variants and conversions between different Unicode encodings (which happen automatically during parsing/saving). 8 | 9 | pugixml is used by a lot of projects, both open-source and proprietary, for performance and easy-to-use interface. 10 | 11 | ## Documentation 12 | 13 | Documentation for the current release of pugixml is available on-line as two separate documents: 14 | 15 | * [Quick-start guide](https://pugixml.org/docs/quickstart.html), that aims to provide enough information to start using the library; 16 | * [Complete reference manual](https://pugixml.org/docs/manual.html), that describes all features of the library in detail. 17 | 18 | You’re advised to start with the quick-start guide; however, many important library features are either not described in it at all or only mentioned briefly; if you require more information you should read the complete manual. 19 | 20 | ## Example 21 | 22 | Here's an example of how code using pugixml looks; it opens an XML file, goes over all Tool nodes and prints tools that have a Timeout attribute greater than 0: 23 | 24 | ```c++ 25 | #include "pugixml.hpp" 26 | #include 27 | 28 | int main() 29 | { 30 | pugi::xml_document doc; 31 | pugi::xml_parse_result result = doc.load_file("xgconsole.xml"); 32 | if (!result) 33 | return -1; 34 | 35 | for (pugi::xml_node tool: doc.child("Profile").child("Tools").children("Tool")) 36 | { 37 | int timeout = tool.attribute("Timeout").as_int(); 38 | 39 | if (timeout > 0) 40 | std::cout << "Tool " << tool.attribute("Filename").value() << " has timeout " << timeout << "\n"; 41 | } 42 | } 43 | ``` 44 | 45 | And the same example using XPath: 46 | 47 | ```c++ 48 | #include "pugixml.hpp" 49 | #include 50 | 51 | int main() 52 | { 53 | pugi::xml_document doc; 54 | pugi::xml_parse_result result = doc.load_file("xgconsole.xml"); 55 | if (!result) 56 | return -1; 57 | 58 | pugi::xpath_node_set tools_with_timeout = doc.select_nodes("/Profile/Tools/Tool[@Timeout > 0]"); 59 | 60 | for (pugi::xpath_node node: tools_with_timeout) 61 | { 62 | pugi::xml_node tool = node.node(); 63 | std::cout << "Tool " << tool.attribute("Filename").value() << 64 | " has timeout " << tool.attribute("Timeout").as_int() << "\n"; 65 | } 66 | } 67 | ``` 68 | 69 | 70 | ## License 71 | 72 | This library is available to anybody free of charge, under the terms of MIT License (see LICENSE.md). 73 | -------------------------------------------------------------------------------- /docs/samples/load_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "pugixml.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void print_doc(const char* message, const pugi::xml_document& doc, const pugi::xml_parse_result& result) 8 | { 9 | std::cout 10 | << message 11 | << "\t: load result '" << result.description() << "'" 12 | << ", first character of root name: U+" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << pugi::as_wide(doc.first_child().name())[0] 13 | << ", year: " << doc.first_child().first_child().first_child().child_value() 14 | << std::endl; 15 | } 16 | 17 | bool try_imbue(std::wistream& stream, const char* name) 18 | { 19 | try 20 | { 21 | stream.imbue(std::locale(name)); 22 | 23 | return true; 24 | } 25 | catch (const std::exception&) 26 | { 27 | return false; 28 | } 29 | } 30 | 31 | int main() 32 | { 33 | pugi::xml_document doc; 34 | 35 | { 36 | // tag::code[] 37 | std::ifstream stream("weekly-utf-8.xml"); 38 | pugi::xml_parse_result result = doc.load(stream); 39 | // end::code[] 40 | 41 | // first character of root name: U+9031, year: 1997 42 | print_doc("UTF8 file from narrow stream", doc, result); 43 | } 44 | 45 | { 46 | std::ifstream stream("weekly-utf-16.xml"); 47 | pugi::xml_parse_result result = doc.load(stream); 48 | 49 | // first character of root name: U+9031, year: 1997 50 | print_doc("UTF16 file from narrow stream", doc, result); 51 | } 52 | 53 | { 54 | // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-8 file from a wide stream 55 | // directly if you have localized characters; you'll have to provide a UTF8 locale (there is no 56 | // standard one; you can use utf8_codecvt_facet from Boost or codecvt_utf8 from C++0x) 57 | std::wifstream stream("weekly-utf-8.xml"); 58 | 59 | if (try_imbue(stream, "en_US.UTF-8")) // try Linux encoding 60 | { 61 | pugi::xml_parse_result result = doc.load(stream); 62 | 63 | // first character of root name: U+00E9, year: 1997 64 | print_doc("UTF8 file from wide stream", doc, result); 65 | } 66 | else 67 | { 68 | std::cout << "UTF-8 locale is not available\n"; 69 | } 70 | } 71 | 72 | { 73 | // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-16 file from a wide stream without 74 | // using custom codecvt; you can use codecvt_utf16 from C++0x 75 | } 76 | 77 | { 78 | // Since encoding names are non-standard, you can't load the Shift-JIS (or any other non-ASCII) file 79 | // from a wide stream portably 80 | std::wifstream stream("weekly-shift_jis.xml"); 81 | 82 | if (try_imbue(stream, ".932") || // try Microsoft encoding 83 | try_imbue(stream, "ja_JP.SJIS")) // try Linux encoding; run "localedef -i ja_JP -c -f SHIFT_JIS /usr/lib/locale/ja_JP.SJIS" to get it 84 | { 85 | pugi::xml_parse_result result = doc.load(stream); 86 | 87 | // first character of root name: U+9031, year: 1997 88 | print_doc("Shift-JIS file from wide stream", doc, result); 89 | } 90 | else 91 | { 92 | std::cout << "Shift-JIS locale is not available\n"; 93 | } 94 | } 95 | } 96 | 97 | // vim:et 98 | -------------------------------------------------------------------------------- /scripts/natvis/pugixml.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {_root} 5 | none 6 | 7 | _root 8 | 9 | 10 | 11 | 12 | {(pugi::xml_node_type)(header & 0xf),en} name={name,na} value={value,na} 13 | {(pugi::xml_node_type)(header & 0xf),en} name={name,na} 14 | {(pugi::xml_node_type)(header & 0xf),en} value={value,na} 15 | {(pugi::xml_node_type)(header & 0xf),en} 16 | 17 | value,na 18 | 19 | 20 | 21 | 22 | 23 | 24 | curr,view(child)na 25 | curr = curr->next_attribute 26 | 27 | 28 | 29 | 30 | 31 | first_child 32 | next_sibling 33 | this,na 34 | 35 | 36 | 37 | 38 | 39 | {_attr} 40 | none 41 | 42 | _attr 43 | 44 | 45 | 46 | 47 | {name,na} = {value,na} 48 | {value,na} 49 | 50 | name,na 51 | value,na 52 | 53 | 54 | 55 | 56 | {_node,na} "{_attribute._attr->name,na}"="{_attribute._attr->value,na}" 57 | {_node,na} 58 | {_attribute} 59 | empty 60 | 61 | _node 62 | _attribute 63 | _node,na 64 | _attribute,na 65 | 66 | 67 | 68 | 69 | 70 | _type 71 | 72 | _end - _begin 73 | _begin 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /tests/test_unicode.cpp: -------------------------------------------------------------------------------- 1 | #ifndef PUGIXML_NO_STL 2 | 3 | #include "test.hpp" 4 | 5 | #include 6 | 7 | using namespace pugi; 8 | 9 | // letters taken from http://www.utf8-chartable.de/ 10 | 11 | TEST(as_wide_empty) 12 | { 13 | CHECK(as_wide("") == L""); 14 | } 15 | 16 | TEST(as_wide_valid_basic) 17 | { 18 | // valid 1-byte, 2-byte and 3-byte inputs 19 | #ifdef U_LITERALS 20 | CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\u0400\u203D"); 21 | #else 22 | CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\x0400\x203D"); 23 | #endif 24 | } 25 | 26 | TEST(as_wide_valid_astral) 27 | { 28 | // valid 4-byte input 29 | std::basic_string b4 = as_wide("\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf"); 30 | 31 | size_t wcharsize = sizeof(wchar_t); 32 | 33 | if (wcharsize == 4) 34 | { 35 | CHECK(b4.size() == 3 && b4[0] == wchar_cast(0x97624) && b4[1] == L' ' && b4[2] == wchar_cast(0x1003ff)); 36 | } 37 | else 38 | { 39 | CHECK(b4.size() == 5 && b4[0] == wchar_cast(0xda1d) && b4[1] == wchar_cast(0xde24) && b4[2] == L' ' && b4[3] == wchar_cast(0xdbc0) && b4[4] == wchar_cast(0xdfff)); 40 | } 41 | } 42 | 43 | TEST(as_wide_invalid) 44 | { 45 | // invalid 1-byte input 46 | CHECK(as_wide("a\xb0") == L"a"); 47 | CHECK(as_wide("a\xb0_") == L"a_"); 48 | 49 | // invalid 2-byte input 50 | CHECK(as_wide("a\xc0") == L"a"); 51 | CHECK(as_wide("a\xd0") == L"a"); 52 | CHECK(as_wide("a\xc0_") == L"a_"); 53 | CHECK(as_wide("a\xd0_") == L"a_"); 54 | 55 | // invalid 3-byte input 56 | CHECK(as_wide("a\xe2\x80") == L"a"); 57 | CHECK(as_wide("a\xe2") == L"a"); 58 | CHECK(as_wide("a\xe2\x80_") == L"a_"); 59 | CHECK(as_wide("a\xe2_") == L"a_"); 60 | 61 | // invalid 4-byte input 62 | CHECK(as_wide("a\xf2\x97\x98") == L"a"); 63 | CHECK(as_wide("a\xf2\x97") == L"a"); 64 | CHECK(as_wide("a\xf2") == L"a"); 65 | CHECK(as_wide("a\xf2\x97\x98_") == L"a_"); 66 | CHECK(as_wide("a\xf2\x97_") == L"a_"); 67 | CHECK(as_wide("a\xf2_") == L"a_"); 68 | 69 | // invalid 5-byte input 70 | std::basic_string b5 = as_wide("\xf8\nbcd"); 71 | CHECK(b5 == L"\nbcd"); 72 | } 73 | 74 | TEST(as_wide_string) 75 | { 76 | std::string s = "abcd"; 77 | 78 | CHECK(as_wide(s) == L"abcd"); 79 | } 80 | 81 | TEST(as_utf8_empty) 82 | { 83 | CHECK(as_utf8(L"") == ""); 84 | } 85 | 86 | TEST(as_utf8_valid_basic) 87 | { 88 | // valid 1-byte, 2-byte and 3-byte outputs 89 | #ifdef U_LITERALS 90 | CHECK(as_utf8(L"?\u0400\u203D") == "?\xd0\x80\xe2\x80\xbd"); 91 | #else 92 | CHECK(as_utf8(L"?\x0400\x203D") == "?\xd0\x80\xe2\x80\xbd"); 93 | #endif 94 | } 95 | 96 | TEST(as_utf8_valid_astral) 97 | { 98 | // valid 4-byte output 99 | size_t wcharsize = sizeof(wchar_t); 100 | 101 | if (wcharsize == 4) 102 | { 103 | std::basic_string s; 104 | s.resize(3); 105 | s[0] = wchar_cast(0x97624); 106 | s[1] = ' '; 107 | s[2] = wchar_cast(0x1003ff); 108 | 109 | CHECK(as_utf8(s.c_str()) == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf"); 110 | } 111 | else 112 | { 113 | #ifdef U_LITERALS 114 | CHECK(as_utf8(L"\uda1d\ude24 \udbc0\udfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf"); 115 | #else 116 | CHECK(as_utf8(L"\xda1d\xde24 \xdbc0\xdfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf"); 117 | #endif 118 | } 119 | } 120 | 121 | TEST(as_utf8_invalid) 122 | { 123 | size_t wcharsize = sizeof(wchar_t); 124 | 125 | if (wcharsize == 2) 126 | { 127 | // check non-terminated degenerate handling 128 | #ifdef U_LITERALS 129 | CHECK(as_utf8(L"a\uda1d") == "a"); 130 | CHECK(as_utf8(L"a\uda1d_") == "a_"); 131 | #else 132 | CHECK(as_utf8(L"a\xda1d") == "a"); 133 | CHECK(as_utf8(L"a\xda1d_") == "a_"); 134 | #endif 135 | 136 | // check incorrect leading code 137 | #ifdef U_LITERALS 138 | CHECK(as_utf8(L"a\ude24") == "a"); 139 | CHECK(as_utf8(L"a\ude24_") == "a_"); 140 | #else 141 | CHECK(as_utf8(L"a\xde24") == "a"); 142 | CHECK(as_utf8(L"a\xde24_") == "a_"); 143 | #endif 144 | } 145 | } 146 | 147 | TEST(as_utf8_string) 148 | { 149 | std::basic_string s = L"abcd"; 150 | 151 | CHECK(as_utf8(s) == "abcd"); 152 | } 153 | #endif 154 | -------------------------------------------------------------------------------- /tests/allocator.cpp: -------------------------------------------------------------------------------- 1 | #include "allocator.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // Address sanitizer 8 | #if defined(__has_feature) 9 | # define ADDRESS_SANITIZER __has_feature(address_sanitizer) 10 | #else 11 | # if defined(__SANITIZE_ADDRESS__) 12 | # define ADDRESS_SANITIZER 1 13 | # else 14 | # define ADDRESS_SANITIZER 0 15 | # endif 16 | #endif 17 | 18 | // Low-level allocation functions 19 | #if defined(_WIN32) || defined(_WIN64) 20 | # ifdef __MWERKS__ 21 | # pragma ANSI_strict off // disable ANSI strictness to include windows.h 22 | # pragma cpp_extensions on // enable some extensions to include windows.h 23 | # endif 24 | 25 | # if defined(_MSC_VER) 26 | # pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union 27 | # endif 28 | 29 | # ifdef _XBOX_VER 30 | # define NOD3D 31 | # include 32 | # else 33 | # include 34 | # endif 35 | 36 | namespace 37 | { 38 | const size_t page_size = 4096; 39 | 40 | size_t align_to_page(size_t value) 41 | { 42 | return (value + page_size - 1) & ~(page_size - 1); 43 | } 44 | 45 | void* allocate_page_aligned(size_t size) 46 | { 47 | // We can't use VirtualAlloc because it has 64Kb granularity so we run out of address space quickly 48 | // We can't use malloc because of occasional problems with CW on CRT termination 49 | static HANDLE heap = HeapCreate(0, 0, 0); 50 | 51 | void* result = HeapAlloc(heap, 0, size + page_size); 52 | 53 | return reinterpret_cast(align_to_page(reinterpret_cast(result))); 54 | } 55 | 56 | void* allocate(size_t size) 57 | { 58 | size_t aligned_size = align_to_page(size); 59 | 60 | void* ptr = allocate_page_aligned(aligned_size + page_size); 61 | if (!ptr) return 0; 62 | 63 | char* end = static_cast(ptr) + aligned_size; 64 | 65 | DWORD old_flags; 66 | VirtualProtect(end, page_size, PAGE_NOACCESS, &old_flags); 67 | 68 | return end - size; 69 | } 70 | 71 | void deallocate(void* ptr, size_t size) 72 | { 73 | size_t aligned_size = align_to_page(size); 74 | 75 | void* rptr = static_cast(ptr) + size - aligned_size; 76 | 77 | DWORD old_flags; 78 | VirtualProtect(rptr, aligned_size + page_size, PAGE_NOACCESS, &old_flags); 79 | } 80 | } 81 | #elif (defined(__APPLE__) || defined(__linux__)) && (defined(__i386) || defined(__x86_64)) && !ADDRESS_SANITIZER 82 | # include 83 | 84 | namespace 85 | { 86 | const size_t page_size = 4096; 87 | 88 | size_t align_to_page(size_t value) 89 | { 90 | return (value + page_size - 1) & ~(page_size - 1); 91 | } 92 | 93 | void* allocate_page_aligned(size_t size) 94 | { 95 | void* result = malloc(size + page_size); 96 | 97 | return reinterpret_cast(align_to_page(reinterpret_cast(result))); 98 | } 99 | 100 | void* allocate(size_t size) 101 | { 102 | size_t aligned_size = align_to_page(size); 103 | 104 | void* ptr = allocate_page_aligned(aligned_size + page_size); 105 | if (!ptr) return 0; 106 | 107 | char* end = static_cast(ptr) + aligned_size; 108 | 109 | int res = mprotect(end, page_size, PROT_NONE); 110 | assert(res == 0); 111 | (void)!res; 112 | 113 | return end - size; 114 | } 115 | 116 | void deallocate(void* ptr, size_t size) 117 | { 118 | size_t aligned_size = align_to_page(size); 119 | 120 | void* rptr = static_cast(ptr) + size - aligned_size; 121 | 122 | int res = mprotect(rptr, aligned_size + page_size, PROT_NONE); 123 | assert(res == 0); 124 | (void)!res; 125 | } 126 | } 127 | #else 128 | namespace 129 | { 130 | void* allocate(size_t size) 131 | { 132 | return malloc(size); 133 | } 134 | 135 | void deallocate(void* ptr, size_t size) 136 | { 137 | (void)size; 138 | 139 | free(ptr); 140 | } 141 | } 142 | #endif 143 | 144 | // High-level allocation functions 145 | const size_t memory_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); 146 | 147 | void* memory_allocate(size_t size) 148 | { 149 | void* result = allocate(size + memory_alignment); 150 | if (!result) return 0; 151 | 152 | memcpy(result, &size, sizeof(size_t)); 153 | 154 | return static_cast(result) + memory_alignment; 155 | } 156 | 157 | size_t memory_size(void* ptr) 158 | { 159 | assert(ptr); 160 | 161 | size_t result; 162 | memcpy(&result, static_cast(ptr) - memory_alignment, sizeof(size_t)); 163 | 164 | return result; 165 | } 166 | 167 | void memory_deallocate(void* ptr) 168 | { 169 | if (!ptr) return; 170 | 171 | size_t size = memory_size(ptr); 172 | 173 | deallocate(static_cast(ptr) - memory_alignment, size + memory_alignment); 174 | } 175 | 176 | -------------------------------------------------------------------------------- /tests/test_compact.cpp: -------------------------------------------------------------------------------- 1 | #ifdef PUGIXML_COMPACT 2 | #include "test.hpp" 3 | 4 | using namespace pugi; 5 | 6 | static void overflow_hash_table(xml_document& doc) 7 | { 8 | xml_node n = doc.child(STR("n")); 9 | 10 | // compact encoding assumes next_sibling is a forward-only pointer so we can allocate hash entries by reordering nodes 11 | // we allocate enough hash entries to be exactly on the edge of rehash threshold 12 | for (int i = 0; i < 8; ++i) 13 | CHECK(n.prepend_child(node_element)); 14 | } 15 | 16 | TEST_XML_FLAGS(compact_out_of_memory_string, "", parse_pi) 17 | { 18 | test_runner::_memory_fail_threshold = 1; 19 | 20 | overflow_hash_table(doc); 21 | 22 | xml_attribute a = doc.child(STR("n")).attribute(STR("a")); 23 | xml_node pi = doc.last_child(); 24 | 25 | CHECK_ALLOC_FAIL(CHECK(!pi.set_name(STR("name")))); 26 | CHECK_ALLOC_FAIL(CHECK(!pi.set_value(STR("value")))); 27 | CHECK_ALLOC_FAIL(CHECK(!a.set_name(STR("name")))); 28 | CHECK_ALLOC_FAIL(CHECK(!a.set_value(STR("value")))); 29 | } 30 | 31 | TEST_XML(compact_out_of_memory_attribute, "") 32 | { 33 | test_runner::_memory_fail_threshold = 1; 34 | 35 | overflow_hash_table(doc); 36 | 37 | xml_node n = doc.child(STR("n")); 38 | xml_attribute a = n.attribute(STR("a")); 39 | 40 | CHECK_ALLOC_FAIL(CHECK(!n.append_attribute(STR("")))); 41 | CHECK_ALLOC_FAIL(CHECK(!n.prepend_attribute(STR("")))); 42 | CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_after(STR(""), a))); 43 | CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_before(STR(""), a))); 44 | } 45 | 46 | TEST_XML(compact_out_of_memory_attribute_copy, "") 47 | { 48 | test_runner::_memory_fail_threshold = 1; 49 | 50 | overflow_hash_table(doc); 51 | 52 | xml_node n = doc.child(STR("n")); 53 | xml_attribute a = n.attribute(STR("a")); 54 | 55 | CHECK_ALLOC_FAIL(CHECK(!n.append_copy(a))); 56 | CHECK_ALLOC_FAIL(CHECK(!n.prepend_copy(a))); 57 | CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_after(a, a))); 58 | CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_before(a, a))); 59 | } 60 | 61 | TEST_XML(compact_out_of_memory_node, "") 62 | { 63 | test_runner::_memory_fail_threshold = 1; 64 | 65 | overflow_hash_table(doc); 66 | 67 | xml_node n = doc.child(STR("n")); 68 | 69 | CHECK_ALLOC_FAIL(CHECK(!doc.append_child(node_element))); 70 | CHECK_ALLOC_FAIL(CHECK(!doc.prepend_child(node_element))); 71 | CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_after(node_element, n))); 72 | CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_before(node_element, n))); 73 | } 74 | 75 | TEST_XML(compact_out_of_memory_node_copy, "") 76 | { 77 | test_runner::_memory_fail_threshold = 1; 78 | 79 | overflow_hash_table(doc); 80 | 81 | xml_node n = doc.child(STR("n")); 82 | 83 | CHECK_ALLOC_FAIL(CHECK(!doc.append_copy(n))); 84 | CHECK_ALLOC_FAIL(CHECK(!doc.prepend_copy(n))); 85 | CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_after(n, n))); 86 | CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_before(n, n))); 87 | } 88 | 89 | TEST_XML(compact_out_of_memory_node_move, "") 90 | { 91 | test_runner::_memory_fail_threshold = 1; 92 | 93 | overflow_hash_table(doc); 94 | 95 | xml_node n = doc.child(STR("n")); 96 | xml_node ne = doc.child(STR("ne")); 97 | 98 | CHECK_ALLOC_FAIL(CHECK(!doc.append_move(n))); 99 | CHECK_ALLOC_FAIL(CHECK(!doc.prepend_move(n))); 100 | CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_after(n, ne))); 101 | CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_before(n, ne))); 102 | } 103 | 104 | TEST_XML(compact_out_of_memory_remove, "") 105 | { 106 | test_runner::_memory_fail_threshold = 1; 107 | 108 | overflow_hash_table(doc); 109 | 110 | xml_node n = doc.child(STR("n")); 111 | xml_attribute a = n.attribute(STR("a")); 112 | 113 | CHECK_ALLOC_FAIL(CHECK(!n.remove_attribute(a))); 114 | CHECK_ALLOC_FAIL(CHECK(!doc.remove_child(n))); 115 | } 116 | 117 | TEST_XML(compact_pointer_attribute_list, "") 118 | { 119 | xml_node n = doc.child(STR("n")); 120 | xml_attribute a = n.attribute(STR("a")); 121 | 122 | // make sure we fill the page with node x 123 | for (int i = 0; i < 1000; ++i) 124 | doc.append_child(STR("x")); 125 | 126 | // this requires extended encoding for prev_attribute_c/next_attribute 127 | n.append_attribute(STR("b")); 128 | 129 | // this requires extended encoding for first_attribute 130 | n.remove_attribute(a); 131 | 132 | CHECK(!n.attribute(STR("a"))); 133 | CHECK(n.attribute(STR("b"))); 134 | } 135 | 136 | TEST_XML(compact_pointer_node_list, "") 137 | { 138 | xml_node n = doc.child(STR("n")); 139 | 140 | // make sure we fill the page with node x 141 | // this requires extended encoding for prev_sibling_c/next_sibling 142 | for (int i = 0; i < 1000; ++i) 143 | doc.append_child(STR("x")); 144 | 145 | // this requires extended encoding for first_child 146 | n.append_child(STR("child")); 147 | 148 | CHECK(n.child(STR("child"))); 149 | } 150 | #endif 151 | -------------------------------------------------------------------------------- /tests/test.cpp: -------------------------------------------------------------------------------- 1 | #define _SCL_SECURE_NO_WARNINGS 2 | #define _SCL_SECURE_NO_DEPRECATE 3 | 4 | #include "test.hpp" 5 | 6 | #include "writer_string.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #ifndef PUGIXML_NO_XPATH 17 | static void build_document_order(std::vector& result, pugi::xml_node root) 18 | { 19 | result.push_back(pugi::xpath_node()); 20 | 21 | pugi::xml_node cur = root; 22 | 23 | for (;;) 24 | { 25 | result.push_back(cur); 26 | 27 | for (pugi::xml_attribute a = cur.first_attribute(); a; a = a.next_attribute()) 28 | result.push_back(pugi::xpath_node(a, cur)); 29 | 30 | if (cur.first_child()) 31 | cur = cur.first_child(); 32 | else if (cur.next_sibling()) 33 | cur = cur.next_sibling(); 34 | else 35 | { 36 | while (cur && !cur.next_sibling()) cur = cur.parent(); 37 | cur = cur.next_sibling(); 38 | 39 | if (!cur) break; 40 | } 41 | } 42 | } 43 | #endif 44 | 45 | bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs) 46 | { 47 | return (!lhs || !rhs) ? lhs == rhs : 48 | #ifdef PUGIXML_WCHAR_MODE 49 | wcscmp(lhs, rhs) == 0; 50 | #else 51 | strcmp(lhs, rhs) == 0; 52 | #endif 53 | } 54 | 55 | bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags) 56 | { 57 | xml_writer_string writer; 58 | 59 | node.print(writer, indent, flags, get_native_encoding()); 60 | 61 | return writer.as_string() == contents; 62 | } 63 | 64 | bool test_double_nan(double value) 65 | { 66 | #if defined(_MSC_VER) || defined(__BORLANDC__) 67 | return _isnan(value) != 0; 68 | #else 69 | return value != value; 70 | #endif 71 | } 72 | 73 | #ifndef PUGIXML_NO_XPATH 74 | static size_t strlength(const pugi::char_t* s) 75 | { 76 | #ifdef PUGIXML_WCHAR_MODE 77 | return wcslen(s); 78 | #else 79 | return strlen(s); 80 | #endif 81 | } 82 | 83 | bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, const pugi::char_t* expected) 84 | { 85 | pugi::xpath_query q(query, variables); 86 | if (!q) return false; 87 | 88 | const size_t capacity = 64; 89 | pugi::char_t result[capacity]; 90 | 91 | size_t size = q.evaluate_string(result, capacity, node); 92 | 93 | if (size != strlength(expected) + 1) 94 | return false; 95 | 96 | if (size <= capacity) 97 | return test_string_equal(result, expected); 98 | 99 | std::basic_string buffer(size, ' '); 100 | 101 | return q.evaluate_string(&buffer[0], size, node) == size && test_string_equal(buffer.c_str(), expected); 102 | } 103 | 104 | bool test_xpath_boolean(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, bool expected) 105 | { 106 | pugi::xpath_query q(query, variables); 107 | if (!q) return false; 108 | 109 | return q.evaluate_boolean(node) == expected; 110 | } 111 | 112 | bool test_xpath_number(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, double expected) 113 | { 114 | pugi::xpath_query q(query, variables); 115 | if (!q) return false; 116 | 117 | double value = q.evaluate_number(node); 118 | double absolute_error = fabs(value - expected); 119 | 120 | const double tolerance = 1e-15; 121 | return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance; 122 | } 123 | 124 | bool test_xpath_number_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables) 125 | { 126 | pugi::xpath_query q(query, variables); 127 | if (!q) return false; 128 | 129 | return test_double_nan(q.evaluate_number(node)); 130 | } 131 | 132 | bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables) 133 | { 134 | #ifdef PUGIXML_NO_EXCEPTIONS 135 | return !pugi::xpath_query(query, variables); 136 | #else 137 | try 138 | { 139 | pugi::xpath_query q(query, variables); 140 | return false; 141 | } 142 | catch (const pugi::xpath_exception&) 143 | { 144 | return true; 145 | } 146 | #endif 147 | } 148 | 149 | void xpath_node_set_tester::check(bool condition) 150 | { 151 | if (!condition) 152 | { 153 | test_runner::_failure_message = message; 154 | longjmp(test_runner::_failure_buffer, 1); 155 | } 156 | } 157 | 158 | xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message_): last(0), message(message_) 159 | { 160 | result = set; 161 | 162 | // only sort unsorted sets so that we're able to verify reverse order for some axes 163 | if (result.type() == pugi::xpath_node_set::type_unsorted) result.sort(); 164 | 165 | if (result.empty()) 166 | { 167 | document_order = 0; 168 | document_size = 0; 169 | } 170 | else 171 | { 172 | std::vector order; 173 | build_document_order(order, (result[0].attribute() ? result[0].parent() : result[0].node()).root()); 174 | 175 | document_order = new pugi::xpath_node[order.size()]; 176 | std::copy(order.begin(), order.end(), document_order); 177 | 178 | document_size = order.size(); 179 | } 180 | } 181 | 182 | xpath_node_set_tester::~xpath_node_set_tester() 183 | { 184 | // check that we processed everything 185 | check(last == result.size()); 186 | 187 | delete[] document_order; 188 | } 189 | 190 | xpath_node_set_tester& xpath_node_set_tester::operator%(unsigned int expected) 191 | { 192 | // check element count 193 | check(last < result.size()); 194 | 195 | // check document order 196 | check(expected < document_size); 197 | check(result.begin()[last] == document_order[expected]); 198 | 199 | // continue to the next element 200 | last++; 201 | 202 | return *this; 203 | } 204 | 205 | #endif 206 | 207 | bool is_little_endian() 208 | { 209 | unsigned int ui = 1; 210 | return *reinterpret_cast(&ui) == 1; 211 | } 212 | 213 | pugi::xml_encoding get_native_encoding() 214 | { 215 | #ifdef PUGIXML_WCHAR_MODE 216 | return pugi::encoding_wchar; 217 | #else 218 | return pugi::encoding_utf8; 219 | #endif 220 | } 221 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | #include "test.hpp" 2 | #include "allocator.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #ifndef PUGIXML_NO_EXCEPTIONS 12 | # include 13 | #endif 14 | 15 | #ifdef _WIN32_WCE 16 | # undef DebugBreak 17 | # pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union 18 | # include 19 | #endif 20 | 21 | test_runner* test_runner::_tests = 0; 22 | size_t test_runner::_memory_fail_threshold = 0; 23 | bool test_runner::_memory_fail_triggered = false; 24 | jmp_buf test_runner::_failure_buffer; 25 | const char* test_runner::_failure_message; 26 | const char* test_runner::_temp_path; 27 | 28 | static size_t g_memory_total_size = 0; 29 | static size_t g_memory_total_count = 0; 30 | static size_t g_memory_fail_triggered = false; 31 | 32 | static void* custom_allocate(size_t size) 33 | { 34 | if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size) 35 | { 36 | g_memory_fail_triggered = true; 37 | test_runner::_memory_fail_triggered = true; 38 | 39 | return 0; 40 | } 41 | else 42 | { 43 | void* ptr = memory_allocate(size); 44 | if (!ptr) return 0; 45 | 46 | g_memory_total_size += memory_size(ptr); 47 | g_memory_total_count++; 48 | 49 | return ptr; 50 | } 51 | } 52 | 53 | #ifndef PUGIXML_NO_EXCEPTIONS 54 | static void* custom_allocate_throw(size_t size) 55 | { 56 | void* result = custom_allocate(size); 57 | 58 | if (!result) 59 | throw std::bad_alloc(); 60 | 61 | return result; 62 | } 63 | #endif 64 | 65 | static void custom_deallocate(void* ptr) 66 | { 67 | assert(ptr); 68 | 69 | g_memory_total_size -= memory_size(ptr); 70 | g_memory_total_count--; 71 | 72 | memory_deallocate(ptr); 73 | } 74 | 75 | static void replace_memory_management() 76 | { 77 | // create some document to touch original functions 78 | { 79 | pugi::xml_document doc; 80 | doc.append_child().set_name(STR("node")); 81 | } 82 | 83 | // replace functions 84 | pugi::set_memory_management_functions(custom_allocate, custom_deallocate); 85 | } 86 | 87 | #if defined(_MSC_VER) && _MSC_VER > 1200 && _MSC_VER < 1400 && !defined(__INTEL_COMPILER) && !defined(__DMC__) 88 | #include 89 | 90 | namespace std 91 | { 92 | _CRTIMP2 _Prhand _Raise_handler; 93 | _CRTIMP2 void __cdecl _Throw(const exception&) {} 94 | } 95 | #endif 96 | 97 | static bool run_test(test_runner* test, const char* test_name, pugi::allocation_function allocate) 98 | { 99 | #ifndef PUGIXML_NO_EXCEPTIONS 100 | try 101 | { 102 | #endif 103 | g_memory_total_size = 0; 104 | g_memory_total_count = 0; 105 | g_memory_fail_triggered = false; 106 | test_runner::_memory_fail_threshold = 0; 107 | test_runner::_memory_fail_triggered = false; 108 | 109 | pugi::set_memory_management_functions(allocate, custom_deallocate); 110 | 111 | #ifdef _MSC_VER 112 | # pragma warning(push) 113 | # pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable 114 | # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged 115 | #endif 116 | 117 | volatile int result = setjmp(test_runner::_failure_buffer); 118 | 119 | #ifdef _MSC_VER 120 | # pragma warning(pop) 121 | #endif 122 | 123 | if (result) 124 | { 125 | printf("Test %s failed: %s\n", test_name, test_runner::_failure_message); 126 | return false; 127 | } 128 | 129 | test->run(); 130 | 131 | if (test_runner::_memory_fail_triggered) 132 | { 133 | printf("Test %s failed: unguarded memory fail triggered\n", test_name); 134 | return false; 135 | } 136 | 137 | if (g_memory_total_size != 0 || g_memory_total_count != 0) 138 | { 139 | printf("Test %s failed: memory leaks found (%u bytes in %u allocations)\n", test_name, static_cast(g_memory_total_size), static_cast(g_memory_total_count)); 140 | return false; 141 | } 142 | 143 | return true; 144 | #ifndef PUGIXML_NO_EXCEPTIONS 145 | } 146 | catch (const std::exception& e) 147 | { 148 | printf("Test %s failed: exception %s\n", test_name, e.what()); 149 | return false; 150 | } 151 | catch (...) 152 | { 153 | printf("Test %s failed for unknown reason\n", test_name); 154 | return false; 155 | } 156 | #endif 157 | } 158 | 159 | #if defined(__CELLOS_LV2__) && defined(PUGIXML_NO_EXCEPTIONS) && !defined(__SNC__) 160 | #include 161 | 162 | void std::exception::_Raise() const 163 | { 164 | abort(); 165 | } 166 | #endif 167 | 168 | int main(int, char** argv) 169 | { 170 | #ifdef __BORLANDC__ 171 | _control87(MCW_EM | PC_53, MCW_EM | MCW_PC); 172 | #endif 173 | 174 | // setup temp path as the executable folder 175 | std::string temp = argv[0]; 176 | std::string::size_type slash = temp.find_last_of("\\/"); 177 | temp.erase((slash != std::string::npos) ? slash + 1 : 0); 178 | 179 | test_runner::_temp_path = temp.c_str(); 180 | 181 | replace_memory_management(); 182 | 183 | unsigned int total = 0; 184 | unsigned int passed = 0; 185 | 186 | test_runner* test = 0; // gcc3 "variable might be used uninitialized in this function" bug workaround 187 | 188 | for (test = test_runner::_tests; test; test = test->_next) 189 | { 190 | total++; 191 | passed += run_test(test, test->_name, custom_allocate); 192 | 193 | if (g_memory_fail_triggered) 194 | { 195 | // run tests that trigger memory failures twice - with an allocator that returns NULL and with an allocator that throws 196 | #ifndef PUGIXML_NO_EXCEPTIONS 197 | total++; 198 | passed += run_test(test, (test->_name + std::string(" (throw)")).c_str(), custom_allocate_throw); 199 | #endif 200 | } 201 | } 202 | 203 | unsigned int failed = total - passed; 204 | 205 | if (failed != 0) 206 | printf("FAILURE: %u out of %u tests failed.\n", failed, total); 207 | else 208 | printf("Success: %u tests passed.\n", total); 209 | 210 | return failed; 211 | } 212 | 213 | #ifdef _WIN32_WCE 214 | int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) 215 | { 216 | return main(0, NULL); 217 | } 218 | #endif 219 | -------------------------------------------------------------------------------- /scripts/pugixml.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0424128F67AB5C730232235E /* pugixml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 47481C4F0E03673E0E780637 /* pugixml.cpp */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXFileReference section */ 14 | 0B66463C5F896E6449051D38 /* pugiconfig.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = "pugiconfig.hpp"; path = "pugiconfig.hpp"; sourceTree = ""; }; 15 | 47481C4F0E03673E0E780637 /* pugixml.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "pugixml.cpp"; path = "pugixml.cpp"; sourceTree = ""; }; 16 | 6C911F0460FC44CD3B1B5624 /* pugixml.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = "pugixml.hpp"; path = "pugixml.hpp"; sourceTree = ""; }; 17 | 1DA04ADC64C3566D16C45B6D /* libpugixmld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libpugixmld.a"; path = "libpugixmld.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 18 | /* End PBXFileReference section */ 19 | 20 | /* Begin PBXFrameworksBuildPhase section */ 21 | 2BA00212518037166623673F /* Frameworks */ = { 22 | isa = PBXFrameworksBuildPhase; 23 | buildActionMask = 2147483647; 24 | files = ( 25 | ); 26 | runOnlyForDeploymentPostprocessing = 0; 27 | }; 28 | /* End PBXFrameworksBuildPhase section */ 29 | 30 | /* Begin PBXGroup section */ 31 | 19E0517F3CF26ED63AE23641 /* pugixml */ = { 32 | isa = PBXGroup; 33 | children = ( 34 | 578963B4309E714F05E01D71 /* src */, 35 | 219F66186DDF392149043810 /* Products */, 36 | ); 37 | name = "pugixml"; 38 | sourceTree = ""; 39 | }; 40 | 578963B4309E714F05E01D71 /* src */ = { 41 | isa = PBXGroup; 42 | children = ( 43 | 0B66463C5F896E6449051D38 /* pugiconfig.hpp */, 44 | 47481C4F0E03673E0E780637 /* pugixml.cpp */, 45 | 6C911F0460FC44CD3B1B5624 /* pugixml.hpp */, 46 | ); 47 | name = "src"; 48 | path = ../src; 49 | sourceTree = ""; 50 | }; 51 | 219F66186DDF392149043810 /* Products */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | 1DA04ADC64C3566D16C45B6D /* libpugixmld.a */, 55 | ); 56 | name = "Products"; 57 | sourceTree = ""; 58 | }; 59 | /* End PBXGroup section */ 60 | 61 | /* Begin PBXNativeTarget section */ 62 | 6B55152571905B6C3A6F39D0 /* pugixml */ = { 63 | isa = PBXNativeTarget; 64 | buildConfigurationList = 73BF376C14AA1ECC0AC517ED /* Build configuration list for PBXNativeTarget "pugixml" */; 65 | buildPhases = ( 66 | 6CA66B9B6252229A36E8733C /* Resources */, 67 | 287808486FBF545206A47CC1 /* Sources */, 68 | 2BA00212518037166623673F /* Frameworks */, 69 | ); 70 | buildRules = ( 71 | ); 72 | dependencies = ( 73 | ); 74 | name = "pugixml"; 75 | productName = "pugixml"; 76 | productReference = 1DA04ADC64C3566D16C45B6D /* libpugixmld.a */; 77 | productType = "com.apple.product-type.library.static"; 78 | }; 79 | /* End PBXNativeTarget section */ 80 | 81 | /* Begin PBXProject section */ 82 | 08FB7793FE84155DC02AAC07 /* Project object */ = { 83 | isa = PBXProject; 84 | buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "pugixml" */; 85 | compatibilityVersion = "Xcode 3.1"; 86 | hasScannedForEncodings = 1; 87 | mainGroup = 19E0517F3CF26ED63AE23641 /* pugixml */; 88 | projectDirPath = ""; 89 | projectRoot = ""; 90 | targets = ( 91 | 6B55152571905B6C3A6F39D0 /* libpugixmld.a */, 92 | ); 93 | }; 94 | /* End PBXProject section */ 95 | 96 | /* Begin PBXResourcesBuildPhase section */ 97 | 6CA66B9B6252229A36E8733C /* Resources */ = { 98 | isa = PBXResourcesBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | /* End PBXResourcesBuildPhase section */ 105 | 106 | /* Begin PBXSourcesBuildPhase section */ 107 | 287808486FBF545206A47CC1 /* Sources */ = { 108 | isa = PBXSourcesBuildPhase; 109 | buildActionMask = 2147483647; 110 | files = ( 111 | 0424128F67AB5C730232235E /* pugixml.cpp in Sources */, 112 | ); 113 | runOnlyForDeploymentPostprocessing = 0; 114 | }; 115 | /* End PBXSourcesBuildPhase section */ 116 | 117 | /* Begin PBXVariantGroup section */ 118 | /* End PBXVariantGroup section */ 119 | 120 | /* Begin XCBuildConfiguration section */ 121 | 4FDB54E4253E36FC55CE27E8 /* Debug */ = { 122 | isa = XCBuildConfiguration; 123 | buildSettings = { 124 | ALWAYS_SEARCH_USER_PATHS = NO; 125 | CONFIGURATION_BUILD_DIR = xcode3; 126 | GCC_DYNAMIC_NO_PIC = NO; 127 | GCC_MODEL_TUNING = G5; 128 | INSTALL_PATH = /usr/local/lib; 129 | PRODUCT_NAME = "pugixmld"; 130 | }; 131 | name = "Debug"; 132 | }; 133 | 0A4C28F553990E0405306C15 /* Release */ = { 134 | isa = XCBuildConfiguration; 135 | buildSettings = { 136 | ALWAYS_SEARCH_USER_PATHS = NO; 137 | CONFIGURATION_BUILD_DIR = xcode3; 138 | GCC_DYNAMIC_NO_PIC = NO; 139 | GCC_MODEL_TUNING = G5; 140 | INSTALL_PATH = /usr/local/lib; 141 | PRODUCT_NAME = "pugixml"; 142 | }; 143 | name = "Release"; 144 | }; 145 | 65DB0F6D27EA20852B6E3BB4 /* Debug */ = { 146 | isa = XCBuildConfiguration; 147 | buildSettings = { 148 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 149 | CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; 150 | CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; 151 | COPY_PHASE_STRIP = NO; 152 | GCC_C_LANGUAGE_STANDARD = gnu99; 153 | GCC_OPTIMIZATION_LEVEL = 0; 154 | GCC_PREPROCESSOR_DEFINITIONS = ( 155 | "_DEBUG", 156 | ); 157 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 158 | GCC_WARN_UNUSED_VARIABLE = YES; 159 | OBJROOT = "xcode3/Universal/Debug"; 160 | ONLY_ACTIVE_ARCH = NO; 161 | PREBINDING = NO; 162 | SYMROOT = "xcode3"; 163 | }; 164 | name = "Debug"; 165 | }; 166 | 5314084032B57C1A11945858 /* Release */ = { 167 | isa = XCBuildConfiguration; 168 | buildSettings = { 169 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 170 | CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; 171 | CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; 172 | COPY_PHASE_STRIP = NO; 173 | GCC_C_LANGUAGE_STANDARD = gnu99; 174 | GCC_OPTIMIZATION_LEVEL = s; 175 | GCC_PREPROCESSOR_DEFINITIONS = ( 176 | "NDEBUG", 177 | ); 178 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 179 | GCC_WARN_UNUSED_VARIABLE = YES; 180 | OBJROOT = "xcode3/Universal/Release"; 181 | ONLY_ACTIVE_ARCH = NO; 182 | PREBINDING = NO; 183 | SYMROOT = "xcode3"; 184 | }; 185 | name = "Release"; 186 | }; 187 | /* End XCBuildConfiguration section */ 188 | 189 | /* Begin XCConfigurationList section */ 190 | 73BF376C14AA1ECC0AC517ED /* Build configuration list for PBXNativeTarget "libpugixmld.a" */ = { 191 | isa = XCConfigurationList; 192 | buildConfigurations = ( 193 | 4FDB54E4253E36FC55CE27E8 /* Debug */, 194 | 0A4C28F553990E0405306C15 /* Release */, 195 | ); 196 | defaultConfigurationIsVisible = 0; 197 | defaultConfigurationName = "Debug"; 198 | }; 199 | 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "pugixml" */ = { 200 | isa = XCConfigurationList; 201 | buildConfigurations = ( 202 | 65DB0F6D27EA20852B6E3BB4 /* Debug */, 203 | 5314084032B57C1A11945858 /* Release */, 204 | ); 205 | defaultConfigurationIsVisible = 0; 206 | defaultConfigurationName = "Debug"; 207 | }; 208 | /* End XCConfigurationList section */ 209 | 210 | }; 211 | rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; 212 | } 213 | -------------------------------------------------------------------------------- /scripts/pugixml_vs2008.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 21 | 28 | 31 | 34 | 37 | 40 | 43 | 55 | 58 | 62 | 65 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 94 | 101 | 104 | 107 | 110 | 113 | 117 | 129 | 132 | 136 | 139 | 143 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 168 | 175 | 178 | 181 | 184 | 187 | 190 | 202 | 205 | 209 | 212 | 216 | 219 | 222 | 225 | 228 | 231 | 234 | 237 | 240 | 241 | 248 | 251 | 254 | 257 | 260 | 264 | 276 | 279 | 283 | 286 | 290 | 293 | 296 | 299 | 302 | 305 | 308 | 311 | 314 | 315 | 316 | 317 | 318 | 319 | 323 | 326 | 327 | 330 | 331 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | -------------------------------------------------------------------------------- /scripts/pugixml_vs2008_static.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 21 | 28 | 31 | 34 | 37 | 40 | 43 | 55 | 58 | 62 | 65 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 94 | 101 | 104 | 107 | 110 | 113 | 117 | 129 | 132 | 136 | 139 | 143 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 168 | 175 | 178 | 181 | 184 | 187 | 190 | 202 | 205 | 209 | 212 | 216 | 219 | 222 | 225 | 228 | 231 | 234 | 237 | 240 | 241 | 248 | 251 | 254 | 257 | 260 | 264 | 276 | 279 | 283 | 286 | 290 | 293 | 296 | 299 | 302 | 305 | 308 | 311 | 314 | 315 | 316 | 317 | 318 | 319 | 323 | 326 | 327 | 330 | 331 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | -------------------------------------------------------------------------------- /tests/test_memory.cpp: -------------------------------------------------------------------------------- 1 | #include "test.hpp" 2 | 3 | #include "writer_string.hpp" 4 | #include "allocator.hpp" 5 | 6 | #include 7 | #include 8 | 9 | using namespace pugi; 10 | 11 | namespace 12 | { 13 | int page_allocs = 0; 14 | int page_deallocs = 0; 15 | 16 | bool is_page(size_t size) 17 | { 18 | return size >= 16384; 19 | } 20 | 21 | void* allocate(size_t size) 22 | { 23 | void* ptr = memory_allocate(size); 24 | page_allocs += is_page(memory_size(ptr)); 25 | return ptr; 26 | } 27 | 28 | void deallocate(void* ptr) 29 | { 30 | page_deallocs += is_page(memory_size(ptr)); 31 | memory_deallocate(ptr); 32 | } 33 | } 34 | 35 | TEST(memory_custom_memory_management) 36 | { 37 | page_allocs = page_deallocs = 0; 38 | 39 | // remember old functions 40 | allocation_function old_allocate = get_memory_allocation_function(); 41 | deallocation_function old_deallocate = get_memory_deallocation_function(); 42 | 43 | // replace functions 44 | set_memory_management_functions(allocate, deallocate); 45 | 46 | { 47 | // parse document 48 | xml_document doc; 49 | 50 | CHECK(page_allocs == 0 && page_deallocs == 0); 51 | 52 | CHECK(doc.load_string(STR(""))); 53 | 54 | CHECK(page_allocs == 1 && page_deallocs == 0); 55 | 56 | // modify document (no new page) 57 | CHECK(doc.first_child().set_name(STR("foobars"))); 58 | CHECK(page_allocs == 1 && page_deallocs == 0); 59 | 60 | // modify document (new page) 61 | std::basic_string s(65536, 'x'); 62 | 63 | CHECK(doc.first_child().set_name(s.c_str())); 64 | CHECK(page_allocs == 2 && page_deallocs == 0); 65 | 66 | // modify document (new page, old one should die) 67 | s += s; 68 | 69 | CHECK(doc.first_child().set_name(s.c_str())); 70 | CHECK(page_allocs == 3 && page_deallocs == 1); 71 | } 72 | 73 | CHECK(page_allocs == 3 && page_deallocs == 3); 74 | 75 | // restore old functions 76 | set_memory_management_functions(old_allocate, old_deallocate); 77 | } 78 | 79 | TEST(memory_large_allocations) 80 | { 81 | page_allocs = page_deallocs = 0; 82 | 83 | // remember old functions 84 | allocation_function old_allocate = get_memory_allocation_function(); 85 | deallocation_function old_deallocate = get_memory_deallocation_function(); 86 | 87 | // replace functions 88 | set_memory_management_functions(allocate, deallocate); 89 | 90 | { 91 | xml_document doc; 92 | 93 | CHECK(page_allocs == 0 && page_deallocs == 0); 94 | 95 | // initial fill 96 | for (size_t i = 0; i < 128; ++i) 97 | { 98 | std::basic_string s(i * 128, 'x'); 99 | 100 | CHECK(doc.append_child(node_pcdata).set_value(s.c_str())); 101 | } 102 | 103 | CHECK(page_allocs > 0 && page_deallocs == 0); 104 | 105 | // grow-prune loop 106 | while (doc.first_child()) 107 | { 108 | xml_node node; 109 | 110 | // grow 111 | for (node = doc.first_child(); node; node = node.next_sibling()) 112 | { 113 | std::basic_string s = node.value(); 114 | 115 | CHECK(node.set_value((s + s).c_str())); 116 | } 117 | 118 | // prune 119 | for (node = doc.first_child(); node; ) 120 | { 121 | xml_node next = node.next_sibling().next_sibling(); 122 | 123 | node.parent().remove_child(node); 124 | 125 | node = next; 126 | } 127 | } 128 | 129 | CHECK(page_allocs == page_deallocs + 1); // only one live page left (it waits for new allocations) 130 | 131 | char buffer; 132 | CHECK(doc.load_buffer_inplace(&buffer, 0, parse_fragment, get_native_encoding())); 133 | 134 | CHECK(page_allocs == page_deallocs); // no live pages left 135 | } 136 | 137 | CHECK(page_allocs == page_deallocs); // everything is freed 138 | 139 | // restore old functions 140 | set_memory_management_functions(old_allocate, old_deallocate); 141 | } 142 | 143 | TEST(memory_page_management) 144 | { 145 | page_allocs = page_deallocs = 0; 146 | 147 | // remember old functions 148 | allocation_function old_allocate = get_memory_allocation_function(); 149 | deallocation_function old_deallocate = get_memory_deallocation_function(); 150 | 151 | // replace functions 152 | set_memory_management_functions(allocate, deallocate); 153 | 154 | { 155 | xml_document doc; 156 | 157 | CHECK(page_allocs == 0 && page_deallocs == 0); 158 | 159 | // initial fill 160 | std::vector nodes; 161 | 162 | for (size_t i = 0; i < 4000; ++i) 163 | { 164 | xml_node node = doc.append_child(STR("n")); 165 | CHECK(node); 166 | 167 | nodes.push_back(node); 168 | } 169 | 170 | CHECK(page_allocs > 0 && page_deallocs == 0); 171 | 172 | // grow-prune loop 173 | size_t offset = 0; 174 | size_t prime = 15485863; 175 | 176 | while (nodes.size() > 0) 177 | { 178 | offset = (offset + prime) % nodes.size(); 179 | 180 | doc.remove_child(nodes[offset]); 181 | 182 | nodes[offset] = nodes.back(); 183 | nodes.pop_back(); 184 | } 185 | 186 | CHECK(page_allocs == page_deallocs + 1); // only one live page left (it waits for new allocations) 187 | 188 | char buffer; 189 | CHECK(doc.load_buffer_inplace(&buffer, 0, parse_fragment, get_native_encoding())); 190 | 191 | CHECK(page_allocs == page_deallocs); // no live pages left 192 | } 193 | 194 | CHECK(page_allocs == page_deallocs); // everything is freed 195 | 196 | // restore old functions 197 | set_memory_management_functions(old_allocate, old_deallocate); 198 | } 199 | 200 | TEST(memory_string_allocate_increasing) 201 | { 202 | xml_document doc; 203 | 204 | doc.append_child(node_pcdata).set_value(STR("x")); 205 | 206 | std::basic_string s = STR("ab"); 207 | 208 | for (int i = 0; i < 17; ++i) 209 | { 210 | doc.append_child(node_pcdata).set_value(s.c_str()); 211 | 212 | s += s; 213 | } 214 | 215 | std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8); 216 | 217 | CHECK(result.size() == 262143); 218 | CHECK(result[0] == 'x'); 219 | 220 | for (size_t j = 1; j < result.size(); ++j) 221 | { 222 | CHECK(result[j] == (j % 2 ? 'a' : 'b')); 223 | } 224 | } 225 | 226 | TEST(memory_string_allocate_decreasing) 227 | { 228 | xml_document doc; 229 | 230 | std::basic_string s = STR("ab"); 231 | 232 | for (int i = 0; i < 17; ++i) s += s; 233 | 234 | for (int j = 0; j < 17; ++j) 235 | { 236 | s.resize(s.size() / 2); 237 | 238 | doc.append_child(node_pcdata).set_value(s.c_str()); 239 | } 240 | 241 | doc.append_child(node_pcdata).set_value(STR("x")); 242 | 243 | std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8); 244 | 245 | CHECK(result.size() == 262143); 246 | CHECK(result[result.size() - 1] == 'x'); 247 | 248 | for (size_t k = 0; k + 1 < result.size(); ++k) 249 | { 250 | CHECK(result[k] == (k % 2 ? 'b' : 'a')); 251 | } 252 | } 253 | 254 | TEST(memory_string_allocate_increasing_inplace) 255 | { 256 | xml_document doc; 257 | 258 | xml_node node = doc.append_child(node_pcdata); 259 | 260 | node.set_value(STR("x")); 261 | 262 | std::basic_string s = STR("ab"); 263 | 264 | for (int i = 0; i < 17; ++i) 265 | { 266 | node.set_value(s.c_str()); 267 | 268 | s += s; 269 | } 270 | 271 | std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8); 272 | 273 | CHECK(result.size() == 131072); 274 | 275 | for (size_t j = 0; j < result.size(); ++j) 276 | { 277 | CHECK(result[j] == (j % 2 ? 'b' : 'a')); 278 | } 279 | } 280 | 281 | TEST(memory_string_allocate_decreasing_inplace) 282 | { 283 | xml_document doc; 284 | 285 | xml_node node = doc.append_child(node_pcdata); 286 | 287 | std::basic_string s = STR("ab"); 288 | 289 | for (int i = 0; i < 17; ++i) s += s; 290 | 291 | for (int j = 0; j < 17; ++j) 292 | { 293 | s.resize(s.size() / 2); 294 | 295 | node.set_value(s.c_str()); 296 | } 297 | 298 | node.set_value(STR("x")); 299 | 300 | std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8); 301 | 302 | CHECK(result == "x"); 303 | } 304 | -------------------------------------------------------------------------------- /scripts/pugixml_vs2005.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 21 | 28 | 31 | 34 | 37 | 40 | 43 | 56 | 59 | 63 | 66 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 102 | 105 | 108 | 111 | 114 | 118 | 131 | 134 | 138 | 141 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 166 | 169 | 170 | 177 | 180 | 183 | 186 | 189 | 192 | 205 | 208 | 212 | 215 | 219 | 222 | 225 | 228 | 231 | 234 | 237 | 240 | 243 | 244 | 251 | 254 | 257 | 260 | 263 | 267 | 280 | 283 | 287 | 290 | 294 | 297 | 300 | 303 | 306 | 309 | 312 | 315 | 318 | 319 | 320 | 321 | 322 | 323 | 327 | 330 | 331 | 334 | 335 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | -------------------------------------------------------------------------------- /scripts/pugixml_vs2005_static.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 21 | 28 | 31 | 34 | 37 | 40 | 43 | 56 | 59 | 63 | 66 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 102 | 105 | 108 | 111 | 114 | 118 | 131 | 134 | 138 | 141 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 166 | 169 | 170 | 177 | 180 | 183 | 186 | 189 | 192 | 205 | 208 | 212 | 215 | 219 | 222 | 225 | 228 | 231 | 234 | 237 | 240 | 243 | 244 | 251 | 254 | 257 | 260 | 263 | 267 | 280 | 283 | 287 | 290 | 294 | 297 | 300 | 303 | 306 | 309 | 312 | 315 | 318 | 319 | 320 | 321 | 322 | 323 | 327 | 330 | 331 | 334 | 335 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | -------------------------------------------------------------------------------- /tests/test_xpath_paths_abbrev_w3c.cpp: -------------------------------------------------------------------------------- 1 | #ifndef PUGIXML_NO_XPATH 2 | 3 | #include "test.hpp" 4 | 5 | using namespace pugi; 6 | 7 | TEST_XML(xpath_paths_abbrev_w3c_1, "") 8 | { 9 | xml_node c; 10 | xml_node n = doc.child(STR("node")); 11 | 12 | CHECK_XPATH_NODESET(c, STR("para")); 13 | CHECK_XPATH_NODESET(n, STR("para")) % 3 % 5; 14 | } 15 | 16 | TEST_XML(xpath_paths_abbrev_w3c_2, "") 17 | { 18 | xml_node c; 19 | xml_node n = doc.child(STR("node")); 20 | 21 | CHECK_XPATH_NODESET(c, STR("*")); 22 | CHECK_XPATH_NODESET(n, STR("*")) % 3 % 4 % 5; 23 | } 24 | 25 | TEST_XML(xpath_paths_abbrev_w3c_3, "pcdata") 26 | { 27 | xml_node c; 28 | xml_node n = doc.child(STR("node")); 29 | 30 | CHECK_XPATH_NODESET(c, STR("text()")); 31 | CHECK_XPATH_NODESET(n, STR("text()")) % 3 % 5; 32 | } 33 | 34 | TEST_XML(xpath_paths_abbrev_w3c_4, "") 35 | { 36 | xml_node c; 37 | xml_node n = doc.child(STR("node")); 38 | 39 | CHECK_XPATH_NODESET(c, STR("@name")); 40 | CHECK_XPATH_NODESET(n, STR("@name")) % 3; 41 | } 42 | 43 | TEST_XML(xpath_paths_abbrev_w3c_5, "") 44 | { 45 | xml_node c; 46 | xml_node n = doc.child(STR("node")); 47 | 48 | CHECK_XPATH_NODESET(c, STR("@*")); 49 | CHECK_XPATH_NODESET(n, STR("@*")) % 3 % 4; 50 | } 51 | 52 | TEST_XML(xpath_paths_abbrev_w3c_6, "") 53 | { 54 | xml_node c; 55 | xml_node n = doc.child(STR("node")); 56 | 57 | CHECK_XPATH_NODESET(c, STR("para[1]")); 58 | CHECK_XPATH_NODESET(n, STR("para[1]")) % 3; 59 | } 60 | 61 | TEST_XML(xpath_paths_abbrev_w3c_7, "") 62 | { 63 | xml_node c; 64 | xml_node n = doc.child(STR("node")); 65 | 66 | CHECK_XPATH_NODESET(c, STR("para[last()]")); 67 | CHECK_XPATH_NODESET(n, STR("para[last()]")) % 6; 68 | } 69 | 70 | TEST_XML(xpath_paths_abbrev_w3c_8, "") 71 | { 72 | xml_node c; 73 | 74 | CHECK_XPATH_NODESET(c, STR("*/para")); 75 | CHECK_XPATH_NODESET(doc, STR("*/para")) % 3 % 9; 76 | } 77 | 78 | TEST_XML(xpath_paths_abbrev_w3c_9, "
") 79 | { 80 | xml_node c; 81 | xml_node n = doc.child(STR("doc")).child(STR("chapter")); 82 | 83 | CHECK_XPATH_NODESET(c, STR("/doc/chapter[5]/section[2]")); 84 | CHECK_XPATH_NODESET(n, STR("/doc/chapter[5]/section[2]")) % 9; 85 | CHECK_XPATH_NODESET(doc, STR("/doc/chapter[5]/section[2]")) % 9; 86 | } 87 | 88 | TEST_XML(xpath_paths_abbrev_w3c_10, "") 89 | { 90 | xml_node c; 91 | 92 | CHECK_XPATH_NODESET(c, STR("chapter//para")); 93 | CHECK_XPATH_NODESET(doc, STR("chapter//para")) % 3 % 4 % 5 % 7 % 9; 94 | } 95 | 96 | TEST_XML(xpath_paths_abbrev_w3c_11, "") 97 | { 98 | xml_node c; 99 | xml_node n = doc.child(STR("node")); 100 | 101 | CHECK_XPATH_NODESET(c, STR("//para")); 102 | CHECK_XPATH_NODESET(n, STR("//para")) % 3 % 4 % 5 % 7 % 9; 103 | CHECK_XPATH_NODESET(n.child(STR("para")), STR("//para")) % 3 % 4 % 5 % 7 % 9; 104 | } 105 | 106 | TEST_XML(xpath_paths_abbrev_w3c_12, "") 107 | { 108 | xml_node c; 109 | xml_node n = doc.child(STR("node")); 110 | 111 | CHECK_XPATH_NODESET(c, STR("//olist/item")); 112 | CHECK_XPATH_NODESET(n, STR("//olist/item")) % 4 % 8 % 9; 113 | CHECK_XPATH_NODESET(n.child(STR("olist")), STR("//olist/item")) % 4 % 8 % 9; 114 | } 115 | 116 | TEST_XML(xpath_paths_abbrev_w3c_13, "") 117 | { 118 | xml_node c; 119 | xml_node n = doc.child(STR("node")); 120 | 121 | CHECK_XPATH_NODESET(c, STR(".")); 122 | CHECK_XPATH_NODESET(n, STR(".")) % 2; 123 | CHECK_XPATH_NODESET(n.child(STR("child")), STR(".")) % 3; 124 | } 125 | 126 | TEST_XML(xpath_paths_abbrev_w3c_14, "") 127 | { 128 | xml_node c; 129 | xml_node n = doc.child(STR("node")); 130 | 131 | CHECK_XPATH_NODESET(c, STR(".//para")); 132 | CHECK_XPATH_NODESET(n, STR(".//para")) % 3 % 4 % 5 % 7 % 9; 133 | CHECK_XPATH_NODESET(n.child(STR("para")), STR(".//para")) % 4 % 5 % 7; 134 | } 135 | 136 | TEST_XML(xpath_paths_abbrev_w3c_15, "") 137 | { 138 | xml_node c; 139 | xml_node n = doc.child(STR("node")); 140 | 141 | CHECK_XPATH_NODESET(c, STR("..")); 142 | CHECK_XPATH_NODESET(n, STR("..")) % 1; 143 | CHECK_XPATH_NODESET(n.child(STR("child")), STR("..")) % 2; 144 | } 145 | 146 | TEST_XML(xpath_paths_abbrev_w3c_16, "") 147 | { 148 | xml_node c; 149 | xml_node n = doc.child(STR("node")); 150 | 151 | CHECK_XPATH_NODESET(c, STR("../@lang")); 152 | CHECK_XPATH_NODESET(n, STR("../@lang")); 153 | CHECK_XPATH_NODESET(n.child(STR("child")), STR("../@lang")) % 3; 154 | } 155 | 156 | TEST_XML(xpath_paths_abbrev_w3c_17, "") 157 | { 158 | xml_node c; 159 | xml_node n = doc.child(STR("node")); 160 | 161 | CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"]")); 162 | CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"]")) % 4 % 6 % 11 % 13 % 15; 163 | } 164 | 165 | TEST_XML(xpath_paths_abbrev_w3c_18, "") 166 | { 167 | xml_node c; 168 | xml_node n = doc.child(STR("node")); 169 | 170 | CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"][5]")); 171 | CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"][5]")) % 15; 172 | } 173 | 174 | TEST_XML(xpath_paths_abbrev_w3c_19a, "") 175 | { 176 | xml_node c; 177 | xml_node n = doc.child(STR("node")); 178 | 179 | CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]")); 180 | CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]")); 181 | } 182 | 183 | TEST_XML(xpath_paths_abbrev_w3c_19b, "") 184 | { 185 | xml_node c; 186 | xml_node n = doc.child(STR("node")); 187 | 188 | CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]")); 189 | CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]")) % 9; 190 | } 191 | 192 | TEST_XML(xpath_paths_abbrev_w3c_20, "fooIntroductionintroductionIntroductionfoo") 193 | { 194 | xml_node c; 195 | xml_node n = doc.child(STR("node")); 196 | 197 | CHECK_XPATH_NODESET(c, STR("chapter[title=\"Introduction\"]")); 198 | CHECK_XPATH_NODESET(n, STR("chapter[title=\"Introduction\"]")) % 6 % 13; 199 | } 200 | 201 | TEST_XML(xpath_paths_abbrev_w3c_21, "fooIntroductionintroductionIntroductionfoo") 202 | { 203 | xml_node c; 204 | xml_node n = doc.child(STR("node")); 205 | 206 | CHECK_XPATH_NODESET(c, STR("chapter[title]")); 207 | CHECK_XPATH_NODESET(n, STR("chapter[title]")) % 3 % 6 % 9 % 13; 208 | } 209 | 210 | TEST_XML(xpath_paths_abbrev_w3c_22, "") 211 | { 212 | xml_node c; 213 | xml_node n = doc.child(STR("node")); 214 | 215 | CHECK_XPATH_NODESET(c, STR("employee[@secretary and @assistant]")); 216 | CHECK_XPATH_NODESET(n, STR("employee[@secretary and @assistant]")) % 8 % 11; 217 | } 218 | 219 | #endif 220 | -------------------------------------------------------------------------------- /tests/test.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_TEST_TEST_HPP 2 | #define HEADER_TEST_TEST_HPP 3 | 4 | #include "../src/pugixml.hpp" 5 | 6 | #include 7 | 8 | #ifndef PUGIXML_NO_EXCEPTIONS 9 | #include 10 | #endif 11 | 12 | struct test_runner 13 | { 14 | test_runner(const char* name) 15 | { 16 | _name = name; 17 | _next = _tests; 18 | _tests = this; 19 | } 20 | 21 | virtual ~test_runner() {} 22 | 23 | virtual void run() = 0; 24 | 25 | const char* _name; 26 | test_runner* _next; 27 | 28 | static test_runner* _tests; 29 | static size_t _memory_fail_threshold; 30 | static bool _memory_fail_triggered; 31 | static jmp_buf _failure_buffer; 32 | static const char* _failure_message; 33 | 34 | static const char* _temp_path; 35 | }; 36 | 37 | bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs); 38 | 39 | template inline bool test_node_name_value(const Node& node, const pugi::char_t* name, const pugi::char_t* value) 40 | { 41 | return test_string_equal(node.name(), name) && test_string_equal(node.value(), value); 42 | } 43 | 44 | bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags); 45 | bool test_double_nan(double value); 46 | 47 | #ifndef PUGIXML_NO_XPATH 48 | bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, const pugi::char_t* expected); 49 | bool test_xpath_boolean(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, bool expected); 50 | bool test_xpath_number(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, double expected); 51 | bool test_xpath_number_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables); 52 | 53 | bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables); 54 | 55 | struct xpath_node_set_tester 56 | { 57 | pugi::xpath_node* document_order; 58 | size_t document_size; 59 | 60 | pugi::xpath_node_set result; 61 | unsigned int last; 62 | const char* message; 63 | 64 | void check(bool condition); 65 | 66 | xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message); 67 | ~xpath_node_set_tester(); 68 | 69 | xpath_node_set_tester& operator%(unsigned int expected); 70 | }; 71 | 72 | #endif 73 | 74 | struct dummy_fixture {}; 75 | 76 | #define TEST_FIXTURE(name, fixture) \ 77 | struct test_runner_helper_##name: fixture \ 78 | { \ 79 | void run(); \ 80 | }; \ 81 | static struct test_runner_##name: test_runner \ 82 | { \ 83 | test_runner_##name(): test_runner(#name) {} \ 84 | \ 85 | virtual void run() PUGIXML_OVERRIDE \ 86 | { \ 87 | test_runner_helper_##name helper; \ 88 | helper.run(); \ 89 | } \ 90 | } test_runner_instance_##name; \ 91 | void test_runner_helper_##name::run() 92 | 93 | #define TEST(name) TEST_FIXTURE(name, dummy_fixture) 94 | 95 | #define TEST_XML_FLAGS(name, xml, flags) \ 96 | struct test_fixture_##name \ 97 | { \ 98 | pugi::xml_document doc; \ 99 | \ 100 | test_fixture_##name() \ 101 | { \ 102 | CHECK(doc.load_string(PUGIXML_TEXT(xml), flags)); \ 103 | } \ 104 | \ 105 | private: \ 106 | test_fixture_##name(const test_fixture_##name&); \ 107 | test_fixture_##name& operator=(const test_fixture_##name&); \ 108 | }; \ 109 | \ 110 | TEST_FIXTURE(name, test_fixture_##name) 111 | 112 | #define TEST_XML(name, xml) TEST_XML_FLAGS(name, xml, pugi::parse_default) 113 | 114 | #define CHECK_JOIN(text, file, line) text " at " file ":" #line 115 | #define CHECK_JOIN2(text, file, line) CHECK_JOIN(text, file, line) 116 | #define CHECK_TEXT(condition, text) if (condition) ; else test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1) 117 | #define CHECK_FORCE_FAIL(text) test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1) 118 | 119 | #if (defined(_MSC_VER) && _MSC_VER == 1200) || defined(__MWERKS__) || (defined(__BORLANDC__) && __BORLANDC__ <= 0x540) 120 | # define STRINGIZE(value) "??" // Some compilers have issues with stringizing expressions that contain strings w/escaping inside 121 | #else 122 | # define STRINGIZE(value) #value 123 | #endif 124 | 125 | #define CHECK(condition) CHECK_TEXT(condition, STRINGIZE(condition) " is false") 126 | #define CHECK_STRING(value, expected) CHECK_TEXT(test_string_equal(value, expected), STRINGIZE(value) " is not equal to " STRINGIZE(expected)) 127 | #define CHECK_DOUBLE(value, expected) CHECK_TEXT((value > expected ? value - expected : expected - value) < 1e-6, STRINGIZE(value) " is not equal to " STRINGIZE(expected)) 128 | #define CHECK_DOUBLE_NAN(value) CHECK_TEXT(test_double_nan(value), STRINGIZE(value) " is not equal to NaN") 129 | #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)) 130 | #define CHECK_NODE_EX(node, expected, indent, flags) CHECK_TEXT(test_node(node, expected, indent, flags), STRINGIZE(node) " contents does not match " STRINGIZE(expected)) 131 | #define CHECK_NODE(node, expected) CHECK_NODE_EX(node, expected, PUGIXML_TEXT(""), pugi::format_raw) 132 | 133 | #ifndef PUGIXML_NO_XPATH 134 | #define CHECK_XPATH_STRING_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_string(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) 135 | #define CHECK_XPATH_BOOLEAN_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_boolean(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) 136 | #define CHECK_XPATH_NUMBER_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_number(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) 137 | #define CHECK_XPATH_NUMBER_NAN_VAR(node, query, variables) CHECK_TEXT(test_xpath_number_nan(node, query, variables), STRINGIZE(query) " does not evaluate to NaN in context " STRINGIZE(node)) 138 | #define CHECK_XPATH_NODESET_VAR(node, query, variables) xpath_node_set_tester(pugi::xpath_query(query, variables).evaluate_node_set(node), CHECK_JOIN2(STRINGIZE(query) " does not evaluate to expected set in context " STRINGIZE(node), __FILE__, __LINE__)) 139 | #define CHECK_XPATH_FAIL_VAR(query, variables) CHECK_TEXT(test_xpath_fail_compile(query, variables), STRINGIZE(query) " should not compile") 140 | 141 | #define CHECK_XPATH_STRING(node, query, expected) CHECK_XPATH_STRING_VAR(node, query, 0, expected) 142 | #define CHECK_XPATH_BOOLEAN(node, query, expected) CHECK_XPATH_BOOLEAN_VAR(node, query, 0, expected) 143 | #define CHECK_XPATH_NUMBER(node, query, expected) CHECK_XPATH_NUMBER_VAR(node, query, 0, expected) 144 | #define CHECK_XPATH_NUMBER_NAN(node, query) CHECK_XPATH_NUMBER_NAN_VAR(node, query, 0) 145 | #define CHECK_XPATH_NODESET(node, query) CHECK_XPATH_NODESET_VAR(node, query, 0) 146 | #define CHECK_XPATH_FAIL(query) CHECK_XPATH_FAIL_VAR(query, 0) 147 | #endif 148 | 149 | #ifdef PUGIXML_NO_EXCEPTIONS 150 | #define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); code; CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered) 151 | #else 152 | #define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); try { code; } catch (std::bad_alloc&) {} CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered) 153 | #endif 154 | 155 | #define STR(text) PUGIXML_TEXT(text) 156 | 157 | #if defined(__DMC__) || defined(__BORLANDC__) 158 | #define U_LITERALS // DMC does not understand \x01234 (it parses first three digits), but understands \u01234 159 | #endif 160 | 161 | #if (defined(_MSC_VER) && _MSC_VER == 1200) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER == 800) || defined(__BORLANDC__) 162 | // NaN comparison on MSVC6 is incorrect, see http://www.nabble.com/assertDoubleEquals,-NaN---Microsoft-Visual-Studio-6-td9137859.html 163 | // IC8 and BCC are also affected by the same bug 164 | # define MSVC6_NAN_BUG 165 | #endif 166 | 167 | inline wchar_t wchar_cast(unsigned int value) 168 | { 169 | return static_cast(value); // to avoid C4310 on MSVC 170 | } 171 | 172 | bool is_little_endian(); 173 | pugi::xml_encoding get_native_encoding(); 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /scripts/pugixml_vs2015.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {07CF01C0-B887-499D-AD9C-799CB6A9FE64} 23 | Win32Proj 24 | pugixml 25 | 8.1 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | StaticLibrary 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | StaticLibrary 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | StaticLibrary 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | vs2015\$(Platform)_$(Configuration)\ 74 | vs2015\$(Platform)_$(Configuration)\ 75 | pugixml 76 | 77 | 78 | vs2015\$(Platform)_$(Configuration)\ 79 | vs2015\$(Platform)_$(Configuration)\ 80 | pugixml 81 | 82 | 83 | vs2015\$(Platform)_$(Configuration)\ 84 | vs2015\$(Platform)_$(Configuration)\ 85 | pugixml 86 | 87 | 88 | vs2015\$(Platform)_$(Configuration)\ 89 | vs2015\$(Platform)_$(Configuration)\ 90 | pugixml 91 | 92 | 93 | 94 | 95 | 96 | Level3 97 | Disabled 98 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 99 | $(IntDir)$(TargetName).pdb 100 | OldStyle 101 | false 102 | 103 | 104 | Windows 105 | true 106 | 107 | 108 | 109 | 110 | 111 | 112 | Level3 113 | Disabled 114 | _DEBUG;_LIB;%(PreprocessorDefinitions) 115 | $(IntDir)$(TargetName).pdb 116 | OldStyle 117 | false 118 | 119 | 120 | Windows 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | 128 | 129 | MaxSpeed 130 | true 131 | true 132 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 133 | $(IntDir)$(TargetName).pdb 134 | OldStyle 135 | 136 | 137 | Windows 138 | true 139 | true 140 | true 141 | 142 | 143 | 144 | 145 | Level3 146 | 147 | 148 | MaxSpeed 149 | true 150 | true 151 | NDEBUG;_LIB;%(PreprocessorDefinitions) 152 | $(IntDir)$(TargetName).pdb 153 | OldStyle 154 | 155 | 156 | Windows 157 | true 158 | true 159 | true 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | --------------------------------------------------------------------------------