aboutsummaryrefslogtreecommitdiff
path: root/contrib/expat
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/expat')
-rw-r--r--contrib/expat/COPYING2
-rw-r--r--contrib/expat/Changes642
-rw-r--r--contrib/expat/Makefile.am35
-rw-r--r--contrib/expat/Makefile.in185
-rw-r--r--contrib/expat/README.md116
-rwxr-xr-xcontrib/expat/buildconf.sh55
-rw-r--r--contrib/expat/configure.ac209
-rw-r--r--contrib/expat/doc/Makefile.am7
-rw-r--r--contrib/expat/doc/Makefile.in46
-rw-r--r--contrib/expat/doc/expat.pngbin1029 -> 0 bytes
-rw-r--r--contrib/expat/doc/ok.min.css2
-rw-r--r--contrib/expat/doc/reference.html620
-rw-r--r--contrib/expat/doc/style.css134
-rw-r--r--contrib/expat/doc/xmlwf.1150
-rw-r--r--contrib/expat/doc/xmlwf.xml252
-rw-r--r--contrib/expat/examples/Makefile.am10
-rw-r--r--contrib/expat/examples/Makefile.in79
-rw-r--r--contrib/expat/examples/element_declarations.c234
-rw-r--r--contrib/expat/examples/elements.c52
-rw-r--r--contrib/expat/examples/outline.c83
-rw-r--r--contrib/expat/expat_config.h.in23
-rwxr-xr-xcontrib/expat/fix-xmltest-log.sh4
-rw-r--r--contrib/expat/fuzz/xml_parse_fuzzer.c105
-rw-r--r--contrib/expat/fuzz/xml_parsebuffer_fuzzer.c117
-rw-r--r--contrib/expat/lib/Makefile.am19
-rw-r--r--contrib/expat/lib/Makefile.in109
-rw-r--r--contrib/expat/lib/ascii.h7
-rw-r--r--contrib/expat/lib/asciitab.h4
-rw-r--r--contrib/expat/lib/expat.h80
-rw-r--r--contrib/expat/lib/expat_external.h9
-rw-r--r--contrib/expat/lib/iasciitab.h4
-rw-r--r--contrib/expat/lib/internal.h64
-rw-r--r--contrib/expat/lib/latin1tab.h4
-rw-r--r--contrib/expat/lib/loadlibrary.c143
-rw-r--r--contrib/expat/lib/nametab.h4
-rw-r--r--contrib/expat/lib/siphash.h23
-rw-r--r--contrib/expat/lib/utf8tab.h4
-rw-r--r--contrib/expat/lib/xmlparse.c2291
-rw-r--r--contrib/expat/lib/xmlrole.c20
-rw-r--r--contrib/expat/lib/xmlrole.h9
-rw-r--r--contrib/expat/lib/xmltok.c82
-rw-r--r--contrib/expat/lib/xmltok.h12
-rw-r--r--contrib/expat/lib/xmltok_impl.c45
-rw-r--r--contrib/expat/lib/xmltok_impl.h5
-rw-r--r--contrib/expat/lib/xmltok_ns.c8
-rw-r--r--contrib/expat/run.sh.in41
-rwxr-xr-xcontrib/expat/test-driver-wrapper.sh3
-rw-r--r--contrib/expat/tests/Makefile.am62
-rw-r--r--contrib/expat/tests/Makefile.in300
-rw-r--r--contrib/expat/tests/acc_tests.c396
-rw-r--r--contrib/expat/tests/acc_tests.h56
-rw-r--r--contrib/expat/tests/acc_tests_cxx.cpp (renamed from contrib/expat/xmlwf/xmlurl.h)19
-rw-r--r--contrib/expat/tests/alloc_tests.c2127
-rw-r--r--contrib/expat/tests/alloc_tests.h56
-rw-r--r--contrib/expat/tests/alloc_tests_cxx.cpp32
-rw-r--r--contrib/expat/tests/basic_tests.c6076
-rw-r--r--contrib/expat/tests/basic_tests.h56
-rw-r--r--contrib/expat/tests/basic_tests_cxx.cpp32
-rw-r--r--contrib/expat/tests/benchmark/Makefile.am5
-rw-r--r--contrib/expat/tests/benchmark/Makefile.in45
-rw-r--r--contrib/expat/tests/benchmark/benchmark.c18
-rw-r--r--contrib/expat/tests/benchmark/benchmark.sln25
-rw-r--r--contrib/expat/tests/chardata.c22
-rw-r--r--contrib/expat/tests/chardata.h5
-rw-r--r--contrib/expat/tests/chardata_cxx.cpp32
-rw-r--r--contrib/expat/tests/common.c325
-rw-r--r--contrib/expat/tests/common.h162
-rw-r--r--contrib/expat/tests/common_cxx.cpp32
-rw-r--r--contrib/expat/tests/dummy.c261
-rw-r--r--contrib/expat/tests/dummy.h150
-rw-r--r--contrib/expat/tests/dummy_cxx.cpp32
-rw-r--r--contrib/expat/tests/handlers.c1932
-rw-r--r--contrib/expat/tests/handlers.h595
-rw-r--r--contrib/expat/tests/handlers_cxx.cpp32
-rw-r--r--contrib/expat/tests/memcheck.c21
-rw-r--r--contrib/expat/tests/memcheck.h4
-rw-r--r--contrib/expat/tests/memcheck_cxx.cpp32
-rw-r--r--contrib/expat/tests/minicheck.c80
-rw-r--r--contrib/expat/tests/minicheck.h82
-rw-r--r--contrib/expat/tests/minicheck_cxx.cpp32
-rw-r--r--contrib/expat/tests/misc_tests.c523
-rw-r--r--contrib/expat/tests/misc_tests.h56
-rw-r--r--contrib/expat/tests/misc_tests_cxx.cpp32
-rw-r--r--contrib/expat/tests/ns_tests.c754
-rw-r--r--contrib/expat/tests/ns_tests.h56
-rw-r--r--contrib/expat/tests/ns_tests_cxx.cpp32
-rw-r--r--contrib/expat/tests/nsalloc_tests.c1537
-rw-r--r--contrib/expat/tests/nsalloc_tests.h56
-rw-r--r--contrib/expat/tests/nsalloc_tests_cxx.cpp32
-rw-r--r--contrib/expat/tests/runtests.c11567
-rw-r--r--contrib/expat/tests/runtests.sln24
-rw-r--r--contrib/expat/tests/runtests_cxx.cpp (renamed from contrib/expat/tests/runtestspp.cpp)4
-rw-r--r--contrib/expat/tests/structdata.c41
-rw-r--r--contrib/expat/tests/structdata.h3
-rw-r--r--contrib/expat/tests/structdata_cxx.cpp32
-rwxr-xr-xcontrib/expat/tests/udiffer.py3
-rwxr-xr-xcontrib/expat/tests/xmltest.sh43
-rw-r--r--contrib/expat/xmlwf/Makefile.am7
-rw-r--r--contrib/expat/xmlwf/Makefile.in48
-rw-r--r--contrib/expat/xmlwf/codepage.c31
-rw-r--r--contrib/expat/xmlwf/codepage.h4
-rw-r--r--contrib/expat/xmlwf/ct.c3
-rw-r--r--contrib/expat/xmlwf/filemap.h4
-rw-r--r--contrib/expat/xmlwf/readfilemap.c28
-rw-r--r--contrib/expat/xmlwf/unixfilemap.c6
-rw-r--r--contrib/expat/xmlwf/win32filemap.c7
-rw-r--r--contrib/expat/xmlwf/xmlfile.c27
-rw-r--r--contrib/expat/xmlwf/xmlfile.h7
-rw-r--r--contrib/expat/xmlwf/xmlmime.c4
-rw-r--r--contrib/expat/xmlwf/xmlmime.h3
-rw-r--r--contrib/expat/xmlwf/xmltchar.h7
-rw-r--r--contrib/expat/xmlwf/xmlwf.c297
-rwxr-xr-xcontrib/expat/xmlwf/xmlwf_helpgen.py45
-rwxr-xr-xcontrib/expat/xmlwf/xmlwf_helpgen.sh5
-rw-r--r--contrib/expat/xmlwf/xmlwin32url.cxx427
115 files changed, 21517 insertions, 13526 deletions
diff --git a/contrib/expat/COPYING b/contrib/expat/COPYING
index 8d288f0f28fd..ce9e5939291e 100644
--- a/contrib/expat/COPYING
+++ b/contrib/expat/COPYING
@@ -1,5 +1,5 @@
Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
-Copyright (c) 2001-2017 Expat maintainers
+Copyright (c) 2001-2022 Expat maintainers
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/contrib/expat/Changes b/contrib/expat/Changes
index 340947118a3f..a7d4caf9ac81 100644
--- a/contrib/expat/Changes
+++ b/contrib/expat/Changes
@@ -2,7 +2,643 @@ NOTE: We are looking for help with a few things:
https://github.com/libexpat/libexpat/labels/help%20wanted
If you can help, please get in touch. Thanks!
-Release 2.2.9 Wed Septemper 25 2019
+Release 2.6.0 Tue February 6 2024
+ Security fixes:
+ #789 #814 CVE-2023-52425 -- Fix quadratic runtime issues with big tokens
+ that can cause denial of service, in partial where
+ dealing with compressed XML input. Applications
+ that parsed a document in one go -- a single call to
+ functions XML_Parse or XML_ParseBuffer -- were not affected.
+ The smaller the chunks/buffers you use for parsing
+ previously, the bigger the problem prior to the fix.
+ Backporters should be careful to no omit parts of
+ pull request #789 and to include earlier pull request #771,
+ in order to not break the fix.
+ #777 CVE-2023-52426 -- Fix billion laughs attacks for users
+ compiling *without* XML_DTD defined (which is not common).
+ Users with XML_DTD defined have been protected since
+ Expat >=2.4.0 (and that was CVE-2013-0340 back then).
+
+ Bug fixes:
+ #753 Fix parse-size-dependent "invalid token" error for
+ external entities that start with a byte order mark
+ #780 Fix NULL pointer dereference in setContext via
+ XML_ExternalEntityParserCreate for compilation with
+ XML_DTD undefined
+ #812 #813 Protect against closing entities out of order
+
+ Other changes:
+ #723 Improve support for arc4random/arc4random_buf
+ #771 #788 Improve buffer growth in XML_GetBuffer and XML_Parse
+ #761 #770 xmlwf: Support --help and --version
+ #759 #770 xmlwf: Support custom buffer size for XML_GetBuffer and read
+ #744 xmlwf: Improve language and URL clickability in help output
+ #673 examples: Add new example "element_declarations.c"
+ #764 Be stricter about macro XML_CONTEXT_BYTES at build time
+ #765 Make inclusion to expat_config.h consistent
+ #726 #727 Autotools: configure.ac: Support --disable-maintainer-mode
+ #678 #705 ..
+ #706 #733 #792 Autotools: Sync CMake templates with CMake 3.26
+ #795 Autotools: Make installation of shipped man page doc/xmlwf.1
+ independent of docbook2man availability
+ #815 Autotools|CMake: Add missing -DXML_STATIC to pkg-config file
+ section "Cflags.private" in order to fix compilation
+ against static libexpat using pkg-config on Windows
+ #724 #751 Autotools|CMake: Require a C99 compiler
+ (a de-facto requirement already since Expat 2.2.2 of 2017)
+ #793 Autotools|CMake: Fix PACKAGE_BUGREPORT variable
+ #750 #786 Autotools|CMake: Make test suite require a C++11 compiler
+ #749 CMake: Require CMake >=3.5.0
+ #672 CMake: Lowercase off_t and size_t to help a bug in Meson
+ #746 CMake: Sort xmlwf sources alphabetically
+ #785 CMake|Windows: Fix generation of DLL file version info
+ #790 CMake: Build tests/benchmark/benchmark.c as well for
+ a build with -DEXPAT_BUILD_TESTS=ON
+ #745 #757 docs: Document the importance of isFinal + adjust tests
+ accordingly
+ #736 docs: Improve use of "NULL" and "null"
+ #713 docs: Be specific about version of XML (XML 1.0r4)
+ and version of C (C99); (XML 1.0r5 will need a sponsor.)
+ #762 docs: reference.html: Promote function XML_ParseBuffer more
+ #779 docs: reference.html: Add HTML anchors to XML_* macros
+ #760 docs: reference.html: Upgrade to OK.css 1.2.0
+ #763 #739 docs: Fix typos
+ #696 docs|CI: Use HTTPS URLs instead of HTTP at various places
+ #669 #670 ..
+ #692 #703 ..
+ #733 #772 Address compiler warnings
+ #798 #800 Address clang-tidy warnings
+ #775 #776 Version info bumped from 9:10:8 (libexpat*.so.1.8.10)
+ to 10:0:9 (libexpat*.so.1.9.0); see https://verbump.de/
+ for what these numbers do
+
+ Infrastructure:
+ #700 #701 docs: Document security policy in file SECURITY.md
+ #766 docs: Improve parse buffer variables in-code documentation
+ #674 #738 ..
+ #740 #747 ..
+ #748 #781 #782 Refactor coverage and conformance tests
+ #714 #716 Refactor debug level variables to unsigned long
+ #671 Improve handling of empty environment variable value
+ in function getDebugLevel (without visible user effect)
+ #755 #774 ..
+ #758 #783 ..
+ #784 #787 tests: Improve test coverage with regard to parse chunk size
+ #660 #797 #801 Fuzzing: Improve fuzzing coverage
+ #367 #799 Fuzzing|CI: Start running OSS-Fuzz fuzzing regression tests
+ #698 #721 CI: Resolve some Travis CI leftovers
+ #669 CI: Be robust towards absence of Git tags
+ #693 #694 CI: Set permissions to "contents: read" for security
+ #709 CI: Pin all GitHub Actions to specific commits for security
+ #739 CI: Reject spelling errors using codespell
+ #798 CI: Enforce clang-tidy clean code
+ #773 #808 ..
+ #809 #810 CI: Upgrade Clang from 15 to 18
+ #796 CI: Start using Clang's Control Flow Integrity sanitizer
+ #675 #720 #722 CI: Adapt to breaking changes in GitHub Actions Ubuntu images
+ #689 CI: Adapt to breaking changes in Clang/LLVM Debian packaging
+ #763 CI: Adapt to breaking changes in codespell
+ #803 CI: Adapt to breaking changes in Cppcheck
+
+ Special thanks to:
+ Ivan Galkin
+ Joyce Brum
+ Philippe Antoine
+ Rhodri James
+ Snild Dolkow
+ spookyahell
+ Steven Garske
+ and
+ Clang AddressSanitizer
+ Clang UndefinedBehaviorSanitizer
+ codespell
+ GCC Farm Project
+ OSS-Fuzz
+ Sony Mobile
+
+Release 2.5.0 Tue October 25 2022
+ Security fixes:
+ #616 #649 #650 CVE-2022-43680 -- Fix heap use-after-free after overeager
+ destruction of a shared DTD in function
+ XML_ExternalEntityParserCreate in out-of-memory situations.
+ Expected impact is denial of service or potentially
+ arbitrary code execution.
+
+ Bug fixes:
+ #612 #645 Fix corruption from undefined entities
+ #613 #654 Fix case when parsing was suspended while processing nested
+ entities
+ #616 #652 #653 Stop leaking opening tag bindings after a closing tag
+ mismatch error where a parser is reset through
+ XML_ParserReset and then reused to parse
+ #656 CMake: Fix generation of pkg-config file
+ #658 MinGW|CMake: Fix static library name
+
+ Other changes:
+ #663 Protect header expat_config.h from multiple inclusion
+ #666 examples: Make use of XML_GetBuffer and be more
+ consistent across examples
+ #648 Address compiler warnings
+ #667 #668 Version info bumped from 9:9:8 to 9:10:8;
+ see https://verbump.de/ for what these numbers do
+
+ Special thanks to:
+ Jann Horn
+ Mark Brand
+ Osyotr
+ Rhodri James
+ and
+ Google Project Zero
+
+Release 2.4.9 Tue September 20 2022
+ Security fixes:
+ #629 #640 CVE-2022-40674 -- Heap use-after-free vulnerability in
+ function doContent. Expected impact is denial of service
+ or potentially arbitrary code execution.
+
+ Bug fixes:
+ #634 MinGW: Fix mis-compilation for -D__USE_MINGW_ANSI_STDIO=0
+ #614 docs: Fix documentation on effect of switch XML_DTD on
+ symbol visibility in doc/reference.html
+
+ Other changes:
+ #638 MinGW: Make fix-xmltest-log.sh drop more Wine bug output
+ #596 #625 Autotools: Sync CMake templates with CMake 3.22
+ #608 CMake: Migrate from use of CMAKE_*_POSTFIX to
+ dedicated variables EXPAT_*_POSTFIX to stop affecting
+ other projects
+ #597 #599 Windows|CMake: Add missing -DXML_STATIC to test runners
+ and fuzzers
+ #512 #621 Windows|CMake: Render .def file from a template to fix
+ linking with -DEXPAT_DTD=OFF and/or -DEXPAT_ATTR_INFO=ON
+ #611 #621 MinGW|CMake: Apply MSVC .def file when linking
+ #622 #624 MinGW|CMake: Sync library name with GNU Autotools,
+ i.e. produce libexpat-1.dll rather than libexpat.dll
+ by default. Filename libexpat.dll.a is unaffected.
+ #632 MinGW|CMake: Set missing variable CMAKE_RC_COMPILER in
+ toolchain file "cmake/mingw-toolchain.cmake" to avoid
+ error "windres: Command not found" on e.g. Ubuntu 20.04
+ #597 #627 CMake: Unify inconsistent use of set() and option() in
+ context of public build time options to take need for
+ set(.. FORCE) in projects using Expat by means of
+ add_subdirectory(..) off Expat's users' shoulders
+ #626 #641 Stop exporting API symbols when building a static library
+ #644 Resolve use of deprecated "fgrep" by "grep -F"
+ #620 CMake: Make documentation on variables a bit more consistent
+ #636 CMake: Drop leading whitespace from a #cmakedefine line in
+ file expat_config.h.cmake
+ #594 xmlwf: Fix harmless variable mix-up in function nsattcmp
+ #592 #593 #610 Address Cppcheck warnings
+ #643 Address Clang 15 compiler warnings
+ #642 #644 Version info bumped from 9:8:8 to 9:9:8;
+ see https://verbump.de/ for what these numbers do
+
+ Infrastructure:
+ #597 #598 CI: Windows: Start covering MSVC 2022
+ #619 CI: macOS: Migrate off deprecated macOS 10.15
+ #632 CI: Linux: Make migration off deprecated Ubuntu 18.04 work
+ #643 CI: Upgrade Clang from 14 to 15
+ #637 apply-clang-format.sh: Add support for BSD find
+ #633 coverage.sh: Exclude MinGW headers
+ #635 coverage.sh: Fix name collision for -funsigned-char
+
+ Special thanks to:
+ David Faure
+ Felix Wilhelm
+ Frank Bergmann
+ Rhodri James
+ Rosen Penev
+ Thijs Schreijer
+ Vincent Torri
+ and
+ Google Project Zero
+
+Release 2.4.8 Mon March 28 2022
+ Other changes:
+ #587 pkg-config: Move "-lm" to section "Libs.private"
+ #587 CMake|MSVC: Fix pkg-config section "Libs"
+ #55 #582 CMake|macOS: Start using linker arguments
+ "-compatibility_version <version>" and
+ "-current_version <version>" in a way compatible with
+ GNU Libtool
+ #590 #591 Version info bumped from 9:7:8 to 9:8:8;
+ see https://verbump.de/ for what these numbers do
+
+ Infrastructure:
+ #589 CI: Upgrade Clang from 13 to 14
+
+ Special thanks to:
+ evpobr
+ Kai Pastor
+ Sam James
+
+Release 2.4.7 Fri March 4 2022
+ Bug fixes:
+ #572 #577 Relax fix to CVE-2022-25236 (introduced with release 2.4.5)
+ with regard to all valid URI characters (RFC 3986),
+ i.e. the following set (excluding whitespace):
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
+ 0123456789 % -._~ :/?#[]@ !$&'()*+,;=
+
+ Other changes:
+ #555 #570 #581 CMake|Windows: Store Expat version in the DLL
+ #577 Document consequences of namespace separator choices not just
+ in doc/reference.html but also in header <expat.h>
+ #577 Document Expat's lack of validation of namespace URIs against
+ RFC 3986, and that the XML 1.0r4 specification doesn't
+ require Expat to validate namespace URIs, and that Expat
+ may do more in that regard in future releases.
+ If you find need for strict RFC 3986 URI validation on
+ application level today, https://uriparser.github.io/ may
+ be of interest.
+ #579 Fix documentation of XML_EndDoctypeDeclHandler in <expat.h>
+ #575 Document that a call to XML_FreeContentModel can be done at
+ a later time from outside the element declaration handler
+ #574 Make hardcoded namespace URIs easier to find in code
+ #573 Update documentation on use of XML_POOR_ENTOPY on Solaris
+ #569 #571 tests: Resolve use of macros NAN and INFINITY for GNU G++
+ 4.8.2 on Solaris.
+ #578 #580 Version info bumped from 9:6:8 to 9:7:8;
+ see https://verbump.de/ for what these numbers do
+
+ Special thanks to:
+ Jeffrey Walton
+ Johnny Jazeix
+ Thijs Schreijer
+
+Release 2.4.6 Sun February 20 2022
+ Bug fixes:
+ #566 Fix a regression introduced by the fix for CVE-2022-25313
+ in release 2.4.5 that affects applications that (1)
+ call function XML_SetElementDeclHandler and (2) are
+ parsing XML that contains nested element declarations
+ (e.g. "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>").
+
+ Other changes:
+ #567 #568 Version info bumped from 9:5:8 to 9:6:8;
+ see https://verbump.de/ for what these numbers do
+
+ Special thanks to:
+ Matt Sergeant
+ Samanta Navarro
+ Sergei Trofimovich
+ and
+ NixOS
+ Perl XML::Parser
+
+Release 2.4.5 Fri February 18 2022
+ Security fixes:
+ #562 CVE-2022-25235 -- Passing malformed 2- and 3-byte UTF-8
+ sequences (e.g. from start tag names) to the XML
+ processing application on top of Expat can cause
+ arbitrary damage (e.g. code execution) depending
+ on how invalid UTF-8 is handled inside the XML
+ processor; validation was not their job but Expat's.
+ Exploits with code execution are known to exist.
+ #561 CVE-2022-25236 -- Passing (one or more) namespace separator
+ characters in "xmlns[:prefix]" attribute values
+ made Expat send malformed tag names to the XML
+ processor on top of Expat which can cause
+ arbitrary damage (e.g. code execution) depending
+ on such unexpectable cases are handled inside the XML
+ processor; validation was not their job but Expat's.
+ Exploits with code execution are known to exist.
+ #558 CVE-2022-25313 -- Fix stack exhaustion in doctype parsing
+ that could be triggered by e.g. a 2 megabytes
+ file with a large number of opening braces.
+ Expected impact is denial of service or potentially
+ arbitrary code execution.
+ #560 CVE-2022-25314 -- Fix integer overflow in function copyString;
+ only affects the encoding name parameter at parser creation
+ time which is often hardcoded (rather than user input),
+ takes a value in the gigabytes to trigger, and a 64-bit
+ machine. Expected impact is denial of service.
+ #559 CVE-2022-25315 -- Fix integer overflow in function storeRawNames;
+ needs input in the gigabytes and a 64-bit machine.
+ Expected impact is denial of service or potentially
+ arbitrary code execution.
+
+ Other changes:
+ #557 #564 Version info bumped from 9:4:8 to 9:5:8;
+ see https://verbump.de/ for what these numbers do
+
+ Special thanks to:
+ Ivan Fratric
+ Samanta Navarro
+ and
+ Google Project Zero
+ JetBrains
+
+Release 2.4.4 Sun January 30 2022
+ Security fixes:
+ #550 CVE-2022-23852 -- Fix signed integer overflow
+ (undefined behavior) in function XML_GetBuffer
+ (that is also called by function XML_Parse internally)
+ for when XML_CONTEXT_BYTES is defined to >0 (which is both
+ common and default).
+ Impact is denial of service or more.
+ #551 CVE-2022-23990 -- Fix unsigned integer overflow in function
+ doProlog triggered by large content in element type
+ declarations when there is an element declaration handler
+ present (from a prior call to XML_SetElementDeclHandler).
+ Impact is denial of service or more.
+
+ Bug fixes:
+ #544 #545 xmlwf: Fix a memory leak on output file opening error
+
+ Other changes:
+ #546 Autotools: Fix broken CMake support under Cygwin
+ #554 Windows: Add missing files to the installer to fix
+ compilation with CMake from installed sources
+ #552 #554 Version info bumped from 9:3:8 to 9:4:8;
+ see https://verbump.de/ for what these numbers do
+
+ Special thanks to:
+ Carlo Bramini
+ hwt0415
+ Roland Illig
+ Samanta Navarro
+ and
+ Clang LeakSan and the Clang team
+
+Release 2.4.3 Sun January 16 2022
+ Security fixes:
+ #531 #534 CVE-2021-45960 -- Fix issues with left shifts by >=29 places
+ resulting in
+ a) realloc acting as free
+ b) realloc allocating too few bytes
+ c) undefined behavior
+ depending on architecture and precise value
+ for XML documents with >=2^27+1 prefixed attributes
+ on a single XML tag a la
+ "<r xmlns:a='[..]' a:a123='[..]' [..] />"
+ where XML_ParserCreateNS is used to create the parser
+ (which needs argument "-n" when running xmlwf).
+ Impact is denial of service, or more.
+ #532 #538 CVE-2021-46143 (ZDI-CAN-16157) -- Fix integer overflow
+ on variable m_groupSize in function doProlog leading
+ to realloc acting as free.
+ Impact is denial of service or more.
+ #539 CVE-2022-22822 to CVE-2022-22827 -- Prevent integer overflows
+ near memory allocation at multiple places. Mitre assigned
+ a dedicated CVE for each involved internal C function:
+ - CVE-2022-22822 for function addBinding
+ - CVE-2022-22823 for function build_model
+ - CVE-2022-22824 for function defineAttribute
+ - CVE-2022-22825 for function lookup
+ - CVE-2022-22826 for function nextScaffoldPart
+ - CVE-2022-22827 for function storeAtts
+ Impact is denial of service or more.
+
+ Other changes:
+ #535 CMake: Make call to file(GENERATE [..]) work for CMake <3.19
+ #541 Autotools|CMake: MinGW: Make run.sh(.in) work for Cygwin
+ and MSYS2 by not going through Wine on these platforms
+ #527 #528 Address compiler warnings
+ #533 #543 Version info bumped from 9:2:8 to 9:3:8;
+ see https://verbump.de/ for what these numbers do
+
+ Infrastructure:
+ #536 CI: Check for realistic minimum CMake version
+ #529 #539 CI: Cover compilation with -m32
+ #529 CI: Store coverage reports as artifacts for download
+ #528 CI: Upgrade Clang from 11 to 13
+
+ Special thanks to:
+ An anonymous whitehat
+ Christopher Degawa
+ J. Peter Mugaas
+ Tyson Smith
+ and
+ GCC Farm Project
+ Trend Micro Zero Day Initiative
+
+Release 2.4.2 Sun December 19 2021
+ Other changes:
+ #509 #510 Link againgst libm for function "isnan"
+ #513 #514 Include expat_config.h as early as possible
+ #498 Autotools: Include files with release archives:
+ - buildconf.sh
+ - fuzz/*.c
+ #507 #519 Autotools: Sync CMake templates with CMake 3.20
+ #495 #524 CMake: MinGW: Fix pkg-config section "Libs" for
+ - non-release build types (e.g. -DCMAKE_BUILD_TYPE=Debug)
+ - multi-config CMake generators (e.g. Ninja Multi-Config)
+ #502 #503 docs: Document that function XML_GetBuffer may return NULL
+ when asking for a buffer of 0 (zero) bytes size
+ #522 #523 docs: Fix return value docs for both
+ XML_SetBillionLaughsAttackProtection* functions
+ #525 #526 Version info bumped from 9:1:8 to 9:2:8;
+ see https://verbump.de/ for what these numbers do
+
+ Special thanks to:
+ Donghee Na
+ Joergen Ibsen
+ Kai Pastor
+
+Release 2.4.1 Sun May 23 2021
+ Bug fixes:
+ #488 #490 Autotools: Fix installed header expat_config.h for multilib
+ systems; regression introduced in 2.4.0 by pull request #486
+
+ Other changes:
+ #491 #492 Version info bumped from 9:0:8 to 9:1:8;
+ see https://verbump.de/ for what these numbers do
+
+ Special thanks to:
+ Gentoo's QA check "multilib_check_headers"
+
+Release 2.4.0 Sun May 23 2021
+ Security fixes:
+ #34 #466 #484 CVE-2013-0340/CWE-776 -- Protect against billion laughs attacks
+ (denial-of-service; flavors targeting CPU time or RAM or both,
+ leveraging general entities or parameter entities or both)
+ by tracking and limiting the input amplification factor
+ (<amplification> := (<direct> + <indirect>) / <direct>).
+ By conservative default, amplification up to a factor of 100.0
+ is tolerated and rejection only starts after 8 MiB of output bytes
+ (=<direct> + <indirect>) have been processed.
+ The fix adds the following to the API:
+ - A new error code XML_ERROR_AMPLIFICATION_LIMIT_BREACH to
+ signals this specific condition.
+ - Two new API functions ..
+ - XML_SetBillionLaughsAttackProtectionMaximumAmplification and
+ - XML_SetBillionLaughsAttackProtectionActivationThreshold
+ .. to further tighten billion laughs protection parameters
+ when desired. Please see file "doc/reference.html" for details.
+ If you ever need to increase the defaults for non-attack XML
+ payload, please file a bug report with libexpat.
+ - Two new XML_FEATURE_* constants ..
+ - that can be queried using the XML_GetFeatureList function, and
+ - that are shown in "xmlwf -v" output.
+ - Two new environment variable switches ..
+ - EXPAT_ACCOUNTING_DEBUG=(0|1|2|3) and
+ - EXPAT_ENTITY_DEBUG=(0|1)
+ .. for runtime debugging of accounting and entity processing.
+ Specific behavior of these values may change in the future.
+ - Two new command line arguments "-a FACTOR" and "-b BYTES"
+ for xmlwf to further tighten billion laughs protection
+ parameters when desired.
+ If you ever need to increase the defaults for non-attack XML
+ payload, please file a bug report with libexpat.
+
+ Bug fixes:
+ #332 #470 For (non-default) compilation with -DEXPAT_MIN_SIZE=ON (CMake)
+ or CPPFLAGS=-DXML_MIN_SIZE (GNU Autotools): Fix segfault
+ for UTF-16 payloads containing CDATA sections.
+ #485 #486 Autotools: Fix generated CMake files for non-64bit and
+ non-Linux platforms (e.g. macOS and MinGW in particular)
+ that were introduced with release 2.3.0
+
+ Other changes:
+ #468 #469 xmlwf: Improve help output and the xmlwf man page
+ #463 xmlwf: Improve maintainability through some refactoring
+ #477 xmlwf: Fix man page DocBook validity
+ #456 Autotools: Sync CMake templates with CMake 3.18
+ #458 #459 CMake: Support absolute paths for both CMAKE_INSTALL_LIBDIR
+ and CMAKE_INSTALL_INCLUDEDIR
+ #471 #481 CMake: Add support for standard variable BUILD_SHARED_LIBS
+ #457 Unexpose symbol _INTERNAL_trim_to_complete_utf8_characters
+ #467 Resolve macro HAVE_EXPAT_CONFIG_H
+ #472 Delete unused legacy helper file "conftools/PrintPath"
+ #473 #483 Improve attribution
+ #464 #465 #477 doc/reference.html: Fix XHTML validity
+ #475 #478 doc/reference.html: Replace the 90s look by OK.css
+ #479 Version info bumped from 8:0:7 to 9:0:8
+ due to addition of new symbols and error codes;
+ see https://verbump.de/ for what these numbers do
+
+ Infrastructure:
+ #456 CI: Enable periodic runs
+ #457 CI: Start covering the list of exported symbols
+ #474 CI: Isolate coverage task
+ #476 #482 CI: Adapt to breaking changes in image "ubuntu-18.04"
+ #477 CI: Cover well-formedness and DocBook/XHTML validity
+ of doc/reference.html and doc/xmlwf.xml
+
+ Special thanks to:
+ Dimitry Andric
+ Eero Helenius
+ Nick Wellnhofer
+ Rhodri James
+ Tomas Korbar
+ Yury Gribov
+ and
+ Clang LeakSan
+ JetBrains
+ OSS-Fuzz
+
+Release 2.3.0 Thu March 25 2021
+ Bug fixes:
+ #438 When calling XML_ParseBuffer without a prior successful call to
+ XML_GetBuffer as a user, no longer trigger undefined behavior
+ (by adding an integer to a NULL pointer) but rather return
+ XML_STATUS_ERROR and set the error code to (new) code
+ XML_ERROR_NO_BUFFER. Found by UBSan (UndefinedBehaviorSanitizer)
+ of Clang 11 (but not Clang 9).
+ #444 xmlwf: Exit status 2 was used for both:
+ - malformed input files (documented) and
+ - invalid command-line arguments (undocumented).
+ The case of invalid command-line arguments now
+ has its own exit status 4, resolving the ambiguity.
+
+ Other changes:
+ #439 xmlwf: Add argument -k to allow continuing after
+ non-fatal errors
+ #439 xmlwf: Add section about exit status to the -h help output
+ #422 #426 #447 Windows: Drop support for Visual Studio <=14.0/2015
+ #434 Windows: CMake: Detect unsupported Visual Studio at
+ configure time (rather than at compile time)
+ #382 #428 testrunner: Make verbose mode (argument "-v") report
+ about passed tests, and make default mode report about
+ failures, as well.
+ #442 CMake: Call "enable_language(CXX)" prior to tinkering
+ with CMAKE_CXX_* variables
+ #448 Document use of libexpat from a CMake-based project
+ #451 Autotools: Install CMake files as generated by CMake 3.19.6
+ so that users with "find_package(expat [..] CONFIG [..])"
+ are served on distributions that are *not* using the CMake
+ build system inside for libexpat packaging
+ #436 #437 Autotools: Drop obsolescent macro AC_HEADER_STDC
+ #450 #452 Autotools: Resolve use of obsolete macro AC_CONFIG_HEADER
+ #441 Address compiler warnings
+ #443 Version info bumped from 7:12:6 to 8:0:7
+ due to addition of error code XML_ERROR_NO_BUFFER
+ (see https://verbump.de/ for what these numbers do)
+
+ Infrastructure:
+ #435 #446 Replace Travis CI by GitHub Actions
+
+ Special thanks to:
+ Alexander Richardson
+ Oleksandr Popovych
+ Thomas Beutlich
+ Tim Bray
+ and
+ Clang LeakSan, Clang 11 UBSan and the Clang team
+
+Release 2.2.10 Sat October 3 2020
+ Bug fixes:
+ #390 #395 #398 Fix undefined behavior during parsing caused by
+ pointer arithmetic with NULL pointers
+ #404 #405 Fix reading uninitialized variable during parsing
+ #406 xmlwf: Add missing check for malloc NULL return
+
+ Other changes:
+ #396 Windows: Drop support for Visual Studio <=8.0/2005
+ #409 Windows: Add missing file "Changes" to the installer
+ to fix compilation with CMake from installed sources
+ #403 xmlwf: Document exit codes in xmlwf manpage and
+ exit with code 3 (rather than code 1) for output errors
+ when used with "-d DIRECTORY"
+ #356 #359 MinGW: Provide declaration of rand_s for mingwrt <5.3.0
+ #383 #392 Autotools: Use -Werror while configure tests the compiler
+ for supported compile flags to avoid false positives
+ #383 #393 #394 Autotools: Improve handling of user (C|CPP|CXX|LD)FLAGS,
+ e.g. ensure that they have the last word over flags added
+ while running ./configure
+ #360 CMake: Create libexpatw.{dll,so} and expatw.pc (with emphasis
+ on suffix "w") with -DEXPAT_CHAR_TYPE=(ushort|wchar_t)
+ #360 CMake: Detect and deny unsupported build combinations
+ involving -DEXPAT_CHAR_TYPE=(ushort|wchar_t)
+ #360 CMake: Install pre-compiled shipped xmlwf.1 manpage in case
+ of -DEXPAT_BUILD_DOCS=OFF
+ #375 #380 #419 CMake: Fix use of Expat by means of add_subdirectory
+ #407 #408 CMake: Keep expat target name constant at "expat"
+ (i.e. refrain from using the target name to control
+ build artifact filenames)
+ #385 CMake: Fix compilation with -DEXPAT_SHARED_LIBS=OFF for
+ Windows
+ CMake: Expose man page compilation as target "xmlwf-manpage"
+ #413 #414 CMake: Introduce option EXPAT_BUILD_PKGCONFIG
+ to control generation of pkg-config file "expat.pc"
+ #424 CMake: Add minimalistic support for building binary packages
+ with CMake target "package"; based on CPack
+ #366 CMake: Add option -DEXPAT_OSSFUZZ_BUILD=(ON|OFF) with
+ default OFF to build fuzzer code against OSS-Fuzz and
+ related environment variable LIB_FUZZING_ENGINE
+ #354 Fix testsuite for -DEXPAT_DTD=OFF and -DEXPAT_NS=OFF, each
+ #354 #355 ..
+ #356 #412 Address compiler warnings
+ #368 #369 Address pngcheck warnings with doc/*.png images
+ #425 Version info bumped from 7:11:6 to 7:12:6
+
+ Special thanks to:
+ asavah
+ Ben Wagner
+ Bhargava Shastry
+ Frank Landgraf
+ Jeffrey Walton
+ Joe Orton
+ Kleber TarcĂ­sio
+ Ma Lin
+ Maciej Sroczyński
+ Mohammed Khajapasha
+ Vadim Zeitlin
+ and
+ Cppcheck 2.0 and the Cppcheck team
+
+Release 2.2.9 Wed September 25 2019
Other changes:
examples: Drop executable bits from elements.c
#349 Windows: Change the name of the Windows DLLs from expat*.dll
@@ -17,7 +653,7 @@ Release 2.2.9 Wed Septemper 25 2019
Special thanks to:
Ben Wagner
-Release 2.2.8 Fri Septemper 13 2019
+Release 2.2.8 Fri September 13 2019
Security fixes:
#317 #318 CVE-2019-15903 -- Fix heap overflow triggered by
XML_GetCurrentLineNumber (or XML_GetCurrentColumnNumber),
@@ -115,10 +751,10 @@ Release 2.2.8 Fri Septemper 13 2019
Special thanks to:
David Loffredo
Joonun Jang
- Khajapasha Mohammed
Kishore Kunche
Marco Maggi
Mitch Phillips
+ Mohammed Khajapasha
Rolf Ade
xantares
Zhongyuan Zhou
diff --git a/contrib/expat/Makefile.am b/contrib/expat/Makefile.am
index 5e1d37dd1a83..9c2259d23e63 100644
--- a/contrib/expat/Makefile.am
+++ b/contrib/expat/Makefile.am
@@ -6,7 +6,10 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2018 KangLin <kl222@126.com>
+# Copyright (c) 2022 Johnny Jazeix <jazeix@gmail.com>
+# Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -53,20 +56,36 @@ pkgconfig_DATA = expat.pc
pkgconfigdir = $(libdir)/pkgconfig
+dist_cmake_DATA = \
+ cmake/autotools/expat.cmake
+
+nodist_cmake_DATA = \
+ cmake/autotools/expat-config-version.cmake \
+ cmake/autotools/expat-noconfig.cmake \
+ cmake/expat-config.cmake
+
+cmakedir = $(libdir)/cmake/expat-@PACKAGE_VERSION@
+
+
_EXTRA_DIST_CMAKE = \
- cmake/expat-config.cmake.in \
+ cmake/autotools/expat-noconfig__linux.cmake.in \
+ cmake/autotools/expat-noconfig__macos.cmake.in \
+ cmake/autotools/expat-noconfig__windows.cmake.in \
+ cmake/autotools/expat-package-init.cmake \
cmake/mingw-toolchain.cmake \
\
CMakeLists.txt \
CMake.README \
ConfigureChecks.cmake \
+ expat.pc.cmake \
expat_config.h.cmake
_EXTRA_DIST_WINDOWS = \
win32/build_expat_iss.bat \
win32/expat.iss \
win32/MANIFEST.txt \
- win32/README.txt
+ win32/README.txt \
+ win32/version.rc.cmake
EXTRA_DIST = \
$(_EXTRA_DIST_CMAKE) \
@@ -74,11 +93,14 @@ EXTRA_DIST = \
\
conftools/expat.m4 \
conftools/get-version.sh \
- conftools/PrintPath \
+ \
+ fuzz/xml_parsebuffer_fuzzer.c \
+ fuzz/xml_parse_fuzzer.c \
\
xmlwf/xmlwf_helpgen.py \
xmlwf/xmlwf_helpgen.sh \
\
+ buildconf.sh \
Changes \
README.md \
\
@@ -110,6 +132,11 @@ buildlib:
run-benchmark:
$(MAKE) -C tests/benchmark
./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/recset.xml 65535 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_attr.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_cdata.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_comment.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_tag.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_text.xml 4096 3
.PHONY: download-xmlts-zip
download-xmlts-zip:
diff --git a/contrib/expat/Makefile.in b/contrib/expat/Makefile.in
index 89bf68febc48..f505224f6fa8 100644
--- a/contrib/expat/Makefile.in
+++ b/contrib/expat/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,10 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2018 KangLin <kl222@126.com>
+# Copyright (c) 2022 Johnny Jazeix <jazeix@gmail.com>
+# Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -134,16 +137,20 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/conftools/ax-append-compile-flags.m4 \
$(top_srcdir)/conftools/ax-append-link-flags.m4 \
$(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx-11.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
- $(am__configure_deps) $(am__DIST_COMMON)
+ $(am__configure_deps) $(dist_cmake_DATA) $(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = expat_config.h
-CONFIG_CLEAN_FILES = expat.pc run.sh
+CONFIG_CLEAN_FILES = expat.pc cmake/expat-config.cmake \
+ cmake/autotools/expat-config-version.cmake \
+ cmake/autotools/expat-noconfig.cmake run.sh
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -199,8 +206,9 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
-am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
-DATA = $(pkgconfig_DATA)
+am__installdirs = "$(DESTDIR)$(cmakedir)" "$(DESTDIR)$(cmakedir)" \
+ "$(DESTDIR)$(pkgconfigdir)"
+DATA = $(dist_cmake_DATA) $(nodist_cmake_DATA) $(pkgconfig_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
@@ -209,8 +217,8 @@ am__recursive_targets = \
$(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
cscope distdir distdir-am dist dist-all distcheck
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
- $(LISP)expat_config.h.in
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+ expat_config.h.in
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
@@ -227,18 +235,17 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-CSCOPE = cscope
DIST_SUBDIRS = lib examples tests xmlwf doc
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/expat.pc.in \
$(srcdir)/expat_config.h.in $(srcdir)/run.sh.in \
+ $(top_srcdir)/cmake/autotools/expat-config-version.cmake.in \
+ $(top_srcdir)/cmake/expat-config.cmake.in \
$(top_srcdir)/conftools/ar-lib $(top_srcdir)/conftools/compile \
$(top_srcdir)/conftools/config.guess \
$(top_srcdir)/conftools/config.sub \
$(top_srcdir)/conftools/install-sh \
$(top_srcdir)/conftools/ltmain.sh \
- $(top_srcdir)/conftools/missing AUTHORS COPYING \
+ $(top_srcdir)/conftools/missing AUTHORS COPYING README.md \
conftools/ar-lib conftools/compile conftools/config.guess \
conftools/config.sub conftools/depcomp conftools/install-sh \
conftools/ltmain.sh conftools/missing
@@ -281,13 +288,19 @@ DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 $(distdir).tar.lz \
$(distdir).tar.xz
GZIP_ENV = --best
DIST_TARGETS = dist-lzip dist-xz dist-bzip2 dist-gzip
+# Exists only to be overridden by the user if desired.
+AM_DISTCHECK_DVI_TARGET = dvi
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
@@ -297,8 +310,10 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CPP = @CPP@
+CMAKE_SHARED_LIBRARY_PREFIX = @CMAKE_SHARED_LIBRARY_PREFIX@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -314,10 +329,20 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
+EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
+EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
+EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
+EXPAT_DTD = @EXPAT_DTD@
+EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
+EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
+EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FILEMAP = @FILEMAP@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -327,6 +352,8 @@ LD = @LD@
LDFLAGS = @LDFLAGS@
LIBAGE = @LIBAGE@
LIBCURRENT = @LIBCURRENT@
+LIBDIR_BASENAME = @LIBDIR_BASENAME@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBREVISION = @LIBREVISION@
LIBS = @LIBS@
@@ -335,6 +362,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -356,6 +384,9 @@ RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SO_MAJOR = @SO_MAJOR@
+SO_MINOR = @SO_MINOR@
+SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
@@ -366,6 +397,7 @@ ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_void_p = @ac_cv_sizeof_void_p@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -403,6 +435,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -423,20 +456,34 @@ LIBTOOLFLAGS = --verbose
SUBDIRS = lib $(am__append_1) $(am__append_2) $(am__append_3)
pkgconfig_DATA = expat.pc
pkgconfigdir = $(libdir)/pkgconfig
+dist_cmake_DATA = \
+ cmake/autotools/expat.cmake
+
+nodist_cmake_DATA = \
+ cmake/autotools/expat-config-version.cmake \
+ cmake/autotools/expat-noconfig.cmake \
+ cmake/expat-config.cmake
+
+cmakedir = $(libdir)/cmake/expat-@PACKAGE_VERSION@
_EXTRA_DIST_CMAKE = \
- cmake/expat-config.cmake.in \
+ cmake/autotools/expat-noconfig__linux.cmake.in \
+ cmake/autotools/expat-noconfig__macos.cmake.in \
+ cmake/autotools/expat-noconfig__windows.cmake.in \
+ cmake/autotools/expat-package-init.cmake \
cmake/mingw-toolchain.cmake \
\
CMakeLists.txt \
CMake.README \
ConfigureChecks.cmake \
+ expat.pc.cmake \
expat_config.h.cmake
_EXTRA_DIST_WINDOWS = \
win32/build_expat_iss.bat \
win32/expat.iss \
win32/MANIFEST.txt \
- win32/README.txt
+ win32/README.txt \
+ win32/version.rc.cmake
EXTRA_DIST = \
$(_EXTRA_DIST_CMAKE) \
@@ -444,11 +491,14 @@ EXTRA_DIST = \
\
conftools/expat.m4 \
conftools/get-version.sh \
- conftools/PrintPath \
+ \
+ fuzz/xml_parsebuffer_fuzzer.c \
+ fuzz/xml_parse_fuzzer.c \
\
xmlwf/xmlwf_helpgen.py \
xmlwf/xmlwf_helpgen.sh \
\
+ buildconf.sh \
Changes \
README.md \
\
@@ -461,7 +511,7 @@ all: expat_config.h
.SUFFIXES:
am--refresh: Makefile
@:
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -487,9 +537,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
-$(top_srcdir)/configure: $(am__configure_deps)
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
$(am__cd) $(srcdir) && $(AUTOCONF)
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
$(am__aclocal_m4_deps):
@@ -500,7 +550,7 @@ expat_config.h: stamp-h1
stamp-h1: $(srcdir)/expat_config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status expat_config.h
-$(srcdir)/expat_config.h.in: $(am__configure_deps)
+$(srcdir)/expat_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
rm -f stamp-h1
touch $@
@@ -509,6 +559,12 @@ distclean-hdr:
-rm -f expat_config.h stamp-h1
expat.pc: $(top_builddir)/config.status $(srcdir)/expat.pc.in
cd $(top_builddir) && $(SHELL) ./config.status $@
+cmake/expat-config.cmake: $(top_builddir)/config.status $(top_srcdir)/cmake/expat-config.cmake.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+cmake/autotools/expat-config-version.cmake: $(top_builddir)/config.status $(top_srcdir)/cmake/autotools/expat-config-version.cmake.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+cmake/autotools/expat-noconfig.cmake: $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $@
run.sh: $(top_builddir)/config.status $(srcdir)/run.sh.in
cd $(top_builddir) && $(SHELL) ./config.status $@
@@ -520,6 +576,48 @@ clean-libtool:
distclean-libtool:
-rm -f libtool config.lt
+install-dist_cmakeDATA: $(dist_cmake_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_cmake_DATA)'; test -n "$(cmakedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(cmakedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(cmakedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(cmakedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(cmakedir)" || exit $$?; \
+ done
+
+uninstall-dist_cmakeDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_cmake_DATA)'; test -n "$(cmakedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(cmakedir)'; $(am__uninstall_files_from_dir)
+install-nodist_cmakeDATA: $(nodist_cmake_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(nodist_cmake_DATA)'; test -n "$(cmakedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(cmakedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(cmakedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(cmakedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(cmakedir)" || exit $$?; \
+ done
+
+uninstall-nodist_cmakeDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_cmake_DATA)'; test -n "$(cmakedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(cmakedir)'; $(am__uninstall_files_from_dir)
install-pkgconfigDATA: $(pkgconfig_DATA)
@$(NORMAL_INSTALL)
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
@@ -647,7 +745,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -728,6 +825,10 @@ dist-xz: distdir
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
$(am__post_remove_distdir)
+dist-zstd: distdir
+ tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst
+ $(am__post_remove_distdir)
+
dist-tarZ: distdir
@echo WARNING: "Support for distribution archives compressed with" \
"legacy program 'compress' is deprecated." >&2
@@ -770,6 +871,8 @@ distcheck: dist
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
+ *.tar.zst*) \
+ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\
esac
chmod -R a-w $(distdir)
chmod u+w $(distdir)
@@ -785,7 +888,7 @@ distcheck: dist
$(DISTCHECK_CONFIGURE_FLAGS) \
--srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
- && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
@@ -841,7 +944,7 @@ check: check-recursive
all-am: Makefile $(DATA) expat_config.h
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
+ for dir in "$(DESTDIR)$(cmakedir)" "$(DESTDIR)$(cmakedir)" "$(DESTDIR)$(pkgconfigdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@@ -896,7 +999,8 @@ info: info-recursive
info-am:
-install-data-am: install-pkgconfigDATA
+install-data-am: install-dist_cmakeDATA install-nodist_cmakeDATA \
+ install-pkgconfigDATA
install-dvi: install-dvi-recursive
@@ -942,7 +1046,8 @@ ps: ps-recursive
ps-am:
-uninstall-am: uninstall-pkgconfigDATA
+uninstall-am: uninstall-dist_cmakeDATA uninstall-nodist_cmakeDATA \
+ uninstall-pkgconfigDATA
.MAKE: $(am__recursive_targets) all install-am install-strip
@@ -950,18 +1055,21 @@ uninstall-am: uninstall-pkgconfigDATA
am--refresh check check-am clean clean-cscope clean-generic \
clean-libtool cscope cscopelist-am ctags ctags-am dist \
dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \
- dist-xz dist-zip distcheck distclean distclean-generic \
- distclean-hdr distclean-libtool distclean-tags distcleancheck \
- distdir distuninstallcheck dvi dvi-am html html-am info \
- info-am install install-am install-data install-data-am \
+ dist-xz dist-zip dist-zstd distcheck distclean \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_cmakeDATA \
install-dvi install-dvi-am install-exec install-exec-am \
install-html install-html-am install-info install-info-am \
- install-man install-pdf install-pdf-am install-pkgconfigDATA \
- install-ps install-ps-am install-strip installcheck \
- installcheck-am installdirs installdirs-am maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-generic \
- mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
- uninstall-am uninstall-pkgconfigDATA
+ install-man install-nodist_cmakeDATA install-pdf \
+ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-dist_cmakeDATA uninstall-nodist_cmakeDATA \
+ uninstall-pkgconfigDATA
.PRECIOUS: Makefile
@@ -989,6 +1097,11 @@ buildlib:
run-benchmark:
$(MAKE) -C tests/benchmark
./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/recset.xml 65535 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_attr.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_cdata.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_comment.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_tag.xml 4096 3
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/aaaaaa_text.xml 4096 3
.PHONY: download-xmlts-zip
download-xmlts-zip:
diff --git a/contrib/expat/README.md b/contrib/expat/README.md
index 1cc52b014489..43c4f4f3dbb3 100644
--- a/contrib/expat/README.md
+++ b/contrib/expat/README.md
@@ -1,12 +1,15 @@
-[![Travis CI Build Status](https://travis-ci.org/libexpat/libexpat.svg?branch=master)](https://travis-ci.org/libexpat/libexpat)
+[![Run Linux CI tasks](https://github.com/libexpat/libexpat/actions/workflows/linux.yml/badge.svg)](https://github.com/libexpat/libexpat/actions/workflows/linux.yml)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/libexpat/libexpat?svg=true)](https://ci.appveyor.com/project/libexpat/libexpat)
[![Packaging status](https://repology.org/badge/tiny-repos/expat.svg)](https://repology.org/metapackage/expat/versions)
+[![Downloads SourceForge](https://img.shields.io/sourceforge/dt/expat?label=Downloads%20SourceForge)](https://sourceforge.net/projects/expat/files/)
+[![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases)
-# Expat, Release 2.2.9
+# Expat, Release 2.6.0
-This is Expat, a C library for parsing XML, started by
-[James Clark](https://en.wikipedia.org/wiki/James_Clark_(programmer)) in 1997.
+This is Expat, a C99 library for parsing
+[XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
+[James Clark](https://en.wikipedia.org/wiki/James_Clark_%28programmer%29) in 1997.
Expat is a stream-oriented XML parser. This means that you register
handlers with the parser before starting the parse. These handlers
are called when the parser discovers the associated structures in the
@@ -14,13 +17,14 @@ document being parsed. A start tag is an example of the kind of
structures for which you may register handlers.
Expat supports the following compilers:
+
- GNU GCC >=4.5
- LLVM Clang >=3.5
-- Microsoft Visual Studio >=8.0/2005
+- Microsoft Visual Studio >=15.0/2017 (rolling `${today} minus 5 years`)
-Windows users should use the
-[`expat_win32` package](https://sourceforge.net/projects/expat/files/expat_win32/),
-which includes both precompiled libraries and executables, and source code for
+Windows users can use the
+[`expat-win32bin-*.*.*.{exe,zip}` download](https://github.com/libexpat/libexpat/releases),
+which includes both pre-compiled libraries and executables, and source code for
developers.
Expat is [free software](https://www.gnu.org/philosophy/free-sw.en.html).
@@ -30,6 +34,67 @@ contained in the file
distributed with this package.
This license is the same as the MIT/X Consortium license.
+
+## Using libexpat in your CMake-Based Project
+
+There are two ways of using libexpat with CMake:
+
+### a) Module Mode
+
+This approach leverages CMake's own [module `FindEXPAT`](https://cmake.org/cmake/help/latest/module/FindEXPAT.html).
+
+Notice the *uppercase* `EXPAT` in the following example:
+
+```cmake
+cmake_minimum_required(VERSION 3.0) # or 3.10, see below
+
+project(hello VERSION 1.0.0)
+
+find_package(EXPAT 2.2.8 MODULE REQUIRED)
+
+add_executable(hello
+ hello.c
+)
+
+# a) for CMake >=3.10 (see CMake's FindEXPAT docs)
+target_link_libraries(hello PUBLIC EXPAT::EXPAT)
+
+# b) for CMake >=3.0
+target_include_directories(hello PRIVATE ${EXPAT_INCLUDE_DIRS})
+target_link_libraries(hello PUBLIC ${EXPAT_LIBRARIES})
+```
+
+### b) Config Mode
+
+This approach requires files from…
+
+- libexpat >=2.2.8 where packaging uses the CMake build system
+or
+- libexpat >=2.3.0 where packaging uses the GNU Autotools build system
+ on Linux
+or
+- libexpat >=2.4.0 where packaging uses the GNU Autotools build system
+ on macOS or MinGW.
+
+Notice the *lowercase* `expat` in the following example:
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+
+project(hello VERSION 1.0.0)
+
+find_package(expat 2.2.8 CONFIG REQUIRED char dtd ns)
+
+add_executable(hello
+ hello.c
+)
+
+target_link_libraries(hello PUBLIC expat::expat)
+```
+
+
+## Building from a Git Clone
+
If you are building Expat from a check-out from the
[Git repository](https://github.com/libexpat/libexpat/),
you need to run a script that generates the configure script using the
@@ -43,6 +108,11 @@ autoconf 2.58 or newer. Run the script like this:
Once this has been done, follow the same instructions as for building
from a source distribution.
+
+## Building from a Source Distribution
+
+### a) Building with the configure script (i.e. GNU Autotools)
+
To build Expat from a source distribution, you first run the
configuration shell script in the top level distribution directory:
@@ -132,8 +202,14 @@ A reference manual is available in the file `doc/reference.html` in this
distribution.
-The CMake build system is still *experimental* and will replace the primary
+### b) Building with CMake
+
+The CMake build system is still *experimental* and may replace the primary
build system based on GNU Autotools at some point when it is ready.
+
+
+#### Available Options
+
For an idea of the available (non-advanced) options for building with CMake:
```console
@@ -147,31 +223,37 @@ CMAKE_INSTALL_PREFIX:PATH=/usr/local
// Path to a program.
DOCBOOK_TO_MAN:FILEPATH=/usr/bin/docbook2x-man
-// build man page for xmlwf
+// Build man page for xmlwf
EXPAT_BUILD_DOCS:BOOL=ON
-// build the examples for expat library
+// Build the examples for expat library
EXPAT_BUILD_EXAMPLES:BOOL=ON
-// build fuzzers for the expat library
+// Build fuzzers for the expat library
EXPAT_BUILD_FUZZERS:BOOL=OFF
-// build the tests for expat library
+// Build pkg-config file
+EXPAT_BUILD_PKGCONFIG:BOOL=ON
+
+// Build the tests for expat library
EXPAT_BUILD_TESTS:BOOL=ON
-// build the xmlwf tool for expat library
+// Build the xmlwf tool for expat library
EXPAT_BUILD_TOOLS:BOOL=ON
// Character type to use (char|ushort|wchar_t) [default=char]
EXPAT_CHAR_TYPE:STRING=char
-// install expat files in cmake install target
+// Install expat files in cmake install target
EXPAT_ENABLE_INSTALL:BOOL=ON
// Use /MT flag (static CRT) when compiling in MSVC
EXPAT_MSVC_STATIC_CRT:BOOL=OFF
-// build a shared expat library
+// Build fuzzers via ossfuzz for the expat library
+EXPAT_OSSFUZZ_BUILD:BOOL=OFF
+
+// Build a shared expat library
EXPAT_SHARED_LIBS:BOOL=ON
// Treat all compiler warnings as errors
@@ -180,7 +262,7 @@ EXPAT_WARNINGS_AS_ERRORS:BOOL=OFF
// Make use of getrandom function (ON|OFF|AUTO) [default=AUTO]
EXPAT_WITH_GETRANDOM:STRING=AUTO
-// utilize libbsd (for arc4random_buf)
+// Utilize libbsd (for arc4random_buf)
EXPAT_WITH_LIBBSD:BOOL=OFF
// Make use of syscall SYS_getrandom (ON|OFF|AUTO) [default=AUTO]
diff --git a/contrib/expat/buildconf.sh b/contrib/expat/buildconf.sh
new file mode 100755
index 000000000000..5e2b3269c256
--- /dev/null
+++ b/contrib/expat/buildconf.sh
@@ -0,0 +1,55 @@
+#! /usr/bin/env bash
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+set -e
+
+# File expat_config.h.in (as generated by autoheader by autoreconf) contains
+# macro SIZEOF_VOID_P which is (1) not really needed by Expat as of today and
+# (2) a problem to "multilib" systems with one shared installed
+# /usr/include/expat_config.h for two Expats with different "void *" sizes
+# installed in e.g. /usr/lib32 and /usr/lib64. Hence we patch macro
+# SIZEOF_VOID_P out of template expat_config.h.in so that configure will
+# not put SIZEOF_VOID_P in the eventual expat_config.h.
+patch_expat_config_h_in() {
+ local filename="$1"
+ local sizeof_void_p_line_number="$(grep -F -n SIZEOF_VOID_P "${filename}" | awk -F: '{print $1}')"
+ [[ ${sizeof_void_p_line_number} =~ ^[0-9]+$ ]] # cheap assert
+ local first_line_to_delete=$(( sizeof_void_p_line_number - 1 ))
+ local last_line_to_delete=$(( sizeof_void_p_line_number + 1 ))
+ # Note: Avoiding "sed -i" only for macOS portability.
+ local tempfile="$(mktemp)"
+ sed "${first_line_to_delete},${last_line_to_delete}d" "${filename}" > "${tempfile}"
+ mv "${tempfile}" "${filename}"
+}
+
+autoreconf --warnings=all --install --verbose "$@"
+
+patch_expat_config_h_in expat_config.h.in
diff --git a/contrib/expat/configure.ac b/contrib/expat/configure.ac
index e2b9a1146286..a5d1ff9317c8 100644
--- a/contrib/expat/configure.ac
+++ b/contrib/expat/configure.ac
@@ -1,21 +1,54 @@
dnl configuration script for expat
dnl Process this file with autoconf to produce a configure script.
+dnl __ __ _
+dnl ___\ \/ /_ __ __ _| |_
+dnl / _ \\ /| '_ \ / _` | __|
+dnl | __// \| |_) | (_| | |_
+dnl \___/_/\_\ .__/ \__,_|\__|
+dnl |_| XML parser
dnl
-dnl Copyright 2000 Clark Cooper
+dnl Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+dnl Copyright (c) 2000-2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+dnl Copyright (c) 2001-2003 Greg Stein <gstein@users.sourceforge.net>
+dnl Copyright (c) 2006-2012 Karl Waclawek <karl@waclawek.net>
+dnl Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+dnl Copyright (c) 2017 S. P. Zeidler <spz@netbsd.org>
+dnl Copyright (c) 2017 Stephen Groat <stephen@groat.us>
+dnl Copyright (c) 2017-2020 Joe Orton <jorton@redhat.com>
+dnl Copyright (c) 2018 Yury Gribov <tetra2005@gmail.com>
+dnl Copyright (c) 2018 Benjamin Peterson <benjamin@python.org>
+dnl Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+dnl Copyright (c) 2018 KangLin <kl222@126.com>
+dnl Copyright (c) 2019 Mohammed Khajapasha <mohammed.khajapasha@intel.com>
+dnl Copyright (c) 2019 Kishore Kunche <kishore.kunche@intel.com>
+dnl Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
+dnl Licensed under the MIT license:
dnl
-dnl This file is part of EXPAT.
+dnl Permission is hereby granted, free of charge, to any person obtaining
+dnl a copy of this software and associated documentation files (the
+dnl "Software"), to deal in the Software without restriction, including
+dnl without limitation the rights to use, copy, modify, merge, publish,
+dnl distribute, sublicense, and/or sell copies of the Software, and to permit
+dnl persons to whom the Software is furnished to do so, subject to the
+dnl following conditions:
dnl
-dnl EXPAT is free software; you can redistribute it and/or modify it
-dnl under the terms of the License (based on the MIT/X license) contained
-dnl in the file COPYING that comes with this distribution.
+dnl The above copyright notice and this permission notice shall be included
+dnl in all copies or substantial portions of the Software.
dnl
+dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+dnl EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+dnl MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+dnl NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+dnl DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+dnl OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+dnl USE OR OTHER DEALINGS IN THE SOFTWARE.
dnl Ensure that Expat is configured with autoconf 2.69 or newer.
-AC_PREREQ(2.69)
+AC_PREREQ([2.69])
dnl Get the version number of Expat, using m4's esyscmd() command to run
dnl the command at m4-generation time. This allows us to create an m4
-dnl symbol holding the correct version number. AC_INIT() requires the
+dnl symbol holding the correct version number. AC_INIT requires the
dnl version number at m4-time, rather than when ./configure is run, so
dnl all this must happen as part of m4, not as part of the shell code
dnl contained in ./configure.
@@ -27,7 +60,7 @@ m4_define([expat_version],
m4_ifdef([__gnu__],
[esyscmd(conftools/get-version.sh lib/expat.h)],
[2.2.x]))
-AC_INIT(expat, expat_version, expat-bugs@libexpat.org)
+AC_INIT([expat], expat_version, [https://github.com/libexpat/libexpat/issues])
m4_undefine([expat_version])
AC_CONFIG_SRCDIR([Makefile.in])
@@ -35,6 +68,7 @@ AC_CONFIG_AUX_DIR([conftools])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE([enable]) # to allow argument --disable-maintainer-mode
dnl
@@ -48,12 +82,14 @@ dnl
dnl If the API changes incompatibly set LIBAGE back to 0
dnl
-LIBCURRENT=7 # sync
-LIBREVISION=11 # with
-LIBAGE=6 # CMakeLists.txt!
+LIBCURRENT=10 # sync
+LIBREVISION=0 # with
+LIBAGE=9 # CMakeLists.txt!
-AX_APPEND_FLAG([-DHAVE_EXPAT_CONFIG_H], [CPPFLAGS])
-AC_CONFIG_HEADER([expat_config.h])
+AC_CONFIG_HEADERS([expat_config.h])
+AH_TOP([#ifndef EXPAT_CONFIG_H
+#define EXPAT_CONFIG_H 1])
+AH_BOTTOM([#endif // ndef EXPAT_CONFIG_H])
AM_PROG_AR
AC_PROG_INSTALL
@@ -69,30 +105,35 @@ AC_SUBST(LIBAGE)
AC_LANG([C])
AC_PROG_CC_C99
+
+AS_IF([test "${ac_cv_prog_cc_c99}" = no],
+ [AC_MSG_ERROR([Expat requires a C99 compiler.])])
+
AS_IF([test "$GCC" = yes],
- [AX_APPEND_COMPILE_FLAGS([-Wall -Wextra], [CFLAGS])
+ [AX_APPEND_COMPILE_FLAGS([-Wall -Wextra], [AM_CFLAGS])
dnl Be careful about adding the -fexceptions option; some versions of
dnl GCC don't support it and it causes extra warnings that are only
dnl distracting; avoid.
- AX_APPEND_COMPILE_FLAGS([-fexceptions], [CFLAGS])
- AX_APPEND_COMPILE_FLAGS([-fno-strict-aliasing -Wmissing-prototypes -Wstrict-prototypes], [CFLAGS])
- AX_APPEND_COMPILE_FLAGS([-pedantic -Wduplicated-cond -Wduplicated-branches -Wlogical-op], [CFLAGS])
- AX_APPEND_COMPILE_FLAGS([-Wrestrict -Wnull-dereference -Wjump-misses-init -Wdouble-promotion], [CFLAGS])
- AX_APPEND_COMPILE_FLAGS([-Wshadow -Wformat=2 -Wmisleading-indentation], [CFLAGS])])
+ AX_APPEND_COMPILE_FLAGS([-fexceptions], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-fno-strict-aliasing -Wmissing-prototypes -Wstrict-prototypes], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-pedantic -Wduplicated-cond -Wduplicated-branches -Wlogical-op], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-Wrestrict -Wnull-dereference -Wjump-misses-init -Wdouble-promotion], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-Wshadow -Wformat=2 -Wno-pedantic-ms-format -Wmisleading-indentation], [AM_CFLAGS])])
AC_LANG_PUSH([C++])
AC_PROG_CXX
+
AS_IF([test "$GCC" = yes],
- [AX_APPEND_COMPILE_FLAGS([-Wall -Wextra], [CXXFLAGS])
+ [AX_APPEND_COMPILE_FLAGS([-Wall -Wextra], [AM_CXXFLAGS])
dnl Be careful about adding the -fexceptions option; some versions of
dnl GCC don't support it and it causes extra warnings that are only
dnl distracting; avoid.
- AX_APPEND_COMPILE_FLAGS([-fexceptions], [CXXFLAGS])
- AX_APPEND_COMPILE_FLAGS([-fno-strict-aliasing], [CXXFLAGS])])
+ AX_APPEND_COMPILE_FLAGS([-fexceptions], [AM_CXXFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-fno-strict-aliasing], [AM_CXXFLAGS])])
AC_LANG_POP([C++])
AS_IF([test "$GCC" = yes],
- [AX_APPEND_LINK_FLAGS([-fno-strict-aliasing],[LDFLAGS])])
+ [AX_APPEND_LINK_FLAGS([-fno-strict-aliasing],[AM_LDFLAGS])])
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang (issue #312)
AS_CASE(["$LD"],[*clang*],
@@ -100,11 +141,9 @@ AS_CASE(["$LD"],[*clang*],
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
EXPATCFG_COMPILER_SUPPORTS_VISIBILITY([
- AX_APPEND_FLAG([-fvisibility=hidden], [CFLAGS])
- AX_APPEND_FLAG([-DXML_ENABLE_VISIBILITY=1], [CFLAGS])])
-
-dnl Checks for header files.
-AC_HEADER_STDC
+ AX_APPEND_FLAG([-fvisibility=hidden], [AM_CFLAGS])
+ AS_IF([test "${enable_shared}" = yes],
+ [AX_APPEND_FLAG([-DXML_ENABLE_VISIBILITY=1], [AM_CPPFLAGS])])])
dnl Checks for typedefs, structures, and compiler characteristics.
@@ -141,6 +180,8 @@ AC_ARG_WITH([tests],
[with_tests=yes])
AM_CONDITIONAL([WITH_TESTS], [test x${with_tests} = xyes])
+AS_IF([test x${with_tests} = xyes],
+ [AX_CXX_COMPILE_STDCXX_11([noext], [mandatory])])
AS_VAR_SET([EXPATCFG_ON_MINGW],[no])
AS_CASE("${host_os}",
@@ -149,8 +190,13 @@ AS_CASE("${host_os}",
AC_MSG_NOTICE([detected OS: MinGW])])
AM_CONDITIONAL([MINGW], [test x${EXPATCFG_ON_MINGW} = xyes])
+dnl Note: Prefix "_INTERNAL_" here means exclusive use inside of file configure.ac
AM_CONDITIONAL([UNICODE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_UNICODE >/dev/null])
+AM_CONDITIONAL([_INTERNAL_UNICODE_WCHAR_T], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_UNICODE_WCHAR_T >/dev/null])
+AM_CONDITIONAL([_INTERNAL_MIN_SIZE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_MIN_SIZE >/dev/null])
+AM_CONDITIONAL([_INTERNAL_LARGE_SIZE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_LARGE_SIZE >/dev/null])
+LT_LIB_M
AC_ARG_WITH([libbsd],
[AS_HELP_STRING([--with-libbsd], [utilize libbsd (for arc4random_buf)])],
@@ -162,14 +208,16 @@ AS_IF([test "x${with_libbsd}" != xno],
[],
[AS_IF([test "x${with_libbsd}" = xyes],
[AC_MSG_ERROR([Enforced use of libbsd cannot be satisfied.])])])])
-AC_MSG_CHECKING([for arc4random_buf (BSD or libbsd)])
+AC_MSG_CHECKING([for arc4random_buf (BSD, libbsd or glibc 2.36+)])
AC_LINK_IFELSE([AC_LANG_SOURCE([
- #include <stdlib.h> /* for arc4random_buf on BSD, for NULL */
#if defined(HAVE_LIBBSD)
# include <bsd/stdlib.h>
+ #else
+ # include <stdlib.h> /* for arc4random_buf on BSD */
#endif
int main() {
- arc4random_buf(NULL, 0U);
+ char dummy[[123]]; // double brackets for m4
+ arc4random_buf(dummy, 0U);
return 0;
}
])],
@@ -177,7 +225,7 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
- AC_MSG_CHECKING([for arc4random (BSD, macOS or libbsd)])
+ AC_MSG_CHECKING([for arc4random (BSD, macOS, libbsd or glibc 2.36+)])
AC_LINK_IFELSE([AC_LANG_SOURCE([
#if defined(HAVE_LIBBSD)
# include <bsd/stdlib.h>
@@ -255,6 +303,8 @@ AC_SUBST(FILEMAP)
dnl Some basic configuration:
AC_DEFINE([XML_NS], 1,
[Define to make XML Namespaces functionality available.])
+AC_DEFINE([XML_GE], 1,
+ [Define as 1/0 to enable/disable support for general entities.])
AC_DEFINE([XML_DTD], 1,
[Define to make parameter entity parsing functionality available.])
AC_DEFINE([XML_DEV_URANDOM], 1,
@@ -279,9 +329,10 @@ AS_HELP_STRING([--disable-xml-context],
AS_IF([test "x${enable_xml_context}" != "xno"],
[AS_IF([test "x${enable_xml_context}" = "xyes" \
-o "x${enable_xml_context}" = "x"],
- [AS_VAR_SET(enable_xml_context,1024)])
- AC_DEFINE_UNQUOTED([XML_CONTEXT_BYTES], [${enable_xml_context}],
- [Define to specify how much context to retain around the current parse point.])])
+ [AS_VAR_SET(enable_xml_context,1024)])],
+ [AS_VAR_SET(enable_xml_context,0)])
+AC_DEFINE_UNQUOTED([XML_CONTEXT_BYTES], [${enable_xml_context}],
+ [Define to specify how much context to retain around the current parse point, 0 to disable.])
AC_ARG_WITH([docbook],
[AS_HELP_STRING([--with-docbook],
@@ -305,10 +356,81 @@ AS_IF([test "x${DOCBOOK_TO_MAN}" != x -a "x$with_docbook" != xno],
You can also configure using --without-docbook if you can do without a man
page for xmlwf.])])])
-AM_CONDITIONAL(WITH_DOCBOOK, [test "x${DOCBOOK_TO_MAN}" != x])
+dnl This will make sure that a release tarball shipping a pre-rendered xmlwf man page will
+dnl get it installed, independent of whether some flavor of docbook2man is available.
+dnl This relies on file xmlwf.1 being at least as recent as its source file xmlwf.xml.
+AS_IF([test -f "${srcdir}"/doc/xmlwf.1],
+ [AM_CONDITIONAL(WITH_DOCBOOK, [true])],
+ [AM_CONDITIONAL(WITH_DOCBOOK, [test "x${DOCBOOK_TO_MAN}" != x])])
+
+dnl Configure CMake file templates
+dnl NOTE: The *_TRUE variables read here are Automake conditionals
+dnl that are either set to "" when enabled or to "#" when disabled
+dnl (because they are used to dynamically comment out certain things)
+AS_IF([test "x${enable_xml_attr_info}" = xyes],
+ [EXPAT_ATTR_INFO=ON],
+ [EXPAT_ATTR_INFO=OFF])
+EXPAT_DTD=ON
+AS_IF([test "x${_INTERNAL_LARGE_SIZE_TRUE}" = x],
+ [EXPAT_LARGE_SIZE=ON],
+ [EXPAT_LARGE_SIZE=OFF])
+AS_IF([test "x${_INTERNAL_MIN_SIZE_TRUE}" = x],
+ [EXPAT_MIN_SIZE=ON],
+ [EXPAT_MIN_SIZE=OFF])
+EXPAT_NS=ON
+AS_IF([test "x${enable_xml_context}" != xno],
+ [EXPAT_CONTEXT_BYTES=${enable_xml_context}],
+ [EXPAT_CONTEXT_BYTES=OFF])
+AS_IF([test "x${UNICODE_TRUE}" = x],
+ [AS_IF(
+ [test "x${_INTERNAL_UNICODE_WCHAR_T_TRUE}" = x],
+ [EXPAT_CHAR_TYPE=wchar_t],
+ [EXPAT_CHAR_TYPE=ushort])],
+ [EXPAT_CHAR_TYPE=char])
+PACKAGE_INIT="${srcdir}"/cmake/autotools/expat-package-init.cmake
+LIBDIR_BASENAME="$(basename "${libdir}")"
+SO_MAJOR="$(expr "${LIBCURRENT}" - "${LIBAGE}")"
+SO_MINOR="${LIBAGE}"
+SO_PATCH="${LIBREVISION}"
+AC_CHECK_SIZEOF([void *]) # sets ac_cv_sizeof_void_p
+AC_SUBST([EXPAT_ATTR_INFO])
+AC_SUBST([EXPAT_DTD])
+AC_SUBST([EXPAT_LARGE_SIZE])
+AC_SUBST([EXPAT_MIN_SIZE])
+AC_SUBST([EXPAT_NS])
+AC_SUBST([EXPAT_CONTEXT_BYTES])
+AC_SUBST([EXPAT_CHAR_TYPE])
+AC_SUBST_FILE([PACKAGE_INIT])
+AC_SUBST([LIBDIR_BASENAME])
+AC_SUBST([SO_MAJOR])
+AC_SUBST([SO_MINOR])
+AC_SUBST([SO_PATCH])
+AC_SUBST([ac_cv_sizeof_void_p])
+
+
+dnl write the Automake flags we set
+AC_SUBST([AM_CPPFLAGS])
+AC_SUBST([AM_CFLAGS])
+AC_SUBST([AM_CXXFLAGS])
+AC_SUBST([AM_LDFLAGS])
+
+dnl Emulate the use of CMAKE_SHARED_LIBRARY_PREFIX under CMake
+AC_MSG_CHECKING([for shared library name prefix])
+AS_CASE("${host_os}",
+ [cygwin*], [CMAKE_SHARED_LIBRARY_PREFIX=cyg],
+ [CMAKE_SHARED_LIBRARY_PREFIX=lib])
+AC_MSG_RESULT([${CMAKE_SHARED_LIBRARY_PREFIX}])
+AC_SUBST([CMAKE_SHARED_LIBRARY_PREFIX])
+AS_CASE("${host_os}",
+ [darwin*], [CMAKE_NOCONFIG_SOURCE=cmake/autotools/expat-noconfig__macos.cmake.in],
+ [mingw*|cygwin*], [CMAKE_NOCONFIG_SOURCE=cmake/autotools/expat-noconfig__windows.cmake.in],
+ [CMAKE_NOCONFIG_SOURCE=cmake/autotools/expat-noconfig__linux.cmake.in])
AC_CONFIG_FILES([Makefile]
[expat.pc]
+ [cmake/expat-config.cmake]
+ [cmake/autotools/expat-config-version.cmake]
+ [cmake/autotools/expat-noconfig.cmake:${CMAKE_NOCONFIG_SOURCE}]
[doc/Makefile]
[examples/Makefile]
[lib/Makefile]
@@ -317,3 +439,18 @@ AC_CONFIG_FILES([Makefile]
[xmlwf/Makefile])
AC_CONFIG_FILES([run.sh], [chmod +x run.sh])
AC_OUTPUT
+
+
+AC_MSG_NOTICE([
+
+Automake flags (can be overridden by user flags):
+ [AM_CPPFLAGS]: ${AM_CPPFLAGS}
+ [AM_CFLAGS]: ${AM_CFLAGS}
+ [AM_CXXFLAGS]: ${AM_CXXFLAGS}
+ [AM_LDFLAGS]: ${AM_LDFLAGS}
+
+User flags (override Automake flags on conflict):
+ CPPFLAGS: ${CPPFLAGS}
+ CFLAGS: ${CFLAGS}
+ CXXFLAGS: ${CXXFLAGS}
+ LDFLAGS: ${LDFLAGS}])
diff --git a/contrib/expat/doc/Makefile.am b/contrib/expat/doc/Makefile.am
index e2f029837a41..c3a3ce59c1b9 100644
--- a/contrib/expat/doc/Makefile.am
+++ b/contrib/expat/doc/Makefile.am
@@ -6,7 +6,9 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017 Stephen Groat <stephen@groat.us>
+# Copyright (c) 2017 Joe Orton <jorton@redhat.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -52,8 +54,7 @@ clean-local-check:
$(RM) xmlwf.1
EXTRA_DIST = \
- expat.png \
+ ok.min.css \
reference.html \
style.css \
- valid-xhtml10.png \
xmlwf.xml
diff --git a/contrib/expat/doc/Makefile.in b/contrib/expat/doc/Makefile.in
index e021e8c675fe..18f86be3947b 100644
--- a/contrib/expat/doc/Makefile.in
+++ b/contrib/expat/doc/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,9 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017 Stephen Groat <stephen@groat.us>
+# Copyright (c) 2017 Joe Orton <jorton@redhat.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -130,6 +132,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/conftools/ax-append-compile-flags.m4 \
$(top_srcdir)/conftools/ax-append-link-flags.m4 \
$(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx-11.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -193,7 +197,11 @@ am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
@@ -203,8 +211,10 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CPP = @CPP@
+CMAKE_SHARED_LIBRARY_PREFIX = @CMAKE_SHARED_LIBRARY_PREFIX@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -220,10 +230,20 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
+EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
+EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
+EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
+EXPAT_DTD = @EXPAT_DTD@
+EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
+EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
+EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FILEMAP = @FILEMAP@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -233,6 +253,8 @@ LD = @LD@
LDFLAGS = @LDFLAGS@
LIBAGE = @LIBAGE@
LIBCURRENT = @LIBCURRENT@
+LIBDIR_BASENAME = @LIBDIR_BASENAME@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBREVISION = @LIBREVISION@
LIBS = @LIBS@
@@ -241,6 +263,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -262,6 +285,9 @@ RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SO_MAJOR = @SO_MAJOR@
+SO_MINOR = @SO_MINOR@
+SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
@@ -272,6 +298,7 @@ ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_void_p = @ac_cv_sizeof_void_p@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -309,6 +336,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -319,16 +347,15 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
@WITH_DOCBOOK_TRUE@dist_man_MANS = xmlwf.1
EXTRA_DIST = \
- expat.png \
+ ok.min.css \
reference.html \
style.css \
- valid-xhtml10.png \
xmlwf.xml
all: all-am
.SUFFIXES:
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -352,9 +379,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: $(am__configure_deps)
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
@@ -413,7 +440,6 @@ ctags CTAGS:
cscope cscopelist:
@WITH_DOCBOOK_TRUE@dist-hook:
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
diff --git a/contrib/expat/doc/expat.png b/contrib/expat/doc/expat.png
deleted file mode 100644
index 3d88eac4a133..000000000000
--- a/contrib/expat/doc/expat.png
+++ /dev/null
Binary files differ
diff --git a/contrib/expat/doc/ok.min.css b/contrib/expat/doc/ok.min.css
new file mode 100644
index 000000000000..d324fabb2873
--- /dev/null
+++ b/contrib/expat/doc/ok.min.css
@@ -0,0 +1,2 @@
+/*! OK.css v1.2.0 | MIT License | github.com/andrewh0/okcss */@import url("https://rsms.me/inter/inter.css");
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}:root{--ok-sans:"Inter",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Open Sans","Helvetica Neue","Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--ok-mono:SFMono-Regular,Menlo,Monaco,Consolas,"Ubuntu Mono","Liberation Mono","Courier New",Courier,monospace;--ok-fw-0:400;--ok-fw-1:600;--ok-fw-2:700;--ok-fw-3:700;--ok-fs-0:2.5rem;--ok-fs-1:2rem;--ok-fs-2:1.5rem;--ok-fs-3:1.25rem;--ok-fs-4:1rem;--ok-fs-5:0.75rem;--ok-br:0.25rem;--ok-s-0:0;--ok-s-1:0.25rem;--ok-s-2:0.5rem;--ok-s-3:1rem;--ok-s-4:1.5rem;--ok-s-5:2rem;--ok-s-6:2.5rem;--ok-lh-body:1.5;--ok-lh-heading:1.25;--ok-t-hl:#ffcf30;--ok-accent-0:#3e67fa;--ok-accent-1:#4788ff;--ok-tc-accent:#3173de;--ok-tc-code:#c23a30;--ok-tc-0:#000;--ok-tc-1:#747474;--ok-tc-2:#848484;--ok-bg-0:#fff;--ok-bg-1:#f0f0f0;--ok-bg-2:#ccc;--ok-b-0:1px solid #cbcbcb;--ok-b-1:1px solid #848484;--ok-down-0:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='8' viewBox='0 0 12 8' width='24' fill='none'%3E%3Cpath d='M6 6l4-4h1v1-1L6 7 1 2h1l4 4z' fill='%23747474'/%3E%3C/svg%3E");--ok-down-1:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='8' viewBox='0 0 12 8' width='24' fill='none'%3E%3Cpath d='M6 6l4-4h1v1-1L6 7 1 2h1l4 4z' fill='%23848484'/%3E%3C/svg%3E")}@media (prefers-color-scheme:dark){:root{--ok-tc-accent:#5c9aff;--ok-tc-code:#ed5853;--ok-tc-0:#fff;--ok-tc-1:#ababab;--ok-tc-2:#929292;--ok-bg-0:#000;--ok-bg-1:#212121;--ok-bg-2:#3e3e3e;--ok-b-0:1px solid #747474;--ok-b-1:1px solid #929292;--ok-down-0:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='8' viewBox='0 0 12 8' width='24' fill='none'%3E%3Cpath d='M6 6l4-4h1v1-1L6 7 1 2h1l4 4z' fill='%23ababab'/%3E%3C/svg%3E");--ok-down-1:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='8' viewBox='0 0 12 8' width='24' fill='none'%3E%3Cpath d='M6 6l4-4h1v1-1L6 7 1 2h1l4 4z' fill='%23929292'/%3E%3C/svg%3E")}}*,:after,:before{box-sizing:border-box}*{margin:0;padding:0}html{font-family:var(--ok-sans);line-sizing:normal;line-height:var(--ok-lh-body);font-weight:var(--ok-fw-0);color:var(--ok-tc-0);background-color:var(--ok-bg-0);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%;text-rendering:optimizeLegibility;scroll-behavior:smooth}@supports (font-variation-settings:normal){html{font-family:Inter var,var(--ok-sans)}}button,input,optgroup,select,textarea{font-family:inherit;line-height:var(--ok-lh-body)}[role=button],button{cursor:pointer}audio,canvas,embed,iframe,img,input,object,select,svg,textarea,video{display:block}img,video{max-width:100%;height:auto}body{padding:var(--ok-s-3);max-width:80ch;margin:auto}article{padding-bottom:var(--ok-s-6)}h1{font-size:var(--ok-fs-0);margin:0}h2{font-size:var(--ok-fs-1)}h3{font-size:var(--ok-fs-2)}h4{font-size:var(--ok-fs-3)}h5{font-size:var(--ok-fs-4)}h6{font-size:var(--ok-fs-5);text-transform:uppercase;font-weight:var(--ok-fw-1)}h1,h2,h3,h4,h5,h6{line-height:var(--ok-lh-heading);font-weight:var(--ok-fw-3);margin-top:var(--ok-s-6);margin-bottom:var(--ok-s-3)}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*,hr+*{margin-top:0}p{font-size:var(--ok-fs-4)}small{font-size:var(--ok-fs-5)}b,dt,strong{font-weight:var(--ok-fw-2)}address,article,aside,audio,blockquote,button,canvas,dd,details,dialog,div,dl,embed,fieldset,figcaption,figure,footer,form,header,hgroup,hr,iframe,img,input,main,nav,object,ol,p,pre,section,select,summary,svg,table,textarea,ul,video{margin-bottom:var(--ok-s-4)}address:last-child,article:last-child,aside:last-child,blockquote:last-child,dd:last-child,details:last-child,dialog:last-child,div:last-child,dl:last-child,dt:last-child,fieldset:last-child,figcaption:last-child,figure:last-child,footer:last-child,form:last-child,h1:last-child,h2:last-child,h3:last-child,h4:last-child,h5:last-child,h6:last-child,header:last-child,hgroup:last-child,hr:last-child,input[type=checkbox],input[type=radio],main:last-child,nav:last-child,ol:last-child,p:last-child,pre:last-child,section:last-child,table:last-child,ul:last-child{margin-bottom:0}fieldset{padding:var(--ok-s-3);border:var(--ok-b-0);border-radius:var(--ok-br)}legend{font-weight:var(--ok-fw-1);text-transform:uppercase;font-size:var(--ok-fs-5)}input,select{padding:var(--ok-s-2);background:var(--ok-bg-0);border:var(--ok-b-0);border-radius:var(--ok-br);color:var(--ok-tc-0);min-width:25ch}input:disabled,select:disabled,textarea:disabled{color:var(--ok-tc-2)}input::placeholder,textarea::placeholder{color:var(--ok-tc-2)}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:var(--ok-tc-2)}input::-moz-placeholder,textarea::-moz-placeholder{color:var(--ok-tc-2)}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:var(--ok-tc-2)}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:var(--ok-tc-2)}input::-webkit-clear-button,input::-webkit-inner-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-results-button{display:none}input::-ms-clear,input::-ms-reveal{display:none}input:disabled,textarea:disabled{background-color:var(--ok-bg-1)}input[type=search]{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=file]{max-width:300px}input[type=number]{-moz-appearance:textfield}input[type=checkbox],input[type=radio]{display:inline;min-width:auto}input[type=color]{height:2.5rem}input[type=date],input[type=datetime-local],input[type=month],input[type=time],input[type=week]{height:2.5rem;-webkit-appearance:none;-moz-appearance:none;appearance:none;position:relative}input[type=date]:before,input[type=datetime-local]:before,input[type=month]:before,input[type=time]:before,input[type=week]:before{position:absolute;right:0;top:0;background-image:var(--ok-down-0);background-repeat:no-repeat;background-position:right .2em top 50%;background-size:2em auto;width:2.5rem;height:calc(2.5rem - 2px);content:""}input[type=date]:disabled:before,input[type=datetime-local]:disabled:before,input[type=month]:disabled:before,input[type=time]:disabled:before,input[type=week]:disabled:before{background-image:var(--ok-down-1)}input::-webkit-calendar-picker-indicator{position:absolute;top:0;right:0;background-color:transparent;cursor:pointer;padding:0;width:2.5rem;height:calc(2.5rem - 2px);content:"";opacity:0}input[type=range]{overflow:visible;line-height:inherit;font-family:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:0;outline:none;cursor:pointer;padding:0;vertical-align:middle;border:none;min-height:2rem;background-color:transparent}input[type=range]::-webkit-slider-runnable-track{cursor:pointer;-webkit-appearance:none;border-radius:var(--ok-br);border:var(--ok-b-0);background-color:var(--ok-bg-1);background-image:linear-gradient(var(--ok-bg-1),var(--ok-bg-1));width:100%;height:.5rem;color:transparent;box-sizing:border-box;position:relative}input[type=range]::-moz-range-track{cursor:pointer;-moz-appearance:none;border-radius:var(--ok-br);border:var(--ok-b-0);background-color:var(--ok-bg-1);background-image:linear-gradient(var(--ok-bg-1),var(--ok-bg-1));width:100%;height:.5rem;color:transparent;box-sizing:border-box}input[type=range]::-ms-track{cursor:pointer;-ms-appearance:none;border-radius:var(--ok-br);border:var(--ok-b-0);background-color:var(--ok-bg-1);background-image:linear-gradient(var(--ok-bg-1),var(--ok-bg-1));width:100%;height:.5rem;color:transparent;box-sizing:border-box}input[type=range]::-ms-fill-lower{background:transparent}input[type=range]::-webkit-slider-thumb{cursor:pointer;-webkit-appearance:none;border-radius:50%;background-color:var(--ok-accent-0);width:1.5rem;height:1.5rem;margin-top:calc(-.5rem - 1px)}input[type=range]::-moz-range-thumb{cursor:pointer;-moz-appearance:none;border:none;border-radius:50%;background-color:var(--ok-accent-0);width:1.5rem;height:1.5rem}input[type=range]::-ms-thumb{cursor:pointer;-ms-appearance:none;border-radius:50%;background-color:var(--ok-accent-0);width:1.5rem;height:1.5rem;transform:translateY(.25rem)}input[type=range]:focus:not(:disabled)::-webkit-slider-thumb{background-color:var(--ok-accent-1)}input[type=range]:focus:not(:disabled)::-moz-range-thumb{background-color:var(--ok-accent-1)}input[type=range]:focus:not(:disabled)::-ms-thumb{background-color:var(--ok-accent-1)}input[type=range]:disabled{cursor:default}input[type=range]:disabled::-webkit-slider-runnable-track{cursor:default}input[type=range]:disabled::-moz-range-track{cursor:default}input[type=range]:disabled::-ms-track{cursor:default}input[type=range]:disabled::-webkit-slider-thumb{background-color:var(--ok-bg-2);cursor:default}input[type=range]:disabled::-moz-range-thumb{background-color:var(--ok-bg-2);cursor:default}input[type=range]:disabled::-ms-thumb{background-color:var(--ok-bg-2);cursor:default}select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:var(--ok-b-0);border-radius:var(--ok-br);background-color:var(--ok-bg-0);min-height:2.5rem;color:var(--ok-tc-0)}select:not([multiple]){background-image:var(--ok-down-0);background-repeat:no-repeat,repeat;background-position:right .2em top 50%;background-size:2em auto;padding-right:2.5em;height:2.5rem}select::-ms-expand{display:none}select:not([multiple]):disabled{background-image:var(--ok-down-1);background-color:var(--ok-bg-1);cursor:default}select[multiple]{border-radius:var(--ok-br)}select[multiple]:disabled{background-color:var(--ok-bg-1)}select[multiple] option{color:var(--ok-t-)}select[multiple]:disabled option{color:var(--ok-tc-2)}textarea{padding:var(--ok-s-2);resize:vertical;background:var(--ok-bg-0);border:var(--ok-b-0);border-radius:var(--ok-br);color:var(--ok-tc-0);min-height:calc(2.5rem - 2px);min-width:25ch}button,input[type=button],input[type=reset],input[type=submit]{display:inline-block;background-color:var(--ok-accent-0);border-radius:var(--ok-br);color:#fff;font-weight:var(--ok-fw-1);height:2.5rem;border:none;padding:var(--ok-s-2) var(--ok-s-3);white-space:nowrap;min-width:auto}input::-webkit-file-upload-button{display:inline-block;background-color:var(--ok-accent-0);border-radius:var(--ok-br);color:#fff;font-weight:var(--ok-fw-1);height:2.5rem;border:none;padding:var(--ok-s-2) var(--ok-s-3);white-space:nowrap}input:disabled::-webkit-file-upload-button{cursor:default;opacity:.5}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer}input:not(:disabled)::-webkit-file-upload-button{cursor:pointer}button:disabled,input[type=button]:disabled,input[type=reset]:disabled,input[type=submit]:disabled{cursor:default;opacity:.5;background-color:var(--ok-accent-0)}button:focus:not(:disabled),input[type=button]:focus:not(:disabled),input[type=reset]:focus:not(:disabled),input[type=submit]:focus:not(:disabled){background-color:var(--ok-accent-1)}input:not(:disabled):focus::-webkit-file-upload-button{background-color:var(--ok-accent-1)}table{border-collapse:collapse;display:table;margin-left:auto;margin-right:auto;white-space:nowrap}tfoot,thead{border:var(--ok-b-0)}thead{position:-webkit-sticky;position:sticky;top:0}tfoot tr,thead tr{background-color:var(--ok-bg-1);font-size:var(--ok-fs-5);text-transform:uppercase;color:var(--ok-tc-0)}td,th{border:var(--ok-b-0) 0;text-align:left;padding:.5rem}td{white-space:normal;max-width:20ch}tr{border:var(--ok-b-0)}table caption{font-size:var(--ok-fs-4);font-weight:var(--ok-fw-3);padding:.5rem}code,samp{padding:.2em .4em;color:var(--ok-tc-code)}code,pre,samp{font-family:var(--ok-mono);font-size:87.5%;line-height:var(--ok-lh-body);background-color:var(--ok-bg-1);border-radius:var(--ok-br);text-transform:none}pre{padding:var(--ok-s-3);white-space:pre;overflow-x:auto}pre,var{color:var(--ok-tc-0)}var{font-family:var(--ok-mono);font-style:normal}code pre,pre code{background:inherit;font-size:inherit;color:inherit;border:0;padding:0;margin:0}code pre{display:inline}kbd{background-color:var(--ok-bg-1);border:var(--ok-b-0);border-radius:var(--ok-br);border-bottom:2px solid var(--ok-bg-2);padding:var(--ok-s-1);font-family:var(--ok-sans);color:var(--ok-tc-0)}a{text-decoration:none;font-weight:var(--ok-fw-1)}a,a:visited,a code,a mark,a samp{color:var(--ok-tc-accent)}ol,ul{padding-left:var(--ok-s-5)}nav ul{text-decoration:none;padding-left:0}nav ul li{display:inline;margin-right:1em}li p{margin-bottom:0}li,li p+p{margin-top:.5em}audio,img,video{margin-left:auto;margin-right:auto}img{border-radius:var(--ok-br)}figure>img:not(:last-child){margin-bottom:var(--ok-s-1)}figure>figcaption{text-align:center}figcaption,time{font-size:var(--ok-fs-5);color:var(--ok-tc-1)}mark{padding:.2em .4em;background:var(--ok-t-hl);color:#000;border-radius:var(--ok-br)}iframe{border:var(--ok-b-0);border-radius:var(--ok-br);width:100%}hr{border:none;border-bottom:var(--ok-b-0)}footer{font-size:var(--ok-fs-5)}blockquote,footer{color:var(--ok-tc-1)}blockquote{position:relative;margin-left:0;margin-right:0;padding-left:var(--ok-s-5)}blockquote:before{position:absolute;height:100%;content:"";width:4px;left:0;border-radius:var(--ok-br);background-color:var(--ok-bg-1)}dd{padding-left:var(--ok-s-5)}abbr{cursor:help}@media (hover:hover){a:hover{text-decoration:underline}input:hover:not(:disabled):not(:focus):not([type=submit]):not([type=button]):not([type=reset]):not([type=range]),select:hover:not(:disabled):not(:focus),textarea:hover:not(:disabled):not(:focus){border:var(--ok-b-1)}input[type=range]:hover:not(:disabled)::-webkit-slider-runnable-track{border:var(--ok-b-1)}input[type=range]:hover:not(:disabled)::-moz-range-track{border:var(--ok-b-1)}input[type=range]:hover:not(:disabled)::-ms-track{border:var(--ok-b-1)}select:not([multiple]):not(:disabled):hover{cursor:pointer}button:hover:not(:disabled),input[type=button]:hover:not(:disabled),input[type=reset]:hover:not(:disabled),input[type=submit]:hover:not(:disabled){background-color:var(--ok-accent-1)}input:not(:disabled):hover::-webkit-file-upload-button{background-color:var(--ok-accent-1)}} \ No newline at end of file
diff --git a/contrib/expat/doc/reference.html b/contrib/expat/doc/reference.html
index 23e9a979707b..898f03a3364d 100644
--- a/contrib/expat/doc/reference.html
+++ b/contrib/expat/doc/reference.html
@@ -3,26 +3,58 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
-<!-- Copyright 1999,2000 Clark Cooper <coopercc@netheaven.com>
- All rights reserved.
- This is free software. You may distribute or modify according to
- the terms of the MIT/X License -->
+<!--
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2000-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2002-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2017-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Jakub Wilk <jwilk@jwilk.net>
+ Copyright (c) 2021 Tomas Korbar <tkorbar@redhat.com>
+ Copyright (c) 2021 Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
+ Copyright (c) 2022 Thijs Schreijer <thijs@thijsschreijer.nl>
+ Copyright (c) 2023 Hanno Böck <hanno@gentoo.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+-->
<title>Expat XML Parser</title>
<meta name="author" content="Clark Cooper, coopercc@netheaven.com" />
<meta http-equiv="Content-Style-Type" content="text/css" />
+ <link href="ok.min.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
- <table cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td class="corner"><img src="expat.png" alt="(Expat logo)" /></td>
- <td class="banner"><h1>The Expat XML Parser</h1></td>
- </tr>
- <tr>
- <td class="releaseno">Release 2.0.1</td>
- <td></td>
- </tr>
- </table>
+ <div>
+ <h1>
+ The Expat XML Parser
+ <small>Release 2.6.0</small>
+ </h1>
+ </div>
<div class="content">
<p>Expat is a library, written in C, for parsing XML documents. It's
@@ -38,11 +70,11 @@ Working Group at W3C that produced the XML specification.</p>
<p>This is free software, licensed under the <a
href="../COPYING">MIT/X Consortium license</a>. You may download it
-from <a href="http://www.libexpat.org/">the Expat home page</a>.
+from <a href="https://libexpat.github.io/">the Expat home page</a>.
</p>
<p>The bulk of this document was originally commissioned as an article
-by <a href="http://www.xml.com/">XML.com</a>. They graciously allowed
+by <a href="https://www.xml.com/">XML.com</a>. They graciously allowed
Clark Cooper to retain copyright and to distribute it with Expat.
This version has been substantially extended to include documentation
on features which have been added since the original article was
@@ -120,6 +152,14 @@ interface.</p>
<li><a href="#XML_GetInputContext">XML_GetInputContext</a></li>
</ul>
</li>
+ <li>
+ <a href="#attack-protection">Attack Protection</a>
+ <ul>
+ <li><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></li>
+ <li><a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</a></li>
+ <li><a href="#XML_SetReparseDeferralEnabled">XML_SetReparseDeferralEnabled</a></li>
+ </ul>
+ </li>
<li><a href="#miscellaneous">Miscellaneous Functions</a>
<ul>
<li><a href="#XML_SetUserData">XML_SetUserData</a></li>
@@ -268,7 +308,7 @@ shoveling the document to the parser so that it can do its work.</p>
<p>The Expat distribution comes as a compressed (with GNU gzip) tar
file. You may download the latest version from <a href=
-"http://sourceforge.net/projects/expat/" >Source Forge</a>. After
+"https://sourceforge.net/projects/expat/" >Source Forge</a>. After
unpacking this, cd into the directory. Then follow either the Win32
directions or Unix directions below.</p>
@@ -322,33 +362,64 @@ and the definition of character types in the case of
<code>XML_UNICODE_WCHAR_T</code>. The symbols are:</p>
<dl class="cpp-symbols">
-<dt>XML_DTD</dt>
+<dt><a name="XML_GE">XML_GE</a></dt>
+<dd>
+Added in Expat 2.6.0.
+Include support for
+<a href="https://www.w3.org/TR/2006/REC-xml-20060816/#sec-physical-struct">general entities</a>
+(syntax <code>&amp;e1;</code> to reference and
+syntax <code>&lt;!ENTITY e1 'value1'&gt;</code> (an internal general entity) or
+<code>&lt;!ENTITY e2 SYSTEM 'file2'&gt;</code> (an external general entity) to declare).
+With <code>XML_GE</code> enabled, general entities will be replaced by their declared replacement text;
+for this to work for <em>external</em> general entities, in addition an
+<code><a href="#XML_SetExternalEntityRefHandler">XML_ExternalEntityRefHandler</a></code> must be set using
+<code><a href="#XML_SetExternalEntityRefHandler">XML_SetExternalEntityRefHandler</a></code>.
+Also, enabling <code>XML_GE</code> makes
+the functions <code><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">
+XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></code> and <code>
+<a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">
+XML_SetBillionLaughsAttackProtectionActivationThreshold</a></code> available.
+<br/>
+With <code>XML_GE</code> disabled, Expat has a smaller memory footprint and can be faster, but will
+not load external general entities and will replace all general entities
+(except the <a href="https://www.w3.org/TR/2006/REC-xml-20060816/#sec-predefined-ent">predefined five</a>:
+<code>amp</code>, <code>apos</code>, <code>gt</code>, <code>lt</code>, <code>quot</code>)
+with a self-reference:
+for example, referencing an entity <code>e1</code> via <code>&amp;e1;</code> will be replaced
+by text <code>&amp;e1;</code>.
+</dd>
+
+<dt><a name="XML_DTD">XML_DTD</a></dt>
<dd>Include support for using and reporting DTD-based content. If
this is defined, default attribute values from an external DTD subset
are reported and attribute value normalization occurs based on the
type of attributes defined in the external subset. Without
this, Expat has a smaller memory footprint and can be faster, but will
-not load external entities or process conditional sections. This does
-not affect the set of functions available in the API.</dd>
-
-<dt>XML_NS</dt>
+not load external parameter entities or process conditional sections. If defined, makes
+the functions <code><a
+href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">
+XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></code> and <code>
+<a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">
+XML_SetBillionLaughsAttackProtectionActivationThreshold</a></code> available.</dd>
+
+<dt><a name="XML_NS">XML_NS</a></dt>
<dd>When defined, support for the <cite><a href=
-"http://www.w3.org/TR/REC-xml-names/" >Namespaces in XML</a></cite>
+"https://www.w3.org/TR/REC-xml-names/" >Namespaces in XML</a></cite>
specification is included.</dd>
-<dt>XML_UNICODE</dt>
+<dt><a name="XML_UNICODE">XML_UNICODE</a></dt>
<dd>When defined, character data reported to the application is
encoded in UTF-16 using wide characters of the type
<code>XML_Char</code>. This is implied if
<code>XML_UNICODE_WCHAR_T</code> is defined.</dd>
-<dt>XML_UNICODE_WCHAR_T</dt>
+<dt><a name="XML_UNICODE_WCHAR_T">XML_UNICODE_WCHAR_T</a></dt>
<dd>If defined, causes the <code>XML_Char</code> character type to be
defined using the <code>wchar_t</code> type; otherwise, <code>unsigned
short</code> is used. Defining this implies
<code>XML_UNICODE</code>.</dd>
-<dt>XML_LARGE_SIZE</dt>
+<dt><a name="XML_LARGE_SIZE">XML_LARGE_SIZE</a></dt>
<dd>If defined, causes the <code>XML_Size</code> and <code>XML_Index</code>
integer types to be at least 64 bits in size. This is intended to support
processing of very large input streams, where the return values of
@@ -358,23 +429,23 @@ processing of very large input streams, where the return values of
could overflow. It may not be supported by all compilers, and is turned
off by default.</dd>
-<dt>XML_CONTEXT_BYTES</dt>
+<dt><a name="XML_CONTEXT_BYTES">XML_CONTEXT_BYTES</a></dt>
<dd>The number of input bytes of markup context which the parser will
ensure are available for reporting via <code><a href=
"#XML_GetInputContext" >XML_GetInputContext</a></code>. This is
-normally set to 1024, and must be set to a positive integer. If this
-is not defined, the input context will not be available and <code><a
+normally set to 1024, and must be set to a positive integer to enable.
+If this is set to zero, the input context will not be available and <code><a
href= "#XML_GetInputContext" >XML_GetInputContext</a></code> will
-always report NULL. Without this, Expat has a smaller memory
+always report <code>NULL</code>. Without this, Expat has a smaller memory
footprint and can be faster.</dd>
-<dt>XML_STATIC</dt>
+<dt><a name="XML_STATIC">XML_STATIC</a></dt>
<dd>On Windows, this should be set if Expat is going to be linked
statically with the code that calls it; this is required to get all
the right MSVC magic annotations correct. This is ignored on other
platforms.</dd>
-<dt>XML_ATTR_INFO</dt>
+<dt><a name="XML_ATTR_INFO">XML_ATTR_INFO</a></dt>
<dd>If defined, makes the additional function <code><a href=
"#XML_GetAttributeInfo" >XML_GetAttributeInfo</a></code> available
for reporting attribute byte offsets.</dd>
@@ -628,8 +699,9 @@ function. The StartNamespaceDeclHandler is called prior to the start
tag handler and the EndNamespaceDeclHandler is called after the
corresponding end tag that ends the namespace's scope. The namespace
start handler gets passed the prefix and URI for the namespace. For a
-default namespace declaration (xmlns='...'), the prefix will be null.
-The URI will be null for the case where the default namespace is being
+default namespace declaration (xmlns='...'), the prefix will be
+<code>NULL</code>.
+The URI will be <code>NULL</code> for the case where the default namespace is being
unset. The namespace end handler just gets the prefix for the closing
scope.</p>
@@ -758,7 +830,7 @@ has already been passed into the parser. Applications for this
include</p>
<ul>
- <li>Supporting the <a href= "http://www.w3.org/TR/xinclude/"
+ <li>Supporting the <a href= "https://www.w3.org/TR/xinclude/"
>XInclude</a> specification.</li>
<li>Delaying further processing until additional information is
@@ -900,24 +972,30 @@ whether the parse can be resumed in the future.</p>
<h3><a name="creation">Parser Creation</a></h3>
-<pre class="fcndec" id="XML_ParserCreate">
+<h4 id="XML_ParserCreate">XML_ParserCreate</h4>
+<pre class="fcndec">
XML_Parser XMLCALL
XML_ParserCreate(const XML_Char *encoding);
</pre>
<div class="fcndef">
-Construct a new parser. If encoding is non-null, it specifies a
+<p>
+Construct a new parser. If encoding is non-<code>NULL</code>, it specifies a
character encoding to use for the document. This overrides the document
encoding declaration. There are four built-in encodings:
+</p>
<ul>
<li>US-ASCII</li>
<li>UTF-8</li>
<li>UTF-16</li>
<li>ISO-8859-1</li>
</ul>
+<p>
Any other value will invoke a call to the UnknownEncodingHandler.
+</p>
</div>
-<pre class="fcndec" id="XML_ParserCreateNS">
+<h4 id="XML_ParserCreateNS">XML_ParserCreateNS</h4>
+<pre class="fcndec">
XML_Parser XMLCALL
XML_ParserCreateNS(const XML_Char *encoding,
XML_Char sep);
@@ -936,7 +1014,16 @@ the local part will be concatenated without any separator - this is intended
to support RDF processors. It is a programming error to use the null separator
with <a href= "#XML_SetReturnNSTriplet">namespace triplets</a>.</div>
-<pre class="fcndec" id="XML_ParserCreate_MM">
+<p><strong>Note:</strong>
+Expat does not validate namespace URIs (beyond encoding)
+against RFC 3986 today (and is not required to do so with regard to
+the XML 1.0 namespaces specification) but it may start doing that
+in future releases. Before that, an application using Expat must
+be ready to receive namespace URIs containing non-URI characters.
+</p>
+
+<h4 id="XML_ParserCreate_MM">XML_ParserCreate_MM</h4>
+<pre class="fcndec">
XML_Parser XMLCALL
XML_ParserCreate_MM(const XML_Char *encoding,
const XML_Memory_Handling_Suite *ms,
@@ -951,14 +1038,15 @@ typedef struct {
</pre>
<div class="fcndef">
<p>Construct a new parser using the suite of memory handling functions
-specified in <code>ms</code>. If <code>ms</code> is NULL, then use the
+specified in <code>ms</code>. If <code>ms</code> is <code>NULL</code>, then use the
standard set of memory management functions. If <code>sep</code> is
-non NULL, then namespace processing is enabled in the created parser
+non-<code>NULL</code>, then namespace processing is enabled in the created parser
and the character pointed at by sep is used as the separator between
the namespace URI and the local part of the name.</p>
</div>
-<pre class="fcndec" id="XML_ExternalEntityParserCreate">
+<h4 id="XML_ExternalEntityParserCreate">XML_ExternalEntityParserCreate</h4>
+<pre class="fcndec">
XML_Parser XMLCALL
XML_ExternalEntityParserCreate(XML_Parser p,
const XML_Char *context,
@@ -974,7 +1062,8 @@ changing functions on this parser (unless you want it to act
differently than the parent parser).
</div>
-<pre class="fcndec" id="XML_ParserFree">
+<h4 id="XML_ParserFree">XML_ParserFree</h4>
+<pre class="fcndec">
void XMLCALL
XML_ParserFree(XML_Parser p);
</pre>
@@ -983,7 +1072,8 @@ Free memory used by the parser. Your application is responsible for
freeing any memory associated with <a href="#userdata">user data</a>.
</div>
-<pre class="fcndec" id="XML_ParserReset">
+<h4 id="XML_ParserReset">XML_ParserReset</h4>
+<pre class="fcndec">
XML_Bool XMLCALL
XML_ParserReset(XML_Parser p,
const XML_Char *encoding);
@@ -1014,7 +1104,7 @@ if they apply to the parser created by
<code><a href= "#XML_ExternalEntityParserCreate"
>XML_ExternalEntityParserCreate</a></code>.</p>
-<p>Note: the <code>len</code> argument passed to these functions
+<p>Note: The <code>len</code> argument passed to these functions
should be considerably less than the maximum value for an integer,
as it could create an integer overflow situation if the added
lengths of a buffer and the unprocessed portion of the previous buffer
@@ -1022,7 +1112,13 @@ exceed the maximum integer value. Input data at the end of a buffer
will remain unprocessed if it is part of an XML token for which the
end is not part of that buffer.</p>
-<pre class="fcndec" id="XML_Parse">
+<p><a name="isFinal"></a>The application <em>must</em> make a concluding
+<code><a href="#XML_Parse">XML_Parse</a></code> or
+<code><a href="#XML_ParseBuffer">XML_ParseBuffer</a></code> call
+with <code>isFinal</code> set to <code>XML_TRUE</code>.</p>
+
+<h4 id="XML_Parse">XML_Parse</h4>
+<pre class="fcndec">
enum XML_Status XMLCALL
XML_Parse(XML_Parser p,
const char *s,
@@ -1036,20 +1132,54 @@ enum XML_Status {
};
</pre>
<div class="fcndef">
+<p>
Parse some more of the document. The string <code>s</code> is a buffer
containing part (or perhaps all) of the document. The number of bytes of s
that are part of the document is indicated by <code>len</code>. This means
-that <code>s</code> doesn't have to be null terminated. It also means that
+that <code>s</code> doesn't have to be null-terminated. It also means that
if <code>len</code> is larger than the number of bytes in the block of
memory that <code>s</code> points at, then a memory fault is likely. The
<code>isFinal</code> parameter informs the parser that this is the last
piece of the document. Frequently, the last piece is empty (i.e.
<code>len</code> is zero.)
+</p>
+
+<p>
If a parse error occurred, it returns <code>XML_STATUS_ERROR</code>.
Otherwise it returns <code>XML_STATUS_OK</code> value.
+Note that regardless of the return value, there is no guarantee that all
+provided input has been parsed; only after <a href="#isFinal">the
+concluding call</a> will all handler callbacks and parsing errors have
+happened.
+</p>
+
+<p>
+Simplified, <code>XML_Parse</code> can be considered a convenience wrapper
+that is pairing calls
+to <code><a href="#XML_GetBuffer">XML_GetBuffer</a></code>
+and <code><a href="#XML_ParseBuffer">XML_ParseBuffer</a></code>
+(when Expat is built with macro <code>XML_CONTEXT_BYTES</code>
+defined to a positive value, which is both common and default).
+<code>XML_Parse</code> is then functionally equivalent to calling
+<code><a href="#XML_GetBuffer">XML_GetBuffer</a></code>,
+<code>memcpy</code>, and
+<code><a href="#XML_ParseBuffer">XML_ParseBuffer</a></code>.
+</p>
+
+<p>
+To avoid double copying of the input, direct use of functions
+<code><a href="#XML_GetBuffer">XML_GetBuffer</a></code> and
+<code><a href="#XML_ParseBuffer">XML_ParseBuffer</a></code> is advised
+for most production use, e.g.
+if you're using <code>read</code> or similar functionality to fill your
+buffers, fill directly into the buffer from
+<code><a href="#XML_GetBuffer">XML_GetBuffer</a></code>,
+then parse with <code><a href="#XML_ParseBuffer">XML_ParseBuffer</a></code>.
+</p>
</div>
-<pre class="fcndec" id="XML_ParseBuffer">
+<h4 id="XML_ParseBuffer">XML_ParseBuffer</h4>
+<pre class="fcndec">
enum XML_Status XMLCALL
XML_ParseBuffer(XML_Parser p,
int len,
@@ -1063,15 +1193,17 @@ buffer from Expat with the <code><a href= "#XML_GetBuffer"
copying of the input.
</div>
-<pre class="fcndec" id="XML_GetBuffer">
+<h4 id="XML_GetBuffer">XML_GetBuffer</h4>
+<pre class="fcndec">
void * XMLCALL
XML_GetBuffer(XML_Parser p,
int len);
</pre>
<div class="fcndef">
Obtain a buffer of size <code>len</code> to read a piece of the document
-into. A NULL value is returned if Expat can't allocate enough memory for
-this buffer. This has to be called prior to every call to
+into. A <code>NULL</code> value is returned if Expat can't allocate enough memory for
+this buffer. A <code>NULL</code> value may also be returned if <code>len</code> is zero.
+This has to be called prior to every call to
<code><a href= "#XML_ParseBuffer" >XML_ParseBuffer</a></code>. A
typical use would look like this:
@@ -1098,7 +1230,8 @@ for (;;) {
</pre>
</div>
-<pre class="fcndec" id="XML_StopParser">
+<h4 id="XML_StopParser">XML_StopParser</h4>
+<pre class="fcndec">
enum XML_Status XMLCALL
XML_StopParser(XML_Parser p,
XML_Bool resumable);
@@ -1111,7 +1244,7 @@ XML_StopParser(XML_Parser p,
call-back handler, except when aborting (when <code>resumable</code>
is <code>XML_FALSE</code>) an already suspended parser. Some
call-backs may still follow because they would otherwise get
-lost, including
+lost, including</p>
<ul>
<li> the end element handler for empty elements when stopped in the
start element handler,</li>
@@ -1120,7 +1253,7 @@ lost, including
<li> the character data handler when stopped in the character data handler
while making multiple call-backs on a contiguous chunk of characters,</li>
</ul>
-and possibly others.</p>
+<p>and possibly others.</p>
<p>This can be called from most handlers, including DTD related
call-backs, except when parsing an external parameter entity and
@@ -1166,7 +1299,8 @@ implementation of that handler to call <code><a href=
<p>New in Expat 1.95.8.</p>
</div>
-<pre class="fcndec" id="XML_ResumeParser">
+<h4 id="XML_ResumeParser">XML_ResumeParser</h4>
+<pre class="fcndec">
enum XML_Status XMLCALL
XML_ResumeParser(XML_Parser p);
</pre>
@@ -1191,7 +1325,8 @@ appropriate moment.</p>
<p>New in Expat 1.95.8.</p>
</div>
-<pre class="fcndec" id="XML_GetParsingStatus">
+<h4 id="XML_GetParsingStatus">XML_GetParsingStatus</h4>
+<pre class="fcndec">
void XMLCALL
XML_GetParsingStatus(XML_Parser p,
XML_ParsingStatus *status);
@@ -1213,7 +1348,7 @@ typedef struct {
<p>Returns status of parser with respect to being initialized,
parsing, finished, or suspended, and whether the final buffer is being
processed. The <code>status</code> parameter <em>must not</em> be
-NULL.</p>
+<code>NULL</code>.</p>
<p>New in Expat 1.95.8.</p>
</div>
@@ -1228,7 +1363,7 @@ to ignore all text not descended from a <code>para</code> element. One
way it could do this is to set the character handler when a para start tag
is seen, and unset it for the corresponding end tag.</p>
-<p>A handler may be <em>unset</em> by providing a NULL pointer to the
+<p>A handler may be <em>unset</em> by providing a <code>NULL</code> pointer to the
appropriate handler setter. None of the handler setting functions have
a return value.</p>
@@ -1240,7 +1375,8 @@ Note that you'll receive them in this form independent of the original
encoding of the document.</p>
<div class="handler">
-<pre class="setter" id="XML_SetStartElementHandler">
+<h4 id="XML_SetStartElementHandler">XML_SetStartElementHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetStartElementHandler(XML_Parser p,
XML_StartElementHandler start);
@@ -1255,13 +1391,14 @@ typedef void
handler as a pointer to a vector of char pointers. Each attribute seen in
a start (or empty) tag occupies 2 consecutive places in this vector: the
attribute name followed by the attribute value. These pairs are terminated
-by a null pointer.</p>
+by a <code>NULL</code> pointer.</p>
<p>Note that an empty tag generates a call to both start and end handlers
(in that order).</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetEndElementHandler">
+<h4 id="XML_SetEndElementHandler">XML_SetEndElementHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetEndElementHandler(XML_Parser p,
XML_EndElementHandler);
@@ -1276,7 +1413,8 @@ generates a call to both start and end handlers.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetElementHandler">
+<h4 id="XML_SetElementHandler">XML_SetElementHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetElementHandler(XML_Parser p,
XML_StartElementHandler start,
@@ -1286,7 +1424,8 @@ XML_SetElementHandler(XML_Parser p,
</div>
<div class="handler">
-<pre class="setter" id="XML_SetCharacterDataHandler">
+<h4 id="XML_SetCharacterDataHandler">XML_SetCharacterDataHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetCharacterDataHandler(XML_Parser p,
XML_CharacterDataHandler charhndl)
@@ -1298,18 +1437,19 @@ typedef void
int len);
</pre>
<p>Set a text handler. The string your handler receives
-is <em>NOT nul-terminated</em>. You have to use the length argument
+is <em>NOT null-terminated</em>. You have to use the length argument
to deal with the end of the string. A single block of contiguous text
free of markup may still result in a sequence of calls to this handler.
In other words, if you're searching for a pattern in the text, it may
-be split across calls to this handler. Note: Setting this handler to NULL
+be split across calls to this handler. Note: Setting this handler to <code>NULL</code>
may <em>NOT immediately</em> terminate call-backs if the parser is currently
processing such a single block of contiguous markup-free text, as the parser
will continue calling back until the end of the block is reached.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetProcessingInstructionHandler">
+<h4 id="XML_SetProcessingInstructionHandler">XML_SetProcessingInstructionHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetProcessingInstructionHandler(XML_Parser p,
XML_ProcessingInstructionHandler proc)
@@ -1327,7 +1467,8 @@ it after skipping all whitespace after the initial word.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetCommentHandler">
+<h4 id="XML_SetCommentHandler">XML_SetCommentHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetCommentHandler(XML_Parser p,
XML_CommentHandler cmnt)
@@ -1342,7 +1483,8 @@ delimiters.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetStartCdataSectionHandler">
+<h4 id="XML_SetStartCdataSectionHandler">XML_SetStartCdataSectionHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetStartCdataSectionHandler(XML_Parser p,
XML_StartCdataSectionHandler start);
@@ -1355,7 +1497,8 @@ typedef void
</div>
<div class="handler">
-<pre class="setter" id="XML_SetEndCdataSectionHandler">
+<h4 id="XML_SetEndCdataSectionHandler">XML_SetEndCdataSectionHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetEndCdataSectionHandler(XML_Parser p,
XML_EndCdataSectionHandler end);
@@ -1368,7 +1511,8 @@ typedef void
</div>
<div class="handler">
-<pre class="setter" id="XML_SetCdataSectionHandler">
+<h4 id="XML_SetCdataSectionHandler">XML_SetCdataSectionHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetCdataSectionHandler(XML_Parser p,
XML_StartCdataSectionHandler start,
@@ -1378,7 +1522,8 @@ XML_SetCdataSectionHandler(XML_Parser p,
</div>
<div class="handler">
-<pre class="setter" id="XML_SetDefaultHandler">
+<h4 id="XML_SetDefaultHandler">XML_SetDefaultHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetDefaultHandler(XML_Parser p,
XML_DefaultHandler hndl)
@@ -1409,7 +1554,8 @@ href="#XML_DefaultCurrent">XML_DefaultCurrent</a></code>.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetDefaultHandlerExpand">
+<h4 id="XML_SetDefaultHandlerExpand">XML_SetDefaultHandlerExpand</h4>
+<pre class="setter">
void XMLCALL
XML_SetDefaultHandlerExpand(XML_Parser p,
XML_DefaultHandler hndl)
@@ -1429,7 +1575,8 @@ href="#XML_DefaultCurrent">XML_DefaultCurrent</a></code>.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetExternalEntityRefHandler">
+<h4 id="XML_SetExternalEntityRefHandler">XML_SetExternalEntityRefHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetExternalEntityRefHandler(XML_Parser p,
XML_ExternalEntityRefHandler hndl)
@@ -1452,16 +1599,16 @@ the format expected by the <code>context</code> argument to <code><a
href="#XML_ExternalEntityParserCreate"
>XML_ExternalEntityParserCreate</a></code>. <code>code</code> is
valid only until the handler returns, so if the referenced entity is
-to be parsed later, it must be copied. <code>context</code> is NULL
+to be parsed later, it must be copied. <code>context</code> is <code>NULL</code>
only when the entity is a parameter entity, which is how one can
differentiate between general and parameter entities.</p>
<p>The <code>base</code> parameter is the base to use for relative
system identifiers. It is set by <code><a
-href="#XML_SetBase">XML_SetBase</a></code> and may be NULL. The
+href="#XML_SetBase">XML_SetBase</a></code> and may be <code>NULL</code>. The
<code>publicId</code> parameter is the public id given in the entity
-declaration and may be NULL. <code>systemId</code> is the system
-identifier specified in the entity declaration and is never NULL.</p>
+declaration and may be <code>NULL</code>. <code>systemId</code> is the system
+identifier specified in the entity declaration and is never <code>NULL</code>.</p>
<p>There are a couple of ways in which this handler differs from
others. First, this handler returns a status indicator (an
@@ -1482,17 +1629,18 @@ parser, the body of the external entity can be recursively parsed.</p>
information into global or static variables.</p>
</div>
-<pre class="fcndec" id="XML_SetExternalEntityRefHandlerArg">
+<h4 id="XML_SetExternalEntityRefHandlerArg">XML_SetExternalEntityRefHandlerArg</h4>
+<pre class="fcndec">
void XMLCALL
XML_SetExternalEntityRefHandlerArg(XML_Parser p,
void *arg)
</pre>
<div class="fcndef">
<p>Set the argument passed to the ExternalEntityRefHandler. If
-<code>arg</code> is not NULL, it is the new value passed to the
+<code>arg</code> is not <code>NULL</code>, it is the new value passed to the
handler set using <code><a href="#XML_SetExternalEntityRefHandler"
>XML_SetExternalEntityRefHandler</a></code>; if <code>arg</code> is
-NULL, the argument passed to the handler function will be the parser
+<code>NULL</code>, the argument passed to the handler function will be the parser
object itself.</p>
<p><strong>Note:</strong>
@@ -1508,7 +1656,8 @@ properly.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetSkippedEntityHandler">
+<h4 id="XML_SetSkippedEntityHandler">XML_SetSkippedEntityHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetSkippedEntityHandler(XML_Parser p,
XML_SkippedEntityHandler handler)
@@ -1528,14 +1677,15 @@ typedef void
has been called.</li>
</ol>
<p>The <code>is_parameter_entity</code> argument will be non-zero for
-a parameter entity and zero for a general entity.</p> <p>Note: skipped
+a parameter entity and zero for a general entity.</p> <p>Note: Skipped
parameter entities in declarations and skipped general entities in
attribute values cannot be reported, because the event would be out of
sync with the reporting of the declarations or attribute values</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetUnknownEncodingHandler">
+<h4 id="XML_SetUnknownEncodingHandler">XML_SetUnknownEncodingHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetUnknownEncodingHandler(XML_Parser p,
XML_UnknownEncodingHandler enchandler,
@@ -1573,18 +1723,19 @@ value is -1, then that byte is invalid as the initial byte in a sequence.
If the value is -n, where n is an integer &gt; 1, then n is the number of
bytes in the sequence and the actual conversion is accomplished by a
call to the function pointed at by convert. This function may return -1
-if the sequence itself is invalid. The convert pointer may be null if
+if the sequence itself is invalid. The convert pointer may be <code>NULL</code> if
there are only single byte codes. The data parameter passed to the convert
function is the data pointer from <code>XML_Encoding</code>. The
-string s is <em>NOT</em> nul-terminated and points at the sequence of
+string s is <em>NOT</em> null-terminated and points at the sequence of
bytes to be converted.</p>
<p>The function pointed at by <code>release</code> is called by the
-parser when it is finished with the encoding. It may be NULL.</p>
+parser when it is finished with the encoding. It may be <code>NULL</code>.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetStartNamespaceDeclHandler">
+<h4 id="XML_SetStartNamespaceDeclHandler">XML_SetStartNamespaceDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetStartNamespaceDeclHandler(XML_Parser p,
XML_StartNamespaceDeclHandler start);
@@ -1602,7 +1753,8 @@ in that start tag.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetEndNamespaceDeclHandler">
+<h4 id="XML_SetEndNamespaceDeclHandler">XML_SetEndNamespaceDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetEndNamespaceDeclHandler(XML_Parser p,
XML_EndNamespaceDeclHandler end);
@@ -1619,7 +1771,8 @@ namespace was declared.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetNamespaceDeclHandler">
+<h4 id="XML_SetNamespaceDeclHandler">XML_SetNamespaceDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetNamespaceDeclHandler(XML_Parser p,
XML_StartNamespaceDeclHandler start,
@@ -1629,7 +1782,8 @@ XML_SetNamespaceDeclHandler(XML_Parser p,
</div>
<div class="handler">
-<pre class="setter" id="XML_SetXmlDeclHandler">
+<h4 id="XML_SetXmlDeclHandler">XML_SetXmlDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetXmlDeclHandler(XML_Parser p,
XML_XmlDeclHandler xmldecl);
@@ -1643,8 +1797,8 @@ typedef void
</pre>
<p>Sets a handler that is called for XML declarations and also for
text declarations discovered in external entities. The way to
-distinguish is that the <code>version</code> parameter will be NULL
-for text declarations. The <code>encoding</code> parameter may be NULL
+distinguish is that the <code>version</code> parameter will be <code>NULL</code>
+for text declarations. The <code>encoding</code> parameter may be <code>NULL</code>
for an XML declaration. The <code>standalone</code> argument will
contain -1, 0, or 1 indicating respectively that there was no
standalone parameter in the declaration, that it was given as no, or
@@ -1652,7 +1806,8 @@ that it was given as yes.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetStartDoctypeDeclHandler">
+<h4 id="XML_SetStartDoctypeDeclHandler">XML_SetStartDoctypeDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetStartDoctypeDeclHandler(XML_Parser p,
XML_StartDoctypeDeclHandler start);
@@ -1667,12 +1822,13 @@ typedef void
</pre>
<p>Set a handler that is called at the start of a DOCTYPE declaration,
before any external or internal subset is parsed. Both <code>sysid</code>
-and <code>pubid</code> may be NULL. The <code>has_internal_subset</code>
+and <code>pubid</code> may be <code>NULL</code>. The <code>has_internal_subset</code>
will be non-zero if the DOCTYPE declaration has an internal subset.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetEndDoctypeDeclHandler">
+<h4 id="XML_SetEndDoctypeDeclHandler">XML_SetEndDoctypeDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetEndDoctypeDeclHandler(XML_Parser p,
XML_EndDoctypeDeclHandler end);
@@ -1686,7 +1842,8 @@ after parsing any external subset.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetDoctypeDeclHandler">
+<h4 id="XML_SetDoctypeDeclHandler">XML_SetDoctypeDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetDoctypeDeclHandler(XML_Parser p,
XML_StartDoctypeDeclHandler start,
@@ -1696,7 +1853,8 @@ XML_SetDoctypeDeclHandler(XML_Parser p,
</div>
<div class="handler">
-<pre class="setter" id="XML_SetElementDeclHandler">
+<h4 id="XML_SetElementDeclHandler">XML_SetElementDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetElementDeclHandler(XML_Parser p,
XML_ElementDeclHandler eldecl);
@@ -1736,16 +1894,17 @@ struct XML_cp {
</pre>
<p>Sets a handler for element declarations in a DTD. The handler gets
called with the name of the element in the declaration and a pointer
-to a structure that contains the element model. It is the
-application's responsibility to free this data structure using
-<code><a href="#XML_FreeContentModel"
->XML_FreeContentModel</a></code>.</p>
+to a structure that contains the element model. It's the user code's
+responsibility to free model when finished with it. See <code>
+<a href="#XML_FreeContentModel">XML_FreeContentModel</a></code>.
+There is no need to free the model from the handler, it can be kept
+around and freed at a later stage.</p>
<p>The <code>model</code> argument is the root of a tree of
<code>XML_Content</code> nodes. If <code>type</code> equals
<code>XML_CTYPE_EMPTY</code> or <code>XML_CTYPE_ANY</code>, then
<code>quant</code> will be <code>XML_CQUANT_NONE</code>, and the other
-fields will be zero or NULL. If <code>type</code> is
+fields will be zero or <code>NULL</code>. If <code>type</code> is
<code>XML_CTYPE_MIXED</code>, then <code>quant</code> will be
<code>XML_CQUANT_NONE</code> or <code>XML_CQUANT_REP</code> and
<code>numchildren</code> will contain the number of elements that are
@@ -1757,7 +1916,7 @@ XML_CTYPE_NAME with no quantification. Only the root node can be type
<p>For type <code>XML_CTYPE_NAME</code>, the <code>name</code> field
points to the name and the <code>numchildren</code> and
-<code>children</code> fields will be zero and NULL. The
+<code>children</code> fields will be zero and <code>NULL</code>. The
<code>quant</code> field will indicate any quantifiers placed on the
name.</p>
@@ -1768,7 +1927,8 @@ or sequence and <code>children</code> points to the nodes.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetAttlistDeclHandler">
+<h4 id="XML_SetAttlistDeclHandler">XML_SetAttlistDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetAttlistDeclHandler(XML_Parser p,
XML_AttlistDeclHandler attdecl);
@@ -1792,16 +1952,17 @@ is in the <code>attname</code> parameter. The attribute type is in the
type in the declaration with whitespace removed.</p>
<p>The <code>dflt</code> parameter holds the default value. It will be
-NULL in the case of "#IMPLIED" or "#REQUIRED" attributes. You can
+<code>NULL</code> in the case of "#IMPLIED" or "#REQUIRED" attributes. You can
distinguish these two cases by checking the <code>isrequired</code>
parameter, which will be true in the case of "#REQUIRED" attributes.
Attributes which are "#FIXED" will have also have a true
-<code>isrequired</code>, but they will have the non-NULL fixed value
+<code>isrequired</code>, but they will have the non-<code>NULL</code> fixed value
in the <code>dflt</code> parameter.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetEntityDeclHandler">
+<h4 id="XML_SetEntityDeclHandler">XML_SetEntityDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetEntityDeclHandler(XML_Parser p,
XML_EntityDeclHandler handler);
@@ -1823,19 +1984,20 @@ The <code>is_parameter_entity</code> argument will be non-zero in the
case of parameter entities and zero otherwise.</p>
<p>For internal entities (<code>&lt;!ENTITY foo "bar"&gt;</code>),
-<code>value</code> will be non-NULL and <code>systemId</code>,
-<code>publicId</code>, and <code>notationName</code> will all be NULL.
-The value string is <em>not</em> NULL terminated; the length is
+<code>value</code> will be non-<code>NULL</code> and <code>systemId</code>,
+<code>publicId</code>, and <code>notationName</code> will all be <code>NULL</code>.
+The value string is <em>not</em> null-terminated; the length is
provided in the <code>value_length</code> parameter. Do not use
<code>value_length</code> to test for internal entities, since it is
legal to have zero-length values. Instead check for whether or not
-<code>value</code> is NULL.</p> <p>The <code>notationName</code>
-argument will have a non-NULL value only for unparsed entity
+<code>value</code> is <code>NULL</code>.</p> <p>The <code>notationName</code>
+argument will have a non-<code>NULL</code> value only for unparsed entity
declarations.</p>
</div>
<div class="handler">
-<pre class="setter" id="XML_SetUnparsedEntityDeclHandler">
+<h4 id="XML_SetUnparsedEntityDeclHandler">XML_SetUnparsedEntityDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetUnparsedEntityDeclHandler(XML_Parser p,
XML_UnparsedEntityDeclHandler h)
@@ -1861,7 +2023,8 @@ compatibility. Use instead <a href= "#XML_SetEntityDeclHandler"
</div>
<div class="handler">
-<pre class="setter" id="XML_SetNotationDeclHandler">
+<h4 id="XML_SetNotationDeclHandler">XML_SetNotationDeclHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetNotationDeclHandler(XML_Parser p,
XML_NotationDeclHandler h)
@@ -1878,7 +2041,8 @@ typedef void
</div>
<div class="handler">
-<pre class="setter" id="XML_SetNotStandaloneHandler">
+<h4 id="XML_SetNotStandaloneHandler">XML_SetNotStandaloneHandler</h4>
+<pre class="setter">
void XMLCALL
XML_SetNotStandaloneHandler(XML_Parser p,
XML_NotStandaloneHandler h)
@@ -1904,7 +2068,7 @@ of errors. The position reported is the byte position (in the original
document or entity encoding) of the first of the sequence of
characters that generated the current event (or the error that caused
the parse functions to return <code>XML_STATUS_ERROR</code>.) The
-exceptions are callbacks trigged by declarations in the document
+exceptions are callbacks triggered by declarations in the document
prologue, in which case they exact position reported is somewhere in the
relevant markup, but not necessarily as meaningful as for other
events.</p>
@@ -1913,7 +2077,8 @@ events.</p>
DTD. In other words, they usually return bogus information when
called from within a DTD declaration handler.</p>
-<pre class="fcndec" id="XML_GetErrorCode">
+<h4 id="XML_GetErrorCode">XML_GetErrorCode</h4>
+<pre class="fcndec">
enum XML_Error XMLCALL
XML_GetErrorCode(XML_Parser p);
</pre>
@@ -1921,7 +2086,8 @@ XML_GetErrorCode(XML_Parser p);
Return what type of error has occurred.
</div>
-<pre class="fcndec" id="XML_ErrorString">
+<h4 id="XML_ErrorString">XML_ErrorString</h4>
+<pre class="fcndec">
const XML_LChar * XMLCALL
XML_ErrorString(enum XML_Error code);
</pre>
@@ -1931,7 +2097,8 @@ The code should be one of the enums that can be returned from
<code><a href= "#XML_GetErrorCode" >XML_GetErrorCode</a></code>.
</div>
-<pre class="fcndec" id="XML_GetCurrentByteIndex">
+<h4 id="XML_GetCurrentByteIndex">XML_GetCurrentByteIndex</h4>
+<pre class="fcndec">
XML_Index XMLCALL
XML_GetCurrentByteIndex(XML_Parser p);
</pre>
@@ -1942,7 +2109,8 @@ the values returned by <code><a href= "#XML_GetCurrentLineNumber"
"#XML_GetCurrentColumnNumber" >XML_GetCurrentColumnNumber</a></code>.
</div>
-<pre class="fcndec" id="XML_GetCurrentLineNumber">
+<h4 id="XML_GetCurrentLineNumber">XML_GetCurrentLineNumber</h4>
+<pre class="fcndec">
XML_Size XMLCALL
XML_GetCurrentLineNumber(XML_Parser p);
</pre>
@@ -1951,7 +2119,8 @@ Return the line number of the position. The first line is reported as
<code>1</code>.
</div>
-<pre class="fcndec" id="XML_GetCurrentColumnNumber">
+<h4 id="XML_GetCurrentColumnNumber">XML_GetCurrentColumnNumber</h4>
+<pre class="fcndec">
XML_Size XMLCALL
XML_GetCurrentColumnNumber(XML_Parser p);
</pre>
@@ -1960,7 +2129,8 @@ Return the offset, from the beginning of the current line, of
the position.
</div>
-<pre class="fcndec" id="XML_GetCurrentByteCount">
+<h4 id="XML_GetCurrentByteCount">XML_GetCurrentByteCount</h4>
+<pre class="fcndec">
int XMLCALL
XML_GetCurrentByteCount(XML_Parser p);
</pre>
@@ -1972,7 +2142,8 @@ be used to distinguish empty-element tags from empty elements using
separate start and end tags).
</div>
-<pre class="fcndec" id="XML_GetInputContext">
+<h4 id="XML_GetInputContext">XML_GetInputContext</h4>
+<pre class="fcndec">
const char * XMLCALL
XML_GetInputContext(XML_Parser p,
int *offset,
@@ -1994,8 +2165,117 @@ untranslated bytes of the input.</p>
triggering a call spans over a very large amount of input, the actual
parse position may be before the beginning of the buffer.</p>
-<p>If <code>XML_CONTEXT_BYTES</code> is not defined, this will always
-return NULL.</p>
+<p>If <code>XML_CONTEXT_BYTES</code> is zero, this will always
+return <code>NULL</code>.</p>
+</div>
+
+<h3><a name="attack-protection">Attack Protection</a><a name="billion-laughs"></a></h3>
+
+<h4 id="XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</h4>
+<pre class="fcndec">
+/* Added in Expat 2.4.0. */
+XML_Bool XMLCALL
+XML_SetBillionLaughsAttackProtectionMaximumAmplification(XML_Parser p,
+ float maximumAmplificationFactor);
+</pre>
+<div class="fcndef">
+ <p>
+ Sets the maximum tolerated amplification factor
+ for protection against
+ <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
+ (default: <code>100.0</code>)
+ of parser <code>p</code> to <code>maximumAmplificationFactor</code>, and
+ returns <code>XML_TRUE</code> upon success and <code>XML_FALSE</code> upon error.
+ </p>
+
+ The amplification factor is calculated as ..
+ <pre>
+ amplification := (direct + indirect) / direct
+ </pre>
+ .. while parsing, whereas
+ <code>direct</code> is the number of bytes read from the primary document in parsing and
+ <code>indirect</code> is the number of bytes added by expanding entities and reading of external DTD files, combined.
+
+ <p>For a call to <code>XML_SetBillionLaughsAttackProtectionMaximumAmplification</code> to succeed:</p>
+ <ul>
+ <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers) and</li>
+ <li><code>maximumAmplificationFactor</code> must be non-<code>NaN</code> and greater than or equal to <code>1.0</code>.</li>
+ </ul>
+
+ <p>
+ <strong>Note:</strong>
+ If you ever need to increase this value for non-attack payload,
+ please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
+ </p>
+
+ <p>
+ <strong>Note:</strong>
+ Peak amplifications
+ of factor 15,000 for the entire payload and
+ of factor 30,000 in the middle of parsing
+ have been observed with small benign files in practice.
+
+ So if you do reduce the maximum allowed amplification,
+ please make sure that the activation threshold is still big enough
+ to not end up with undesired false positives (i.e. benign files being rejected).
+ </p>
+</div>
+
+<h4 id="XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</h4>
+<pre class="fcndec">
+/* Added in Expat 2.4.0. */
+XML_Bool XMLCALL
+XML_SetBillionLaughsAttackProtectionActivationThreshold(XML_Parser p,
+ unsigned long long activationThresholdBytes);
+</pre>
+<div class="fcndef">
+ <p>
+ Sets number of output bytes (including amplification from entity expansion and reading DTD files)
+ needed to activate protection against
+ <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
+ (default: <code>8 MiB</code>)
+ of parser <code>p</code> to <code>activationThresholdBytes</code>, and
+ returns <code>XML_TRUE</code> upon success and <code>XML_FALSE</code> upon error.
+ </p>
+
+ <p>For a call to <code>XML_SetBillionLaughsAttackProtectionActivationThreshold</code> to succeed:</p>
+ <ul>
+ <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers).</li>
+ </ul>
+
+ <p>
+ <strong>Note:</strong>
+ If you ever need to increase this value for non-attack payload,
+ please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
+ </p>
+
+ <p>
+ <strong>Note:</strong>
+ Activation thresholds below 4 MiB are known to break support for
+ <a href="https://en.wikipedia.org/wiki/Darwin_Information_Typing_Architecture">DITA</a> 1.3 payload
+ and are hence not recommended.
+ </p>
+</div>
+
+<h4 id="XML_SetReparseDeferralEnabled">XML_SetReparseDeferralEnabled</h4>
+<pre class="fcndec">
+/* Added in Expat 2.6.0. */
+XML_Bool XMLCALL
+XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
+</pre>
+<div class="fcndef">
+ <p>
+ Large tokens may require many parse calls before enough data is available for Expat to parse it in full.
+ If Expat retried parsing the token on every parse call, parsing could take quadratic time.
+ To avoid this, Expat only retries once a significant amount of new data is available.
+ This function allows disabling this behavior.
+ </p>
+ <p>
+ The <code>enabled</code> argument should be <code>XML_TRUE</code> or <code>XML_FALSE</code>.
+ </p>
+ <p>
+ Returns <code>XML_TRUE</code> on success, and <code>XML_FALSE</code> on error.
+ </p>
</div>
<h3><a name="miscellaneous">Miscellaneous functions</a></h3>
@@ -2003,7 +2283,8 @@ return NULL.</p>
<p>The functions in this section either obtain state information from
the parser or can be used to dynamically set parser options.</p>
-<pre class="fcndec" id="XML_SetUserData">
+<h4 id="XML_SetUserData">XML_SetUserData</h4>
+<pre class="fcndec">
void XMLCALL
XML_SetUserData(XML_Parser p,
void *userData);
@@ -2018,7 +2299,8 @@ the memory associated with it, then you've probably just leaked
memory.
</div>
-<pre class="fcndec" id="XML_GetUserData">
+<h4 id="XML_GetUserData">XML_GetUserData</h4>
+<pre class="fcndec">
void * XMLCALL
XML_GetUserData(XML_Parser p);
</pre>
@@ -2027,7 +2309,8 @@ This returns the user data pointer that gets passed to handlers.
It is actually implemented as a macro.
</div>
-<pre class="fcndec" id="XML_UseParserAsHandlerArg">
+<h4 id="XML_UseParserAsHandlerArg">XML_UseParserAsHandlerArg</h4>
+<pre class="fcndec">
void XMLCALL
XML_UseParserAsHandlerArg(XML_Parser p);
</pre>
@@ -2038,7 +2321,8 @@ using the <code><a href= "#XML_GetUserData"
>XML_GetUserData</a></code> function.
</div>
-<pre class="fcndec" id="XML_SetBase">
+<h4 id="XML_SetBase">XML_SetBase</h4>
+<pre class="fcndec">
enum XML_Status XMLCALL
XML_SetBase(XML_Parser p,
const XML_Char *base);
@@ -2050,7 +2334,8 @@ there's no memory to store base, otherwise it's
<code>XML_STATUS_OK</code>.
</div>
-<pre class="fcndec" id="XML_GetBase">
+<h4 id="XML_GetBase">XML_GetBase</h4>
+<pre class="fcndec">
const XML_Char * XMLCALL
XML_GetBase(XML_Parser p);
</pre>
@@ -2058,7 +2343,8 @@ XML_GetBase(XML_Parser p);
Return the base for resolving relative URIs.
</div>
-<pre class="fcndec" id="XML_GetSpecifiedAttributeCount">
+<h4 id="XML_GetSpecifiedAttributeCount">XML_GetSpecifiedAttributeCount</h4>
+<pre class="fcndec">
int XMLCALL
XML_GetSpecifiedAttributeCount(XML_Parser p);
</pre>
@@ -2074,7 +2360,8 @@ call to a start handler. If called inside a start handler, then that
means the current call.
</div>
-<pre class="fcndec" id="XML_GetIdAttributeIndex">
+<h4 id="XML_GetIdAttributeIndex">XML_GetIdAttributeIndex</h4>
+<pre class="fcndec">
int XMLCALL
XML_GetIdAttributeIndex(XML_Parser p);
</pre>
@@ -2086,7 +2373,8 @@ attribute. If called inside a start handler, then that means the
current call.
</div>
-<pre class="fcndec" id="XML_GetAttributeInfo">
+<h4 id="XML_GetAttributeInfo">XML_GetAttributeInfo</h4>
+<pre class="fcndec">
const XML_AttrInfo * XMLCALL
XML_GetAttributeInfo(XML_Parser parser);
</pre>
@@ -2107,14 +2395,15 @@ as 1; thus the number of entries in the array is
<code>XML_GetSpecifiedAttributeCount(parser) / 2</code>.
</div>
-<pre class="fcndec" id="XML_SetEncoding">
+<h4 id="XML_SetEncoding">XML_SetEncoding</h4>
+<pre class="fcndec">
enum XML_Status XMLCALL
XML_SetEncoding(XML_Parser p,
const XML_Char *encoding);
</pre>
<div class="fcndef">
Set the encoding to be used by the parser. It is equivalent to
-passing a non-null encoding argument to the parser creation functions.
+passing a non-<code>NULL</code> encoding argument to the parser creation functions.
It must not be called after <code><a href= "#XML_Parse"
>XML_Parse</a></code> or <code><a href= "#XML_ParseBuffer"
>XML_ParseBuffer</a></code> have been called on the given parser.
@@ -2122,7 +2411,8 @@ Returns <code>XML_STATUS_OK</code> on success or
<code>XML_STATUS_ERROR</code> on error.
</div>
-<pre class="fcndec" id="XML_SetParamEntityParsing">
+<h4 id="XML_SetParamEntityParsing">XML_SetParamEntityParsing</h4>
+<pre class="fcndec">
int XMLCALL
XML_SetParamEntityParsing(XML_Parser p,
enum XML_ParamEntityParsing code);
@@ -2142,7 +2432,8 @@ The choices for <code>code</code> are:
no effect and will always return 0.
</div>
-<pre class="fcndec" id="XML_SetHashSalt">
+<h4 id="XML_SetHashSalt">XML_SetHashSalt</h4>
+<pre class="fcndec">
int XMLCALL
XML_SetHashSalt(XML_Parser p,
unsigned long hash_salt);
@@ -2153,15 +2444,16 @@ Helps in preventing DoS attacks based on predicting hash
function behavior. In order to have an effect this must be called
before parsing has started. Returns 1 if successful, 0 when called
after <code>XML_Parse</code> or <code>XML_ParseBuffer</code>.
-<p><b>Note:</b>This call is optional, as the parser will auto-generate
+<p><b>Note:</b> This call is optional, as the parser will auto-generate
a new random salt value if no value has been set at the start of parsing.</p>
-<p><b>Note:</b>One should not call <code>XML_SetHashSalt</code> with a
+<p><b>Note:</b> One should not call <code>XML_SetHashSalt</code> with a
hash salt value of 0, as this value is used as sentinel value to indicate
that <code>XML_SetHashSalt</code> has <b>not</b> been called. Consequently
such a call will have no effect, even if it returns 1.</p>
</div>
-<pre class="fcndec" id="XML_UseForeignDTD">
+<h4 id="XML_UseForeignDTD">XML_UseForeignDTD</h4>
+<pre class="fcndec">
enum XML_Error XMLCALL
XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
</pre>
@@ -2183,7 +2475,7 @@ called. The setting of parameter entity parsing, controlled using
external entity reference handler set via <code><a href=
"#XML_SetExternalEntityRefHandler"
>XML_SetExternalEntityRefHandler</a></code> with both
-<code>publicId</code> and <code>systemId</code> set to NULL.</p>
+<code>publicId</code> and <code>systemId</code> set to <code>NULL</code>.</p>
<p>If this function is called after parsing has begun, it returns
<code>XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING</code> and ignores
@@ -2198,7 +2490,8 @@ the document had a DTD with an external subset. This holds true even if
the external entity reference handler returns without action.</p>
</div>
-<pre class="fcndec" id="XML_SetReturnNSTriplet">
+<h4 id="XML_SetReturnNSTriplet">XML_SetReturnNSTriplet</h4>
+<pre class="fcndec">
void XMLCALL
XML_SetReturnNSTriplet(XML_Parser parser,
int do_nst);
@@ -2220,7 +2513,8 @@ default manner, URI then local_name separated by the namespace
separator.</p>
</div>
-<pre class="fcndec" id="XML_DefaultCurrent">
+<h4 id="XML_DefaultCurrent">XML_DefaultCurrent</h4>
+<pre class="fcndec">
void XMLCALL
XML_DefaultCurrent(XML_Parser parser);
</pre>
@@ -2234,7 +2528,8 @@ href="#XML_SetDefaultHandler" >XML_SetDefaultHandler</a></code> or
not a default handler.
</div>
-<pre class="fcndec" id="XML_ExpatVersion">
+<h4 id="XML_ExpatVersion">XML_ExpatVersion</h4>
+<pre class="fcndec">
XML_LChar * XMLCALL
XML_ExpatVersion();
</pre>
@@ -2242,7 +2537,8 @@ XML_ExpatVersion();
Return the library version as a string (e.g. <code>"expat_1.95.1"</code>).
</div>
-<pre class="fcndec" id="XML_ExpatVersionInfo">
+<h4 id="XML_ExpatVersionInfo">XML_ExpatVersionInfo</h4>
+<pre class="fcndec">
struct XML_Expat_Version XMLCALL
XML_ExpatVersionInfo();
</pre>
@@ -2266,7 +2562,8 @@ Testing these constants is currently the best way to determine if
particular parts of the Expat API are available.
</div>
-<pre class="fcndec" id="XML_GetFeatureList">
+<h4 id="XML_GetFeatureList">XML_GetFeatureList</h4>
+<pre class="fcndec">
const XML_Feature * XMLCALL
XML_GetFeatureList();
</pre>
@@ -2299,7 +2596,7 @@ check these features to do so at runtime.</p>
<p>The return value is an array of <code>XML_Feature</code>,
terminated by a record with a <code>feature</code> of
-<code>XML_FEATURE_END</code> and <code>name</code> of NULL,
+<code>XML_FEATURE_END</code> and <code>name</code> of <code>NULL</code>,
identifying the feature-test macros Expat was compiled with. Since an
application that requires this kind of information needs to determine
the type of character the <code>name</code> points to, records for the
@@ -2327,7 +2624,8 @@ time, the following features have been defined to have values:</p>
</dl>
</div>
-<pre class="fcndec" id="XML_FreeContentModel">
+<h4 id="XML_FreeContentModel">XML_FreeContentModel</h4>
+<pre class="fcndec">
void XMLCALL
XML_FreeContentModel(XML_Parser parser, XML_Content *model);
</pre>
@@ -2346,19 +2644,21 @@ applications. This can be essential when using dynamically loaded
libraries which use different C standard libraries (this can happen on
Windows, at least).</p>
-<pre class="fcndec" id="XML_MemMalloc">
+<h4 id="XML_MemMalloc">XML_MemMalloc</h4>
+<pre class="fcndec">
void * XMLCALL
XML_MemMalloc(XML_Parser parser, size_t size);
</pre>
<div class="fcndef">
Allocate <code>size</code> bytes of memory using the allocator the
<code>parser</code> object has been configured to use. Returns a
-pointer to the memory or NULL on failure. Memory allocated in this
+pointer to the memory or <code>NULL</code> on failure. Memory allocated in this
way must be freed using <code><a href="#XML_MemFree"
>XML_MemFree</a></code>.
</div>
-<pre class="fcndec" id="XML_MemRealloc">
+<h4 id="XML_MemRealloc">XML_MemRealloc</h4>
+<pre class="fcndec">
void * XMLCALL
XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
</pre>
@@ -2367,9 +2667,9 @@ Allocate <code>size</code> bytes of memory using the allocator the
<code>parser</code> object has been configured to use.
<code>ptr</code> must point to a block of memory allocated by <code><a
href="#XML_MemMalloc" >XML_MemMalloc</a></code> or
-<code>XML_MemRealloc</code>, or be NULL. This function tries to
+<code>XML_MemRealloc</code>, or be <code>NULL</code>. This function tries to
expand the block pointed to by <code>ptr</code> if possible. Returns
-a pointer to the memory or NULL on failure. On success, the original
+a pointer to the memory or <code>NULL</code> on failure. On success, the original
block has either been expanded or freed. On failure, the original
block has not been freed; the caller is responsible for freeing the
original block. Memory allocated in this way must be freed using
@@ -2377,20 +2677,24 @@ original block. Memory allocated in this way must be freed using
>XML_MemFree</a></code>.
</div>
-<pre class="fcndec" id="XML_MemFree">
+<h4 id="XML_MemFree">XML_MemFree</h4>
+<pre class="fcndec">
void XMLCALL
XML_MemFree(XML_Parser parser, void *ptr);
</pre>
<div class="fcndef">
Free a block of memory pointed to by <code>ptr</code>. The block must
have been allocated by <code><a href="#XML_MemMalloc"
->XML_MemMalloc</a></code> or <code>XML_MemRealloc</code>, or be NULL.
+>XML_MemMalloc</a></code> or <code>XML_MemRealloc</code>, or be <code>NULL</code>.
</div>
<hr />
-<p><a href="http://validator.w3.org/check/referer"><img
- src="valid-xhtml10.png" alt="Valid XHTML 1.0!"
- height="31" width="88" class="noborder" /></a></p>
+
+ <div class="footer">
+ Found a bug in the documentation?
+ <a href="https://github.com/libexpat/libexpat/issues">Please file a bug report.</a>
+ </div>
+
</div>
</body>
</html>
diff --git a/contrib/expat/doc/style.css b/contrib/expat/doc/style.css
index 69df30bcecb2..1b8cd10dffa4 100644
--- a/contrib/expat/doc/style.css
+++ b/contrib/expat/doc/style.css
@@ -1,101 +1,47 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2000-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2021 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/* Stop not using half the screen */
body {
- background-color: white;
- border: 0px;
- margin: 0px;
- padding: 0px;
-}
-
-.corner {
- width: 200px;
- height: 80px;
- text-align: center;
-}
-
-.banner {
- background-color: rgb(110,139,61);
- color: rgb(255,236,176);
- padding-left: 2em;
-}
-
-.banner h1 {
- font-size: 200%;
-}
-
-.content {
- padding: 0em 2em 1em 2em;
-}
-
-.releaseno {
- background-color: rgb(110,139,61);
- color: rgb(255,236,176);
- padding-bottom: 0.3em;
- padding-top: 0.5em;
- text-align: center;
- font-weight: bold;
-}
-
-.noborder {
- border-width: 0px;
-}
-
-.eg {
- padding-left: 1em;
- padding-top: .5em;
- padding-bottom: .5em;
- border: solid thin;
- margin: 1em 0;
- background-color: tan;
- margin-left: 2em;
- margin-right: 10%;
-}
-
-.pseudocode {
- padding-left: 1em;
- padding-top: .5em;
- padding-bottom: .5em;
- border: solid thin;
- margin: 1em 0;
- background-color: rgb(250,220,180);
- margin-left: 2em;
- margin-right: 10%;
-}
-
-.handler {
- width: 100%;
- border-top-width: thin;
- margin-bottom: 1em;
-}
-
-.handler p {
- margin-left: 2em;
-}
-
-.setter {
- font-weight: bold;
-}
-
-.signature {
- color: navy;
-}
-
-.fcndec {
- width: 100%;
- border-top-width: thin;
- font-weight: bold;
-}
-
-.fcndef {
- margin-left: 2em;
- margin-bottom: 2em;
-}
-
-dd {
- margin-bottom: 2em;
+ max-width: none; /* was: 80ch */
}
.cpp-symbols dt {
font-family: monospace;
}
-.cpp-symbols dd {
- margin-bottom: 1em;
+
+/* Resemble style of <footer> which is not part of xhtml1-strict */
+.footer {
+ font-size: var(--ok-fs-5);
+ color: var(--ok-tc-1);
}
diff --git a/contrib/expat/doc/xmlwf.1 b/contrib/expat/doc/xmlwf.1
index 57230689ef23..ac5ce21e6b81 100644
--- a/contrib/expat/doc/xmlwf.1
+++ b/contrib/expat/doc/xmlwf.1
@@ -5,7 +5,7 @@
\\$2 \(la\\$1\(ra\\$3
..
.if \n(.g .mso www.tmac
-.TH XMLWF 1 "March 11, 2016" "" ""
+.TH XMLWF 1 "February 6, 2024" "" ""
.SH NAME
xmlwf \- Determines if an XML document is well-formed
.SH SYNOPSIS
@@ -15,7 +15,27 @@ xmlwf \- Determines if an XML document is well-formed
\fBxmlwf\fR \kx
.if (\nx>(\n(.l/2)) .nr x (\n(.l/5)
'in \n(.iu+\nxu
-[\fB-s\fR] [\fB-n\fR] [\fB-p\fR] [\fB-x\fR] [\fB-e \fIencoding\fB\fR] [\fB-w\fR] [\fB-d \fIoutput-dir\fB\fR] [\fB-c\fR] [\fB-m\fR] [\fB-r\fR] [\fB-t\fR] [\fB-N\fR] [\fB-v\fR] [file ...]
+[\fIOPTIONS\fR] [\fIFILE\fR ...]
+'in \n(.iu-\nxu
+.ad b
+'hy
+'nh
+.fi
+.ad l
+\fBxmlwf\fR \kx
+.if (\nx>(\n(.l/2)) .nr x (\n(.l/5)
+'in \n(.iu+\nxu
+\fB-h\fR | \fB--help\fR
+'in \n(.iu-\nxu
+.ad b
+'hy
+'nh
+.fi
+.ad l
+\fBxmlwf\fR \kx
+.if (\nx>(\n(.l/2)) .nr x (\n(.l/5)
+'in \n(.iu+\nxu
+\fB-v\fR | \fB--version\fR
'in \n(.iu-\nxu
.ad b
'hy
@@ -34,7 +54,7 @@ following rules:
\(bu
The file begins with an XML declaration. For instance,
\*(T<<?xml version="1.0" standalone="yes"?>\*(T>.
-\fINOTE:\fR
+\fINOTE\fR:
\fBxmlwf\fR does not currently
check for a valid XML declaration.
.TP 0.2i
@@ -62,10 +82,42 @@ it does not check the DTD. However, it does support
external entities (see the \*(T<\fB\-x\fR\*(T> option).
.SH OPTIONS
When an option includes an argument, you may specify the argument either
-separately ("\*(T<\fB\-d\fR\*(T> output") or concatenated with the
-option ("\*(T<\fB\-d\fR\*(T>output"). \fBxmlwf\fR
+separately ("\*(T<\fB\-d\fR\*(T> \fIoutput\fR") or concatenated with the
+option ("\*(T<\fB\-d\fR\*(T>\fIoutput\fR"). \fBxmlwf\fR
supports both.
.TP
+\*(T<\fB\-a\fR\*(T> \fIfactor\fR
+Sets the maximum tolerated amplification factor
+for protection against billion laughs attacks (default: 100.0).
+The amplification factor is calculated as ..
+
+.nf
+
+ amplification := (direct + indirect) / direct
+
+.fi
+
+\&.. while parsing, whereas
+<direct> is the number of bytes read
+from the primary document in parsing and
+<indirect> is the number of bytes
+added by expanding entities and reading of external DTD files,
+combined.
+
+\fINOTE\fR:
+If you ever need to increase this value for non-attack payload,
+please file a bug report.
+.TP
+\*(T<\fB\-b\fR\*(T> \fIbytes\fR
+Sets the number of output bytes (including amplification)
+needed to activate protection against billion laughs attacks
+(default: 8 MiB).
+This can be thought of as an "activation threshold".
+
+\fINOTE\fR:
+If you ever need to increase this value for non-attack payload,
+please file a bug report.
+.TP
\*(T<\fB\-c\fR\*(T>
If the input file is well-formed and \fBxmlwf\fR
doesn't encounter any errors, the input file is simply copied to
@@ -73,7 +125,7 @@ the output directory unchanged.
This implies no namespaces (turns off \*(T<\fB\-n\fR\*(T>) and
requires \*(T<\fB\-d\fR\*(T> to specify an output directory.
.TP
-\*(T<\fB\-d output\-dir\fR\*(T>
+\*(T<\fB\-d\fR\*(T> \fIoutput-dir\fR
Specifies a directory to contain transformed
representations of the input files.
By default, \*(T<\fB\-d\fR\*(T> outputs a canonical representation
@@ -96,7 +148,7 @@ is treated equivalently to data.
More on canonical XML can be found at
http://www.jclark.com/xml/canonxml.html .
.TP
-\*(T<\fB\-e encoding\fR\*(T>
+\*(T<\fB\-e\fR\*(T> \fIencoding\fR
Specifies the character encoding for the document, overriding
any document encoding declaration. \fBxmlwf\fR
supports four built-in encodings:
@@ -106,6 +158,25 @@ supports four built-in encodings:
\*(T<ISO\-8859\-1\*(T>.
Also see the \*(T<\fB\-w\fR\*(T> option.
.TP
+\*(T<\fB\-g\fR\*(T> \fIbytes\fR
+Sets the buffer size to request per call pair to
+\*(T<\fBXML_GetBuffer\fR\*(T> and \*(T<\fBread\fR\*(T>
+(default: 8 KiB).
+.TP
+\*(T<\fB\-h\fR\*(T>, \*(T<\fB\-\-help\fR\*(T>
+Prints short usage information on command \fBxmlwf\fR,
+and then exits.
+Similar to this man page but more concise.
+.TP
+\*(T<\fB\-k\fR\*(T>
+When processing multiple files, \fBxmlwf\fR
+by default halts after the the first file with an error.
+This tells \fBxmlwf\fR to report the error
+but to keep processing.
+This can be useful, for example, when testing a filter that converts
+many files to XML and you want to quickly find out which conversions
+failed.
+.TP
\*(T<\fB\-m\fR\*(T>
Outputs some strange sort of XML file that completely
describes the input file, including character positions.
@@ -121,13 +192,17 @@ This matches the example output used by the formal XML test cases.
Requires \*(T<\fB\-d\fR\*(T> to specify an output file.
.TP
\*(T<\fB\-p\fR\*(T>
-Tells xmlwf to process external DTDs and parameter
+Tells \fBxmlwf\fR to process external DTDs and parameter
entities.
Normally \fBxmlwf\fR never parses parameter
entities. \*(T<\fB\-p\fR\*(T> tells it to always parse them.
\*(T<\fB\-p\fR\*(T> implies \*(T<\fB\-x\fR\*(T>.
.TP
+\*(T<\fB\-q\fR\*(T>
+Disable reparse deferral, and allow quadratic parse runtime
+on large tokens (default: reparse deferral enabled).
+.TP
\*(T<\fB\-r\fR\*(T>
Normally \fBxmlwf\fR memory-maps the XML file
before parsing; this can result in faster parsing on many
@@ -156,7 +231,7 @@ without client overhead.
\*(T<\fB\-t\fR\*(T> turns off most of the output options
(\*(T<\fB\-d\fR\*(T>, \*(T<\fB\-m\fR\*(T>, \*(T<\fB\-c\fR\*(T>, ...).
.TP
-\*(T<\fB\-v\fR\*(T>
+\*(T<\fB\-v\fR\*(T>, \*(T<\fB\-\-version\fR\*(T>
Prints the version of the Expat library being used, including some
information on the compile-time configuration of the library, and
then exits.
@@ -165,7 +240,7 @@ then exits.
Enables support for Windows code pages.
Normally, \fBxmlwf\fR will throw an error if it
runs across an encoding that it is not equipped to handle itself. With
-\*(T<\fB\-w\fR\*(T>, xmlwf will try to use a Windows code
+\*(T<\fB\-w\fR\*(T>, \fBxmlwf\fR will try to use a Windows code
page. See also \*(T<\fB\-e\fR\*(T>.
.TP
\*(T<\fB\-x\fR\*(T>
@@ -210,18 +285,33 @@ will run \fBxmlwf\fR on the file
Older versions of \fBxmlwf\fR do not support
reading from standard input.
.SH OUTPUT
-If an input file is not well-formed,
-\fBxmlwf\fR prints a single line describing
-the problem to standard output. If a file is well formed,
-\fBxmlwf\fR outputs nothing.
-Note that the result code is \fInot\fR set.
-.SH BUGS
-\fBxmlwf\fR returns a 0 - noerr result,
-even if the file is not well-formed. There is no good way for
-a program to use \fBxmlwf\fR to quickly
-check a file -- it must parse \fBxmlwf\fR's
-standard output.
+\fBxmlwf\fR outputs nothing for files which are problem-free.
+If any input file is not well-formed, or if the output for any
+input file cannot be opened, \fBxmlwf\fR prints a single
+line describing the problem to standard output.
.PP
+If the \*(T<\fB\-k\fR\*(T> option is not provided, \fBxmlwf\fR
+halts upon encountering a well-formedness or output-file error.
+If \*(T<\fB\-k\fR\*(T> is provided, \fBxmlwf\fR continues
+processing the remaining input files, describing problems found with any of them.
+.SH "EXIT STATUS"
+For options \*(T<\fB\-v\fR\*(T>|\*(T<\fB\-\-version\fR\*(T> or \*(T<\fB\-h\fR\*(T>|\*(T<\fB\-\-help\fR\*(T>, \fBxmlwf\fR always exits with status code 0. For other cases, the following exit status codes are returned:
+.TP
+\*(T<\fB0\fR\*(T>
+The input files are well-formed and the output (if requested) was written successfully.
+.TP
+\*(T<\fB1\fR\*(T>
+An internal error occurred.
+.TP
+\*(T<\fB2\fR\*(T>
+One or more input files were not well-formed or could not be parsed.
+.TP
+\*(T<\fB3\fR\*(T>
+If using the \*(T<\fB\-d\fR\*(T> option, an error occurred opening an output file.
+.TP
+\*(T<\fB4\fR\*(T>
+There was a command-line argument error in how \fBxmlwf\fR was invoked.
+.SH BUGS
The errors should go to standard error, not standard output.
.PP
There should be a way to get \*(T<\fB\-d\fR\*(T> to send its
@@ -232,24 +322,16 @@ I have no idea why anyone would want to use the
\*(T<\fB\-d\fR\*(T>, \*(T<\fB\-c\fR\*(T>, and
\*(T<\fB\-m\fR\*(T> options. If someone could explain it to
me, I'd like to add this information to this manpage.
-.SH ALTERNATIVES
-Here are some XML validators on the web:
-
-.nf
-
-http://www.hcrc.ed.ac.uk/~richard/xml\-check.html
-http://www.stg.brown.edu/service/xmlvalid/
-http://www.scripting.com/frontier5/xml/code/xmlValidator.html
-http://www.xml.com/pub/a/tools/ruwf/check.html
-.fi
.SH "SEE ALSO"
.nf
-The Expat home page: http://www.libexpat.org/
-The W3 XML specification: http://www.w3.org/TR/REC\-xml
+The Expat home page: https://libexpat.github.io/
+The W3 XML 1.0 specification (fourth edition): https://www.w3.org/TR/2006/REC\-xml\-20060816/
+Billion laughs attack: https://en.wikipedia.org/wiki/Billion_laughs_attack
.fi
.SH AUTHOR
-This manual page was written by Scott Bronson <\*(T<bronson@rinspin.com\*(T>> for
+This manual page was originally written by Scott Bronson <\*(T<bronson@rinspin.com\*(T>>
+in December 2001 for
the Debian GNU/Linux system (but may be used by others). Permission is
granted to copy, distribute and/or modify this document under
the terms of the GNU Free Documentation
diff --git a/contrib/expat/doc/xmlwf.xml b/contrib/expat/doc/xmlwf.xml
index 5e2a4ae94ab3..2b3f1ccd74a8 100644
--- a/contrib/expat/doc/xmlwf.xml
+++ b/contrib/expat/doc/xmlwf.xml
@@ -1,11 +1,28 @@
-<!DOCTYPE refentry [
- <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+<!--
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001 Scott Bronson <bronson@rinspin.com>
+ Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2009 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016 Ardo van Rangelrooij <ardo@debian.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2020 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2021 Tim Bray <tbray@textuality.com>
+ Unlike most of Expat,
+ this file is copyrighted under the GNU Free Documentation License 1.1.
+-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY dhfirstname "<firstname>Scott</firstname>">
<!ENTITY dhsurname "<surname>Bronson</surname>">
- <!-- Please adjust the date whenever revising the manpage. -->
- <!ENTITY dhdate "<date>March 11, 2016</date>">
- <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
- allowed: see man(7), man(1). -->
+ <!ENTITY dhdate "<date>February 6, 2024</date>">
+ <!-- Please adjust this^^ date whenever cutting a new release. -->
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
<!ENTITY dhemail "<email>bronson@rinspin.com</email>">
<!ENTITY dhusername "Scott Bronson">
@@ -44,25 +61,22 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>&dhpackage;</command>
- <arg><option>-s</option></arg>
- <arg><option>-n</option></arg>
- <arg><option>-p</option></arg>
- <arg><option>-x</option></arg>
-
- <arg><option>-e <replaceable>encoding</replaceable></option></arg>
- <arg><option>-w</option></arg>
-
- <arg><option>-d <replaceable>output-dir</replaceable></option></arg>
- <arg><option>-c</option></arg>
- <arg><option>-m</option></arg>
-
- <arg><option>-r</option></arg>
- <arg><option>-t</option></arg>
- <arg><option>-N</option></arg>
-
- <arg><option>-v</option></arg>
-
- <arg>file ...</arg>
+ <arg><replaceable>OPTIONS</replaceable></arg>
+ <arg><replaceable>FILE</replaceable> ...</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>&dhpackage;</command>
+ <group choice="plain">
+ <arg><option>-h</option></arg>
+ <arg><option>--help</option></arg>
+ </group>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>&dhpackage;</command>
+ <group choice="plain">
+ <arg><option>-v</option></arg>
+ <arg><option>--version</option></arg>
+ </group>
</cmdsynopsis>
</refsynopsisdiv>
@@ -95,7 +109,7 @@
<listitem><para>
The file begins with an XML declaration. For instance,
<literal>&lt;?xml version="1.0" standalone="yes"?&gt;</literal>.
- <emphasis>NOTE:</emphasis>
+ <emphasis>NOTE</emphasis>:
<command>&dhpackage;</command> does not currently
check for a valid XML declaration.
</para></listitem>
@@ -132,14 +146,58 @@
<para>
When an option includes an argument, you may specify the argument either
-separately ("<option>-d</option> output") or concatenated with the
-option ("<option>-d</option>output"). <command>&dhpackage;</command>
+separately ("<option>-d</option> <replaceable>output</replaceable>") or concatenated with the
+option ("<option>-d</option><replaceable>output</replaceable>"). <command>&dhpackage;</command>
supports both.
</para>
<variablelist>
<varlistentry>
+ <term><option>-a</option> <replaceable>factor</replaceable></term>
+ <listitem>
+ <para>
+ Sets the maximum tolerated amplification factor
+ for protection against billion laughs attacks (default: 100.0).
+ The amplification factor is calculated as ..
+ </para>
+ <literallayout>
+ amplification := (direct + indirect) / direct
+ </literallayout>
+ <para>
+ .. while parsing, whereas
+ &lt;direct&gt; is the number of bytes read
+ from the primary document in parsing and
+ &lt;indirect&gt; is the number of bytes
+ added by expanding entities and reading of external DTD files,
+ combined.
+ </para>
+ <para>
+ <emphasis>NOTE</emphasis>:
+ If you ever need to increase this value for non-attack payload,
+ please file a bug report.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-b</option> <replaceable>bytes</replaceable></term>
+ <listitem>
+ <para>
+ Sets the number of output bytes (including amplification)
+ needed to activate protection against billion laughs attacks
+ (default: 8 MiB).
+ This can be thought of as an &quot;activation threshold&quot;.
+ </para>
+ <para>
+ <emphasis>NOTE</emphasis>:
+ If you ever need to increase this value for non-attack payload,
+ please file a bug report.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-c</option></term>
<listitem>
<para>
@@ -153,7 +211,7 @@ supports both.
</varlistentry>
<varlistentry>
- <term><option>-d output-dir</option></term>
+ <term><option>-d</option> <replaceable>output-dir</replaceable></term>
<listitem>
<para>
Specifies a directory to contain transformed
@@ -184,7 +242,7 @@ supports both.
</varlistentry>
<varlistentry>
- <term><option>-e encoding</option></term>
+ <term><option>-e</option> <replaceable>encoding</replaceable></term>
<listitem>
<para>
Specifies the character encoding for the document, overriding
@@ -200,6 +258,44 @@ supports both.
</varlistentry>
<varlistentry>
+ <term><option>-g</option> <replaceable>bytes</replaceable></term>
+ <listitem>
+ <para>
+ Sets the buffer size to request per call pair to
+ <function>XML_GetBuffer</function> and <function>read</function>
+ (default: 8 KiB).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-h</option></term>
+ <term><option>--help</option></term>
+ <listitem>
+ <para>
+ Prints short usage information on command <command>&dhpackage;</command>,
+ and then exits.
+ Similar to this man page but more concise.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-k</option></term>
+ <listitem>
+ <para>
+ When processing multiple files, <command>&dhpackage;</command>
+ by default halts after the the first file with an error.
+ This tells <command>&dhpackage;</command> to report the error
+ but to keep processing.
+ This can be useful, for example, when testing a filter that converts
+ many files to XML and you want to quickly find out which conversions
+ failed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-m</option></term>
<listitem>
<para>
@@ -235,7 +331,7 @@ supports both.
<term><option>-p</option></term>
<listitem>
<para>
- Tells xmlwf to process external DTDs and parameter
+ Tells <command>&dhpackage;</command> to process external DTDs and parameter
entities.
</para>
<para>
@@ -247,6 +343,16 @@ supports both.
</varlistentry>
<varlistentry>
+ <term><option>-q</option></term>
+ <listitem>
+ <para>
+ Disable reparse deferral, and allow quadratic parse runtime
+ on large tokens (default: reparse deferral enabled).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-r</option></term>
<listitem>
<para>
@@ -292,9 +398,10 @@ supports both.
</para>
</listitem>
</varlistentry>
-
+
<varlistentry>
<term><option>-v</option></term>
+ <term><option>--version</option></term>
<listitem>
<para>
Prints the version of the Expat library being used, including some
@@ -311,7 +418,7 @@ supports both.
Enables support for Windows code pages.
Normally, <command>&dhpackage;</command> will throw an error if it
runs across an encoding that it is not equipped to handle itself. With
- <option>-w</option>, &dhpackage; will try to use a Windows code
+ <option>-w</option>, <command>&dhpackage;</command> will try to use a Windows code
page. See also <option>-e</option>.
</para>
</listitem>
@@ -379,24 +486,56 @@ supports both.
<refsect1>
<title>OUTPUT</title>
<para>
- If an input file is not well-formed,
- <command>&dhpackage;</command> prints a single line describing
- the problem to standard output. If a file is well formed,
- <command>&dhpackage;</command> outputs nothing.
- Note that the result code is <emphasis>not</emphasis> set.
+ <command>&dhpackage;</command> outputs nothing for files which are problem-free.
+ If any input file is not well-formed, or if the output for any
+ input file cannot be opened, <command>&dhpackage;</command> prints a single
+ line describing the problem to standard output.
+ </para>
+ <para>
+ If the <option>-k</option> option is not provided, <command>&dhpackage;</command>
+ halts upon encountering a well-formedness or output-file error.
+ If <option>-k</option> is provided, <command>&dhpackage;</command> continues
+ processing the remaining input files, describing problems found with any of them.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>EXIT STATUS</title>
+ <para>For options <option>-v</option>|<option>--version</option> or <option>-h</option>|<option>--help</option>, <command>&dhpackage;</command> always exits with status code 0. For other cases, the following exit status codes are returned:
+ <variablelist>
+ <varlistentry>
+ <term><option>0</option></term>
+ <listitem><para>The input files are well-formed and the output (if requested) was written successfully.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>1</option></term>
+ <listitem><para>An internal error occurred.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>2</option></term>
+ <listitem><para>One or more input files were not well-formed or could not be parsed.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>3</option></term>
+ <listitem><para>If using the <option>-d</option> option, an error occurred opening an output file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>4</option></term>
+ <listitem><para>There was a command-line argument error in how <command>&dhpackage;</command> was invoked.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
</para>
</refsect1>
+
<refsect1>
<title>BUGS</title>
<para>
- <command>&dhpackage;</command> returns a 0 - noerr result,
- even if the file is not well-formed. There is no good way for
- a program to use <command>&dhpackage;</command> to quickly
- check a file -- it must parse <command>&dhpackage;</command>'s
- standard output.
- </para>
- <para>
The errors should go to standard error, not standard output.
</para>
<para>
@@ -413,27 +552,13 @@ supports both.
</refsect1>
<refsect1>
- <title>ALTERNATIVES</title>
- <para>
- Here are some XML validators on the web:
-
-<literallayout>
-http://www.hcrc.ed.ac.uk/~richard/xml-check.html
-http://www.stg.brown.edu/service/xmlvalid/
-http://www.scripting.com/frontier5/xml/code/xmlValidator.html
-http://www.xml.com/pub/a/tools/ruwf/check.html
-</literallayout>
-
- </para>
- </refsect1>
-
- <refsect1>
<title>SEE ALSO</title>
<para>
<literallayout>
-The Expat home page: http://www.libexpat.org/
-The W3 XML specification: http://www.w3.org/TR/REC-xml
+The Expat home page: https://libexpat.github.io/
+The W3 XML 1.0 specification (fourth edition): https://www.w3.org/TR/2006/REC-xml-20060816/
+Billion laughs attack: https://en.wikipedia.org/wiki/Billion_laughs_attack
</literallayout>
</para>
@@ -442,7 +567,8 @@ The W3 XML specification: http://www.w3.org/TR/REC-xml
<refsect1>
<title>AUTHOR</title>
<para>
- This manual page was written by &dhusername; &dhemail; for
+ This manual page was originally written by &dhusername; &dhemail;
+ in December 2001 for
the &debian; system (but may be used by others). Permission is
granted to copy, distribute and/or modify this document under
the terms of the <acronym>GNU</acronym> Free Documentation
diff --git a/contrib/expat/examples/Makefile.am b/contrib/expat/examples/Makefile.am
index 99edf21227c9..e2e22bce8f69 100644
--- a/contrib/expat/examples/Makefile.am
+++ b/contrib/expat/examples/Makefile.am
@@ -6,7 +6,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -28,9 +29,12 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
# USE OR OTHER DEALINGS IN THE SOFTWARE.
-AM_CPPFLAGS = -I$(srcdir)/../lib
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
-noinst_PROGRAMS = elements outline
+noinst_PROGRAMS = element_declarations elements outline
+
+element_declarations_SOURCES = element_declarations.c
+element_declarations_LDADD = ../lib/libexpat.la
elements_SOURCES = elements.c
elements_LDADD = ../lib/libexpat.la
diff --git a/contrib/expat/examples/Makefile.in b/contrib/expat/examples/Makefile.in
index 391c71ee93e2..0ccc020dd94f 100644
--- a/contrib/expat/examples/Makefile.in
+++ b/contrib/expat/examples/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -118,7 +119,8 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-noinst_PROGRAMS = elements$(EXEEXT) outline$(EXEEXT)
+noinst_PROGRAMS = element_declarations$(EXEEXT) elements$(EXEEXT) \
+ outline$(EXEEXT)
subdir = examples
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
@@ -132,6 +134,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/conftools/ax-append-compile-flags.m4 \
$(top_srcdir)/conftools/ax-append-link-flags.m4 \
$(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx-11.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -141,13 +145,16 @@ CONFIG_HEADER = $(top_builddir)/expat_config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
PROGRAMS = $(noinst_PROGRAMS)
-am_elements_OBJECTS = elements.$(OBJEXT)
-elements_OBJECTS = $(am_elements_OBJECTS)
-elements_DEPENDENCIES = ../lib/libexpat.la
+am_element_declarations_OBJECTS = element_declarations.$(OBJEXT)
+element_declarations_OBJECTS = $(am_element_declarations_OBJECTS)
+element_declarations_DEPENDENCIES = ../lib/libexpat.la
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
+am_elements_OBJECTS = elements.$(OBJEXT)
+elements_OBJECTS = $(am_elements_OBJECTS)
+elements_DEPENDENCIES = ../lib/libexpat.la
am_outline_OBJECTS = outline.$(OBJEXT)
outline_OBJECTS = $(am_outline_OBJECTS)
outline_DEPENDENCIES = ../lib/libexpat.la
@@ -166,7 +173,8 @@ am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
am__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/elements.Po ./$(DEPDIR)/outline.Po
+am__depfiles_remade = ./$(DEPDIR)/element_declarations.Po \
+ ./$(DEPDIR)/elements.Po ./$(DEPDIR)/outline.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -186,8 +194,10 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
-SOURCES = $(elements_SOURCES) $(outline_SOURCES)
-DIST_SOURCES = $(elements_SOURCES) $(outline_SOURCES)
+SOURCES = $(element_declarations_SOURCES) $(elements_SOURCES) \
+ $(outline_SOURCES)
+DIST_SOURCES = $(element_declarations_SOURCES) $(elements_SOURCES) \
+ $(outline_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -210,14 +220,16 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in \
$(top_srcdir)/conftools/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
@@ -227,8 +239,10 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CPP = @CPP@
+CMAKE_SHARED_LIBRARY_PREFIX = @CMAKE_SHARED_LIBRARY_PREFIX@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -244,10 +258,20 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
+EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
+EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
+EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
+EXPAT_DTD = @EXPAT_DTD@
+EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
+EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
+EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FILEMAP = @FILEMAP@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -257,6 +281,8 @@ LD = @LD@
LDFLAGS = @LDFLAGS@
LIBAGE = @LIBAGE@
LIBCURRENT = @LIBCURRENT@
+LIBDIR_BASENAME = @LIBDIR_BASENAME@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBREVISION = @LIBREVISION@
LIBS = @LIBS@
@@ -265,6 +291,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -286,6 +313,9 @@ RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SO_MAJOR = @SO_MAJOR@
+SO_MINOR = @SO_MINOR@
+SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
@@ -296,6 +326,7 @@ ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_void_p = @ac_cv_sizeof_void_p@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -333,6 +364,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -341,7 +373,8 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-AM_CPPFLAGS = -I$(srcdir)/../lib
+element_declarations_SOURCES = element_declarations.c
+element_declarations_LDADD = ../lib/libexpat.la
elements_SOURCES = elements.c
elements_LDADD = ../lib/libexpat.la
outline_SOURCES = outline.c
@@ -350,7 +383,7 @@ all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -374,9 +407,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: $(am__configure_deps)
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
@@ -389,6 +422,10 @@ clean-noinstPROGRAMS:
echo " rm -f" $$list; \
rm -f $$list
+element_declarations$(EXEEXT): $(element_declarations_OBJECTS) $(element_declarations_DEPENDENCIES) $(EXTRA_element_declarations_DEPENDENCIES)
+ @rm -f element_declarations$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(element_declarations_OBJECTS) $(element_declarations_LDADD) $(LIBS)
+
elements$(EXEEXT): $(elements_OBJECTS) $(elements_DEPENDENCIES) $(EXTRA_elements_DEPENDENCIES)
@rm -f elements$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(elements_OBJECTS) $(elements_LDADD) $(LIBS)
@@ -403,6 +440,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/element_declarations.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elements.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/outline.Po@am__quote@ # am--include-marker
@@ -490,7 +528,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -564,7 +601,8 @@ clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
mostlyclean-am
distclean: distclean-am
- -rm -f ./$(DEPDIR)/elements.Po
+ -rm -f ./$(DEPDIR)/element_declarations.Po
+ -rm -f ./$(DEPDIR)/elements.Po
-rm -f ./$(DEPDIR)/outline.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
@@ -611,7 +649,8 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
- -rm -f ./$(DEPDIR)/elements.Po
+ -rm -f ./$(DEPDIR)/element_declarations.Po
+ -rm -f ./$(DEPDIR)/elements.Po
-rm -f ./$(DEPDIR)/outline.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/contrib/expat/examples/element_declarations.c b/contrib/expat/examples/element_declarations.c
new file mode 100644
index 000000000000..7ce8544f6f04
--- /dev/null
+++ b/contrib/expat/examples/element_declarations.c
@@ -0,0 +1,234 @@
+/* Read an XML document from standard input and print
+ element declarations (if any) to standard output.
+ It must be used with Expat compiled for UTF-8 output.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2004-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2019 Zhongyuan Zhou <zhouzhongyuan@huawei.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <expat.h>
+
+#ifdef XML_LARGE_SIZE
+# define XML_FMT_INT_MOD "ll"
+#else
+# define XML_FMT_INT_MOD "l"
+#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_STR "ls"
+#else
+# define XML_FMT_STR "s"
+#endif
+
+// While traversing the XML_Content tree, we avoid recursion
+// to not be vulnerable to a denial of service attack.
+typedef struct StackStruct {
+ const XML_Content *model;
+ unsigned level;
+ struct StackStruct *prev;
+} Stack;
+
+static Stack *
+stackPushMalloc(Stack *stackTop, const XML_Content *model, unsigned level) {
+ Stack *const newStackTop = malloc(sizeof(Stack));
+ if (! newStackTop) {
+ return NULL;
+ }
+ newStackTop->model = model;
+ newStackTop->level = level;
+ newStackTop->prev = stackTop;
+ return newStackTop;
+}
+
+static Stack *
+stackPopFree(Stack *stackTop) {
+ Stack *const newStackTop = stackTop->prev;
+ free(stackTop);
+ return newStackTop;
+}
+
+static char *
+contentTypeName(enum XML_Content_Type contentType) {
+ switch (contentType) {
+ case XML_CTYPE_EMPTY:
+ return "EMPTY";
+ case XML_CTYPE_ANY:
+ return "ANY";
+ case XML_CTYPE_MIXED:
+ return "MIXED";
+ case XML_CTYPE_NAME:
+ return "NAME";
+ case XML_CTYPE_CHOICE:
+ return "CHOICE";
+ case XML_CTYPE_SEQ:
+ return "SEQ";
+ default:
+ return "???";
+ }
+}
+
+static char *
+contentQuantName(enum XML_Content_Quant contentQuant) {
+ switch (contentQuant) {
+ case XML_CQUANT_NONE:
+ return "NONE";
+ case XML_CQUANT_OPT:
+ return "OPT";
+ case XML_CQUANT_REP:
+ return "REP";
+ case XML_CQUANT_PLUS:
+ return "PLUS";
+ default:
+ return "???";
+ }
+}
+
+static void
+dumpContentModelElement(const XML_Content *model, unsigned level,
+ const XML_Content *root) {
+ // Indent
+ unsigned u = 0;
+ for (; u < level; u++) {
+ printf(" ");
+ }
+
+ // Node
+ printf("[%u] type=%s(%d), quant=%s(%d)", (unsigned)(model - root),
+ contentTypeName(model->type), model->type,
+ contentQuantName(model->quant), model->quant);
+ if (model->name) {
+ printf(", name=\"%" XML_FMT_STR "\"", model->name);
+ } else {
+ printf(", name=NULL");
+ }
+ printf(", numchildren=%d", model->numchildren);
+ printf("\n");
+}
+
+static bool
+dumpContentModel(const XML_Char *name, const XML_Content *root) {
+ printf("Element \"%" XML_FMT_STR "\":\n", name);
+ Stack *stackTop = stackPushMalloc(NULL, root, 1);
+ if (! stackTop) {
+ return false;
+ }
+
+ while (stackTop) {
+ const XML_Content *const model = stackTop->model;
+ const unsigned level = stackTop->level;
+
+ dumpContentModelElement(model, level, root);
+
+ stackTop = stackPopFree(stackTop);
+
+ for (size_t u = model->numchildren; u >= 1; u--) {
+ Stack *const newStackTop
+ = stackPushMalloc(stackTop, model->children + (u - 1), level + 1);
+ if (! newStackTop) {
+ // We ran out of memory, so let's free all memory allocated
+ // earlier in this function, to be leak-clean:
+ while (stackTop != NULL) {
+ stackTop = stackPopFree(stackTop);
+ }
+ return false;
+ }
+ stackTop = newStackTop;
+ }
+ }
+
+ printf("\n");
+ return true;
+}
+
+static void XMLCALL
+handleElementDeclaration(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ XML_Parser parser = (XML_Parser)userData;
+ const bool success = dumpContentModel(name, model);
+ XML_FreeContentModel(parser, model);
+ if (! success) {
+ XML_StopParser(parser, /* resumable= */ XML_FALSE);
+ }
+}
+
+int
+main(void) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ int done;
+
+ if (! parser) {
+ fprintf(stderr, "Couldn't allocate memory for parser\n");
+ return 1;
+ }
+
+ XML_SetUserData(parser, parser);
+ XML_SetElementDeclHandler(parser, handleElementDeclaration);
+
+ do {
+ void *const buf = XML_GetBuffer(parser, BUFSIZ);
+ if (! buf) {
+ fprintf(stderr, "Couldn't allocate memory for buffer\n");
+ XML_ParserFree(parser);
+ return 1;
+ }
+
+ const size_t len = fread(buf, 1, BUFSIZ, stdin);
+
+ if (ferror(stdin)) {
+ fprintf(stderr, "Read error\n");
+ XML_ParserFree(parser);
+ return 1;
+ }
+
+ done = feof(stdin);
+
+ if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
+ enum XML_Error errorCode = XML_GetErrorCode(parser);
+ if (errorCode == XML_ERROR_ABORTED) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ }
+ fprintf(stderr,
+ "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber(parser), XML_ErrorString(errorCode));
+ XML_ParserFree(parser);
+ return 1;
+ }
+ } while (! done);
+
+ XML_ParserFree(parser);
+ return 0;
+}
diff --git a/contrib/expat/examples/elements.c b/contrib/expat/examples/elements.c
index eb0c729bff15..e5fb850d501b 100644
--- a/contrib/expat/examples/elements.c
+++ b/contrib/expat/examples/elements.c
@@ -11,7 +11,12 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2004-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2019 Zhongyuan Zhou <zhouzhongyuan@huawei.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -44,7 +49,6 @@
#endif
#ifdef XML_UNICODE_WCHAR_T
-# include <wchar.h>
# define XML_FMT_STR "ls"
#else
# define XML_FMT_STR "s"
@@ -53,7 +57,7 @@
static void XMLCALL
startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
int i;
- int *depthPtr = (int *)userData;
+ int *const depthPtr = (int *)userData;
(void)atts;
for (i = 0; i < *depthPtr; i++)
@@ -64,34 +68,54 @@ startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
static void XMLCALL
endElement(void *userData, const XML_Char *name) {
- int *depthPtr = (int *)userData;
+ int *const depthPtr = (int *)userData;
(void)name;
*depthPtr -= 1;
}
int
-main(int argc, char *argv[]) {
- char buf[BUFSIZ];
+main(void) {
XML_Parser parser = XML_ParserCreate(NULL);
int done;
int depth = 0;
- (void)argc;
- (void)argv;
+
+ if (! parser) {
+ fprintf(stderr, "Couldn't allocate memory for parser\n");
+ return 1;
+ }
XML_SetUserData(parser, &depth);
XML_SetElementHandler(parser, startElement, endElement);
+
do {
- size_t len = fread(buf, 1, sizeof(buf), stdin);
- done = len < sizeof(buf);
- if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) {
- fprintf(stderr, "%" XML_FMT_STR " at line %" XML_FMT_INT_MOD "u\n",
- XML_ErrorString(XML_GetErrorCode(parser)),
- XML_GetCurrentLineNumber(parser));
+ void *const buf = XML_GetBuffer(parser, BUFSIZ);
+ if (! buf) {
+ fprintf(stderr, "Couldn't allocate memory for buffer\n");
+ XML_ParserFree(parser);
+ return 1;
+ }
+
+ const size_t len = fread(buf, 1, BUFSIZ, stdin);
+
+ if (ferror(stdin)) {
+ fprintf(stderr, "Read error\n");
+ XML_ParserFree(parser);
+ return 1;
+ }
+
+ done = feof(stdin);
+
+ if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
+ fprintf(stderr,
+ "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber(parser),
+ XML_ErrorString(XML_GetErrorCode(parser)));
XML_ParserFree(parser);
return 1;
}
} while (! done);
+
XML_ParserFree(parser);
return 0;
}
diff --git a/contrib/expat/examples/outline.c b/contrib/expat/examples/outline.c
index d996b8e3a8d3..d2df914fedb8 100644
--- a/contrib/expat/examples/outline.c
+++ b/contrib/expat/examples/outline.c
@@ -8,8 +8,12 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -47,73 +51,74 @@
# define XML_FMT_STR "s"
#endif
-#define BUFFSIZE 8192
-
-char Buff[BUFFSIZE];
-
-int Depth;
-
static void XMLCALL
-start(void *data, const XML_Char *el, const XML_Char **attr) {
+startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
int i;
- (void)data;
+ int *const depthPtr = (int *)userData;
- for (i = 0; i < Depth; i++)
+ for (i = 0; i < *depthPtr; i++)
printf(" ");
- printf("%" XML_FMT_STR, el);
+ printf("%" XML_FMT_STR, name);
- for (i = 0; attr[i]; i += 2) {
- printf(" %" XML_FMT_STR "='%" XML_FMT_STR "'", attr[i], attr[i + 1]);
+ for (i = 0; atts[i]; i += 2) {
+ printf(" %" XML_FMT_STR "='%" XML_FMT_STR "'", atts[i], atts[i + 1]);
}
printf("\n");
- Depth++;
+ *depthPtr += 1;
}
static void XMLCALL
-end(void *data, const XML_Char *el) {
- (void)data;
- (void)el;
+endElement(void *userData, const XML_Char *name) {
+ int *const depthPtr = (int *)userData;
+ (void)name;
- Depth--;
+ *depthPtr -= 1;
}
int
-main(int argc, char *argv[]) {
- XML_Parser p = XML_ParserCreate(NULL);
- (void)argc;
- (void)argv;
+main(void) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ int done;
+ int depth = 0;
- if (! p) {
+ if (! parser) {
fprintf(stderr, "Couldn't allocate memory for parser\n");
- exit(-1);
+ return 1;
}
- XML_SetElementHandler(p, start, end);
+ XML_SetUserData(parser, &depth);
+ XML_SetElementHandler(parser, startElement, endElement);
- for (;;) {
- int done;
- int len;
+ do {
+ void *const buf = XML_GetBuffer(parser, BUFSIZ);
+ if (! buf) {
+ fprintf(stderr, "Couldn't allocate memory for buffer\n");
+ XML_ParserFree(parser);
+ return 1;
+ }
+
+ const size_t len = fread(buf, 1, BUFSIZ, stdin);
- len = (int)fread(Buff, 1, BUFFSIZE, stdin);
if (ferror(stdin)) {
fprintf(stderr, "Read error\n");
- exit(-1);
+ XML_ParserFree(parser);
+ return 1;
}
+
done = feof(stdin);
- if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) {
+ if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
fprintf(stderr,
"Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(p),
- XML_ErrorString(XML_GetErrorCode(p)));
- exit(-1);
+ XML_GetCurrentLineNumber(parser),
+ XML_ErrorString(XML_GetErrorCode(parser)));
+ XML_ParserFree(parser);
+ return 1;
}
+ } while (! done);
- if (done)
- break;
- }
- XML_ParserFree(p);
+ XML_ParserFree(parser);
return 0;
}
diff --git a/contrib/expat/expat_config.h.in b/contrib/expat/expat_config.h.in
index 59207b42e41d..91c32340868e 100644
--- a/contrib/expat/expat_config.h.in
+++ b/contrib/expat/expat_config.h.in
@@ -1,5 +1,8 @@
/* expat_config.h.in. Generated from configure.ac by autoheader. */
+#ifndef EXPAT_CONFIG_H
+#define EXPAT_CONFIG_H 1
+
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
@@ -12,6 +15,9 @@
/* Define to 1 if you have the `arc4random_buf' function. */
#undef HAVE_ARC4RANDOM_BUF
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
@@ -30,15 +36,15 @@
/* Define to 1 if you have the `bsd' library (-lbsd). */
#undef HAVE_LIBBSD
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
-
/* Define to 1 if you have a working `mmap' system call. */
#undef HAVE_MMAP
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
@@ -87,7 +93,9 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
#undef STDC_HEADERS
/* Version number of package */
@@ -110,7 +118,7 @@
#undef XML_ATTR_INFO
/* Define to specify how much context to retain around the current parse
- point. */
+ point, 0 to disable. */
#undef XML_CONTEXT_BYTES
/* Define to include code reading entropy from `/dev/urandom'. */
@@ -119,6 +127,9 @@
/* Define to make parameter entity parsing functionality available. */
#undef XML_DTD
+/* Define as 1/0 to enable/disable support for general entities. */
+#undef XML_GE
+
/* Define to make XML Namespaces functionality available. */
#undef XML_NS
@@ -130,3 +141,5 @@
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
+
+#endif // ndef EXPAT_CONFIG_H
diff --git a/contrib/expat/fix-xmltest-log.sh b/contrib/expat/fix-xmltest-log.sh
index c143e93cf20a..7981cf3b00c8 100755
--- a/contrib/expat/fix-xmltest-log.sh
+++ b/contrib/expat/fix-xmltest-log.sh
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2019 Expat development team
+# Copyright (c) 2019-2022 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -42,6 +42,8 @@ sed \
-e '/^Application tried to create a window, but no driver could be loaded.$/d' \
-e '/^Make sure that your X server is running and that $DISPLAY is set correctly.$/d' \
-e '/^err:systray:initialize_systray Could not create tray window$/d' \
+ -e '/^[0-9a-f]\+:err:/d' \
+ -e '/^wine client error:/d' \
-e '/^In ibm\/invalid\/P49\/: Unhandled exception: unimplemented .\+/d' \
\
"${filename}" > "${tempfile}"
diff --git a/contrib/expat/fuzz/xml_parse_fuzzer.c b/contrib/expat/fuzz/xml_parse_fuzzer.c
new file mode 100644
index 000000000000..a7e8414ce355
--- /dev/null
+++ b/contrib/expat/fuzz/xml_parse_fuzzer.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "expat.h"
+#include "siphash.h"
+
+// Macros to convert preprocessor macros to string literals. See
+// https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html
+#define xstr(s) str(s)
+#define str(s) #s
+
+// The encoder type that we wish to fuzz should come from the compile-time
+// definition `ENCODING_FOR_FUZZING`. This allows us to have a separate fuzzer
+// binary for
+#ifndef ENCODING_FOR_FUZZING
+# error "ENCODING_FOR_FUZZING was not provided to this fuzz target."
+#endif
+
+// 16-byte deterministic hash key.
+static unsigned char hash_key[16] = "FUZZING IS FUN!";
+
+static void XMLCALL
+start(void *userData, const XML_Char *name, const XML_Char **atts) {
+ (void)userData;
+ (void)name;
+ (void)atts;
+}
+static void XMLCALL
+end(void *userData, const XML_Char *name) {
+ (void)userData;
+ (void)name;
+}
+
+static void XMLCALL
+may_stop_character_handler(void *userData, const XML_Char *s, int len) {
+ XML_Parser parser = (XML_Parser)userData;
+ if (len > 1 && s[0] == 's') {
+ XML_StopParser(parser, s[1] == 'r' ? XML_FALSE : XML_TRUE);
+ }
+}
+
+static void
+ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
+ // Set the hash salt using siphash to generate a deterministic hash.
+ struct sipkey *key = sip_keyof(hash_key);
+ XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key));
+ (void)sip24_valid;
+
+ XML_SetUserData(p, p);
+ XML_SetElementHandler(p, start, end);
+ XML_SetCharacterDataHandler(p, may_stop_character_handler);
+ XML_Parse(p, (const XML_Char *)data, size, 0);
+ if (XML_Parse(p, (const XML_Char *)data, size, 1) == XML_STATUS_ERROR) {
+ XML_ErrorString(XML_GetErrorCode(p));
+ }
+ XML_GetCurrentLineNumber(p);
+ if (size % 2) {
+ XML_ParserReset(p, NULL);
+ }
+}
+
+int
+LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ XML_Parser parentParser = XML_ParserCreate(xstr(ENCODING_FOR_FUZZING));
+ assert(parentParser);
+ ParseOneInput(parentParser, data, size);
+ // not freed yet, but used later and freed then
+
+ XML_Parser namespaceParser = XML_ParserCreateNS(NULL, '!');
+ assert(namespaceParser);
+ ParseOneInput(namespaceParser, data, size);
+ XML_ParserFree(namespaceParser);
+
+ XML_Parser externalEntityParser
+ = XML_ExternalEntityParserCreate(parentParser, "e1", NULL);
+ assert(externalEntityParser);
+ ParseOneInput(externalEntityParser, data, size);
+ XML_ParserFree(externalEntityParser);
+
+ XML_Parser externalDtdParser
+ = XML_ExternalEntityParserCreate(parentParser, NULL, NULL);
+ assert(externalDtdParser);
+ ParseOneInput(externalDtdParser, data, size);
+ XML_ParserFree(externalDtdParser);
+
+ // finally frees this parser which served as parent
+ XML_ParserFree(parentParser);
+ return 0;
+}
diff --git a/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c b/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c
new file mode 100644
index 000000000000..0327aa9f952e
--- /dev/null
+++ b/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "expat.h"
+#include "siphash.h"
+
+// Macros to convert preprocessor macros to string literals. See
+// https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html
+#define xstr(s) str(s)
+#define str(s) #s
+
+// The encoder type that we wish to fuzz should come from the compile-time
+// definition `ENCODING_FOR_FUZZING`. This allows us to have a separate fuzzer
+// binary for
+#ifndef ENCODING_FOR_FUZZING
+# error "ENCODING_FOR_FUZZING was not provided to this fuzz target."
+#endif
+
+// 16-byte deterministic hash key.
+static unsigned char hash_key[16] = "FUZZING IS FUN!";
+
+static void XMLCALL
+start(void *userData, const XML_Char *name, const XML_Char **atts) {
+ (void)userData;
+ (void)name;
+ (void)atts;
+}
+static void XMLCALL
+end(void *userData, const XML_Char *name) {
+ (void)userData;
+ (void)name;
+}
+
+static void XMLCALL
+may_stop_character_handler(void *userData, const XML_Char *s, int len) {
+ XML_Parser parser = (XML_Parser)userData;
+ if (len > 1 && s[0] == 's') {
+ XML_StopParser(parser, s[1] == 'r' ? XML_FALSE : XML_TRUE);
+ }
+}
+
+static void
+ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
+ // Set the hash salt using siphash to generate a deterministic hash.
+ struct sipkey *key = sip_keyof(hash_key);
+ XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key));
+ (void)sip24_valid;
+
+ XML_SetUserData(p, p);
+ XML_SetElementHandler(p, start, end);
+ XML_SetCharacterDataHandler(p, may_stop_character_handler);
+ void *buf = XML_GetBuffer(p, size);
+ assert(buf);
+ memcpy(buf, data, size);
+ XML_ParseBuffer(p, size, 0);
+ buf = XML_GetBuffer(p, size);
+ if (buf == NULL) {
+ return;
+ }
+ memcpy(buf, data, size);
+ if (XML_ParseBuffer(p, size, 1) == XML_STATUS_ERROR) {
+ XML_ErrorString(XML_GetErrorCode(p));
+ }
+ XML_GetCurrentLineNumber(p);
+ if (size % 2) {
+ XML_ParserReset(p, NULL);
+ }
+}
+
+int
+LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size == 0)
+ return 0;
+
+ XML_Parser parentParser = XML_ParserCreate(xstr(ENCODING_FOR_FUZZING));
+ assert(parentParser);
+ ParseOneInput(parentParser, data, size);
+ // not freed yet, but used later and freed then
+
+ XML_Parser namespaceParser = XML_ParserCreateNS(NULL, '!');
+ assert(namespaceParser);
+ ParseOneInput(namespaceParser, data, size);
+ XML_ParserFree(namespaceParser);
+
+ XML_Parser externalEntityParser
+ = XML_ExternalEntityParserCreate(parentParser, "e1", NULL);
+ assert(externalEntityParser);
+ ParseOneInput(externalEntityParser, data, size);
+ XML_ParserFree(externalEntityParser);
+
+ XML_Parser externalDtdParser
+ = XML_ExternalEntityParserCreate(parentParser, NULL, NULL);
+ assert(externalDtdParser);
+ ParseOneInput(externalDtdParser, data, size);
+ XML_ParserFree(externalDtdParser);
+
+ // finally frees this parser which served as parent
+ XML_ParserFree(parentParser);
+ return 0;
+}
diff --git a/contrib/expat/lib/Makefile.am b/contrib/expat/lib/Makefile.am
index 8cb451ed4647..0e0185b59120 100644
--- a/contrib/expat/lib/Makefile.am
+++ b/contrib/expat/lib/Makefile.am
@@ -6,7 +6,9 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017 Tomasz KĹ‚oczko <kloczek@fedoraproject.org>
+# Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -34,16 +36,26 @@ include_HEADERS = \
expat_external.h
lib_LTLIBRARIES = libexpat.la
+noinst_LTLIBRARIES = libexpatinternal.la
libexpat_la_LDFLAGS = \
+ @AM_LDFLAGS@ \
+ @LIBM@ \
-no-undefined \
-version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
-libexpat_la_SOURCES = \
+libexpat_la_SOURCES =
+
+# This layer of indirection allows
+# the test suite to access internal symbols
+# despite compiling with -fvisibility=hidden
+libexpatinternal_la_SOURCES = \
xmlparse.c \
xmltok.c \
xmlrole.c
+libexpat_la_LIBADD = libexpatinternal.la
+
doc_DATA = \
../AUTHORS \
../Changes
@@ -62,8 +74,7 @@ EXTRA_DIST = \
iasciitab.h \
internal.h \
latin1tab.h \
- libexpat.def \
- libexpatw.def \
+ libexpat.def.cmake \
nametab.h \
siphash.h \
utf8tab.h \
diff --git a/contrib/expat/lib/Makefile.in b/contrib/expat/lib/Makefile.in
index bbd6a1885fc8..29584d8bbe74 100644
--- a/contrib/expat/lib/Makefile.in
+++ b/contrib/expat/lib/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,9 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017 Tomasz KĹ‚oczko <kloczek@fedoraproject.org>
+# Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -133,6 +135,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/conftools/ax-append-compile-flags.m4 \
$(top_srcdir)/conftools/ax-append-link-flags.m4 \
$(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx-11.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -171,9 +175,9 @@ am__uninstall_files_from_dir = { \
}
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(docdir)" \
"$(DESTDIR)$(includedir)"
-LTLIBRARIES = $(lib_LTLIBRARIES)
-libexpat_la_LIBADD =
-am_libexpat_la_OBJECTS = xmlparse.lo xmltok.lo xmlrole.lo
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libexpat_la_DEPENDENCIES = libexpatinternal.la
+am_libexpat_la_OBJECTS =
libexpat_la_OBJECTS = $(am_libexpat_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -182,6 +186,9 @@ am__v_lt_1 =
libexpat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libexpat_la_LDFLAGS) $(LDFLAGS) -o $@
+libexpatinternal_la_LIBADD =
+am_libexpatinternal_la_OBJECTS = xmlparse.lo xmltok.lo xmlrole.lo
+libexpatinternal_la_OBJECTS = $(am_libexpatinternal_la_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -218,8 +225,8 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
-SOURCES = $(libexpat_la_SOURCES)
-DIST_SOURCES = $(libexpat_la_SOURCES)
+SOURCES = $(libexpat_la_SOURCES) $(libexpatinternal_la_SOURCES)
+DIST_SOURCES = $(libexpat_la_SOURCES) $(libexpatinternal_la_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -244,14 +251,16 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in \
$(top_srcdir)/conftools/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
@@ -261,8 +270,10 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CPP = @CPP@
+CMAKE_SHARED_LIBRARY_PREFIX = @CMAKE_SHARED_LIBRARY_PREFIX@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -278,10 +289,20 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
+EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
+EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
+EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
+EXPAT_DTD = @EXPAT_DTD@
+EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
+EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
+EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FILEMAP = @FILEMAP@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -291,6 +312,8 @@ LD = @LD@
LDFLAGS = @LDFLAGS@
LIBAGE = @LIBAGE@
LIBCURRENT = @LIBCURRENT@
+LIBDIR_BASENAME = @LIBDIR_BASENAME@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBREVISION = @LIBREVISION@
LIBS = @LIBS@
@@ -299,6 +322,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -320,6 +344,9 @@ RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SO_MAJOR = @SO_MAJOR@
+SO_MINOR = @SO_MINOR@
+SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
@@ -330,6 +357,7 @@ ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_void_p = @ac_cv_sizeof_void_p@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -367,6 +395,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -381,15 +410,24 @@ include_HEADERS = \
expat_external.h
lib_LTLIBRARIES = libexpat.la
+noinst_LTLIBRARIES = libexpatinternal.la
libexpat_la_LDFLAGS = \
+ @AM_LDFLAGS@ \
+ @LIBM@ \
-no-undefined \
-version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
-libexpat_la_SOURCES = \
+libexpat_la_SOURCES =
+
+# This layer of indirection allows
+# the test suite to access internal symbols
+# despite compiling with -fvisibility=hidden
+libexpatinternal_la_SOURCES = \
xmlparse.c \
xmltok.c \
xmlrole.c
+libexpat_la_LIBADD = libexpatinternal.la
doc_DATA = \
../AUTHORS \
../Changes
@@ -402,8 +440,7 @@ EXTRA_DIST = \
iasciitab.h \
internal.h \
latin1tab.h \
- libexpat.def \
- libexpatw.def \
+ libexpat.def.cmake \
nametab.h \
siphash.h \
utf8tab.h \
@@ -418,7 +455,7 @@ all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -442,9 +479,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: $(am__configure_deps)
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
@@ -483,9 +520,23 @@ clean-libLTLIBRARIES:
rm -f $${locs}; \
}
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
libexpat.la: $(libexpat_la_OBJECTS) $(libexpat_la_DEPENDENCIES) $(EXTRA_libexpat_la_DEPENDENCIES)
$(AM_V_CCLD)$(libexpat_la_LINK) -rpath $(libdir) $(libexpat_la_OBJECTS) $(libexpat_la_LIBADD) $(LIBS)
+libexpatinternal.la: $(libexpatinternal_la_OBJECTS) $(libexpatinternal_la_DEPENDENCIES) $(EXTRA_libexpatinternal_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libexpatinternal_la_OBJECTS) $(libexpatinternal_la_LIBADD) $(LIBS)
+
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -622,7 +673,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -696,7 +746,7 @@ maintainer-clean-generic:
clean: clean-am
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
- mostlyclean-am
+ clean-noinstLTLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/xmlparse.Plo
@@ -773,16 +823,17 @@ uninstall-am: uninstall-docDATA uninstall-includeHEADERS \
.MAKE: install-am install-data-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
- clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
- ctags ctags-am distclean distclean-compile distclean-generic \
- distclean-libtool distclean-tags distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-data-hook install-docDATA install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-includeHEADERS install-info \
- install-info-am install-libLTLIBRARIES install-man install-pdf \
- install-pdf-am install-ps install-ps-am install-strip \
- installcheck installcheck-am installdirs maintainer-clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-data-hook install-docDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-includeHEADERS install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-docDATA \
diff --git a/contrib/expat/lib/ascii.h b/contrib/expat/lib/ascii.h
index c3587e57332b..1f594d2e54b4 100644
--- a/contrib/expat/lib/ascii.h
+++ b/contrib/expat/lib/ascii.h
@@ -6,8 +6,11 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 1999-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2007 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/lib/asciitab.h b/contrib/expat/lib/asciitab.h
index 63b1d1b4482e..af766fb24785 100644
--- a/contrib/expat/lib/asciitab.h
+++ b/contrib/expat/lib/asciitab.h
@@ -7,7 +7,9 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/lib/expat.h b/contrib/expat/lib/expat.h
index 48a6e2a32917..95464b0dd177 100644
--- a/contrib/expat/lib/expat.h
+++ b/contrib/expat/lib/expat.h
@@ -7,7 +7,17 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2000-2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016 Cristian RodrĂ­guez <crrodriguez@opensuse.org>
+ Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2022 Thijs Schreijer <thijs@thijsschreijer.nl>
+ Copyright (c) 2023 Hanno Böck <hanno@gentoo.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -115,7 +125,11 @@ enum XML_Error {
XML_ERROR_RESERVED_PREFIX_XMLNS,
XML_ERROR_RESERVED_NAMESPACE_URI,
/* Added in 2.2.1. */
- XML_ERROR_INVALID_ARGUMENT
+ XML_ERROR_INVALID_ARGUMENT,
+ /* Added in 2.3.0. */
+ XML_ERROR_NO_BUFFER,
+ /* Added in 2.4.0. */
+ XML_ERROR_AMPLIFICATION_LIMIT_BREACH
};
enum XML_Content_Type {
@@ -163,8 +177,10 @@ struct XML_cp {
};
/* This is called for an element declaration. See above for
- description of the model argument. It's the caller's responsibility
- to free model when finished with it.
+ description of the model argument. It's the user code's responsibility
+ to free model when finished with it. See XML_FreeContentModel.
+ There is no need to free the model from the handler, it can be kept
+ around and freed at a later stage.
*/
typedef void(XMLCALL *XML_ElementDeclHandler)(void *userData,
const XML_Char *name,
@@ -226,6 +242,17 @@ XML_ParserCreate(const XML_Char *encoding);
and the local part will be concatenated without any separator.
It is a programming error to use the separator '\0' with namespace
triplets (see XML_SetReturnNSTriplet).
+ If a namespace separator is chosen that can be part of a URI or
+ part of an XML name, splitting an expanded name back into its
+ 1, 2 or 3 original parts on application level in the element handler
+ may end up vulnerable, so these are advised against; sane choices for
+ a namespace separator are e.g. '\n' (line feed) and '|' (pipe).
+
+ Note that Expat does not validate namespace URIs (beyond encoding)
+ against RFC 3986 today (and is not required to do so with regard to
+ the XML 1.0 namespaces specification) but it may start doing that
+ in future releases. Before that, an application using Expat must
+ be ready to receive namespace URIs containing non-URI characters.
*/
XMLPARSEAPI(XML_Parser)
XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
@@ -244,7 +271,7 @@ XML_ParserCreate_MM(const XML_Char *encoding,
const XML_Memory_Handling_Suite *memsuite,
const XML_Char *namespaceSeparator);
-/* Prepare a parser object to be re-used. This is particularly
+/* Prepare a parser object to be reused. This is particularly
valuable when memory allocation overhead is disproportionately high,
such as when a large number of small documnents need to be parsed.
All handlers are cleared from the parser, except for the
@@ -306,7 +333,7 @@ typedef void(XMLCALL *XML_StartDoctypeDeclHandler)(void *userData,
const XML_Char *pubid,
int has_internal_subset);
-/* This is called for the start of the DOCTYPE declaration when the
+/* This is called for the end of the DOCTYPE declaration when the
closing > is encountered, but after processing any external
subset.
*/
@@ -318,7 +345,7 @@ typedef void(XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
For internal entities (<!ENTITY foo "bar">), value will
be non-NULL and systemId, publicID, and notationName will be NULL.
- The value string is NOT nul-terminated; the length is provided in
+ The value string is NOT null-terminated; the length is provided in
the value_length argument. Since it is legal to have zero-length
values, do not use this argument to test for internal entities.
@@ -513,7 +540,7 @@ typedef struct {
Otherwise it must return XML_STATUS_ERROR.
If info does not describe a suitable encoding, then the parser will
- return an XML_UNKNOWN_ENCODING error.
+ return an XML_ERROR_UNKNOWN_ENCODING error.
*/
typedef int(XMLCALL *XML_UnknownEncodingHandler)(void *encodingHandlerData,
const XML_Char *name,
@@ -707,7 +734,7 @@ XML_GetBase(XML_Parser parser);
/* Returns the number of the attribute/value pairs passed in last call
to the XML_StartElementHandler that were specified in the start-tag
rather than defaulted. Each attribute/value pair counts as 2; thus
- this correspondds to an index into the atts array passed to the
+ this corresponds to an index into the atts array passed to the
XML_StartElementHandler. Returns -1 if parser == NULL.
*/
XMLPARSEAPI(int)
@@ -716,7 +743,7 @@ XML_GetSpecifiedAttributeCount(XML_Parser parser);
/* Returns the index of the ID attribute passed in the last call to
XML_StartElementHandler, or -1 if there is no ID attribute or
parser == NULL. Each attribute/value pair counts as 2; thus this
- correspondds to an index into the atts array passed to the
+ corresponds to an index into the atts array passed to the
XML_StartElementHandler.
*/
XMLPARSEAPI(int)
@@ -926,7 +953,7 @@ XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
XMLPARSEAPI(int)
XML_GetCurrentByteCount(XML_Parser parser);
-/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
+/* If XML_CONTEXT_BYTES is >=1, returns the input buffer, sets
the integer pointed to by offset to the offset within this buffer
of the current parse position, and sets the integer pointed to by size
to the size of this buffer (the number of input bytes). Otherwise
@@ -997,7 +1024,12 @@ enum XML_FeatureEnum {
XML_FEATURE_SIZEOF_XML_LCHAR,
XML_FEATURE_NS,
XML_FEATURE_LARGE_SIZE,
- XML_FEATURE_ATTR_INFO
+ XML_FEATURE_ATTR_INFO,
+ /* Added in Expat 2.4.0. */
+ XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
+ XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
+ /* Added in Expat 2.6.0. */
+ XML_FEATURE_GE
/* Additional features must be added to the end of this enum. */
};
@@ -1010,12 +1042,30 @@ typedef struct {
XMLPARSEAPI(const XML_Feature *)
XML_GetFeatureList(void);
+#if XML_GE == 1
+/* Added in Expat 2.4.0 for XML_DTD defined and
+ * added in Expat 2.6.0 for XML_GE == 1. */
+XMLPARSEAPI(XML_Bool)
+XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ XML_Parser parser, float maximumAmplificationFactor);
+
+/* Added in Expat 2.4.0 for XML_DTD defined and
+ * added in Expat 2.6.0 for XML_GE == 1. */
+XMLPARSEAPI(XML_Bool)
+XML_SetBillionLaughsAttackProtectionActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes);
+#endif
+
+/* Added in Expat 2.6.0. */
+XMLPARSEAPI(XML_Bool)
+XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
+
/* Expat follows the semantic versioning convention.
- See http://semver.org.
+ See https://semver.org
*/
#define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 2
-#define XML_MICRO_VERSION 9
+#define XML_MINOR_VERSION 6
+#define XML_MICRO_VERSION 0
#ifdef __cplusplus
}
diff --git a/contrib/expat/lib/expat_external.h b/contrib/expat/lib/expat_external.h
index b3b6e74d9d20..8829f7709104 100644
--- a/contrib/expat/lib/expat_external.h
+++ b/contrib/expat/lib/expat_external.h
@@ -7,7 +7,14 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2000-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016 Cristian RodrĂ­guez <crrodriguez@opensuse.org>
+ Copyright (c) 2016-2019 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2018 Yury Gribov <tetra2005@gmail.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/lib/iasciitab.h b/contrib/expat/lib/iasciitab.h
index ea97cfcf678e..5d8646f2a318 100644
--- a/contrib/expat/lib/iasciitab.h
+++ b/contrib/expat/lib/iasciitab.h
@@ -7,7 +7,9 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/lib/internal.h b/contrib/expat/lib/internal.h
index 60913dab762f..cce71e4c5164 100644
--- a/contrib/expat/lib/internal.h
+++ b/contrib/expat/lib/internal.h
@@ -25,8 +25,13 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2018 Yury Gribov <tetra2005@gmail.com>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -101,22 +106,63 @@
# endif
#endif
+#include <limits.h> // ULONG_MAX
+
+#if defined(_WIN32) \
+ && (! defined(__USE_MINGW_ANSI_STDIO) \
+ || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0))
+# define EXPAT_FMT_ULL(midpart) "%" midpart "I64u"
+# if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "I64u"
+# else
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
+# endif
+#else
+# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
+# if ! defined(ULONG_MAX)
+# error Compiler did not define ULONG_MAX for us
+# elif ULONG_MAX == 18446744073709551615u // 2^64-1
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
+# else
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
+# endif
+#endif
+
#ifndef UNUSED_P
# define UNUSED_P(p) (void)p
#endif
+/* NOTE BEGIN If you ever patch these defaults to greater values
+ for non-attack XML payload in your environment,
+ please file a bug report with libexpat. Thank you!
+*/
+#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT \
+ 100.0f
+#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \
+ 8388608 // 8 MiB, 2^23
+/* NOTE END */
+
+#include "expat.h" // so we can use type XML_Parser below
+
#ifdef __cplusplus
extern "C" {
#endif
-#ifdef XML_ENABLE_VISIBILITY
-# if XML_ENABLE_VISIBILITY
-__attribute__((visibility("default")))
-# endif
+void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
+ const char **fromLimRef);
+
+#if XML_GE == 1
+unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
+unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
+const char *unsignedCharToPrintable(unsigned char c);
#endif
-void
-_INTERNAL_trim_to_complete_utf8_characters(const char *from,
- const char **fromLimRef);
+
+extern XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c
+extern unsigned int g_parseAttempts; // used for testing only
#ifdef __cplusplus
}
diff --git a/contrib/expat/lib/latin1tab.h b/contrib/expat/lib/latin1tab.h
index 6f916041355a..b681d278af65 100644
--- a/contrib/expat/lib/latin1tab.h
+++ b/contrib/expat/lib/latin1tab.h
@@ -7,7 +7,9 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/lib/loadlibrary.c b/contrib/expat/lib/loadlibrary.c
deleted file mode 100644
index 35fdf98bce6c..000000000000
--- a/contrib/expat/lib/loadlibrary.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2016 - 2017, Steve Holme, <steve_holme@hotmail.com>.
- * Copyright (C) 2017, Expat development team
- *
- * All rights reserved.
- * Licensed under the MIT license:
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
- * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
- * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Except as contained in this notice, the name of a copyright holder shall
- * not be used in advertising or otherwise to promote the sale, use or other
- * dealings in this Software without prior written authorization of the
- * copyright holder.
- *
- ***************************************************************************/
-
-#if defined(_WIN32)
-
-#include <windows.h>
-#include <tchar.h>
-
-
-HMODULE _Expat_LoadLibrary(LPCTSTR filename);
-
-
-#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
-#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
-#endif
-
-#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
-#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
-#endif
-
-/* We use our own typedef here since some headers might lack these */
-typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
-
-/* See function definitions in winbase.h */
-#ifdef UNICODE
-# ifdef _WIN32_WCE
-# define LOADLIBARYEX L"LoadLibraryExW"
-# else
-# define LOADLIBARYEX "LoadLibraryExW"
-# endif
-#else
-# define LOADLIBARYEX "LoadLibraryExA"
-#endif
-
-
-/*
- * _Expat_LoadLibrary()
- *
- * This is used to dynamically load DLLs using the most secure method available
- * for the version of Windows that we are running on.
- *
- * Parameters:
- *
- * filename [in] - The filename or full path of the DLL to load. If only the
- * filename is passed then the DLL will be loaded from the
- * Windows system directory.
- *
- * Returns the handle of the module on success; otherwise NULL.
- */
-HMODULE _Expat_LoadLibrary(LPCTSTR filename)
-{
- HMODULE hModule = NULL;
- LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
-
- /* Get a handle to kernel32 so we can access it's functions at runtime */
- HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
- if(!hKernel32)
- return NULL; /* LCOV_EXCL_LINE */
-
- /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
- and above */
- pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX);
-
- /* Detect if there's already a path in the filename and load the library if
- there is. Note: Both back slashes and forward slashes have been supported
- since the earlier days of DOS at an API level although they are not
- supported by command prompt */
- if(_tcspbrk(filename, TEXT("\\/"))) {
- /** !checksrc! disable BANNEDFUNC 1 **/
- hModule = pLoadLibraryEx ?
- pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
- LoadLibrary(filename);
- }
- /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only
- supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
- Server 2008 R2 with this patch or natively on Windows 8 and above */
- else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
- /* Load the DLL from the Windows system directory */
- hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
- }
- else {
- /* Attempt to get the Windows system path */
- UINT systemdirlen = GetSystemDirectory(NULL, 0);
- if(systemdirlen) {
- /* Allocate space for the full DLL path (Room for the null terminator
- is included in systemdirlen) */
- size_t filenamelen = _tcslen(filename);
- TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
- if(path && GetSystemDirectory(path, systemdirlen)) {
- /* Calculate the full DLL path */
- _tcscpy(path + _tcslen(path), TEXT("\\"));
- _tcscpy(path + _tcslen(path), filename);
-
- /* Load the DLL from the Windows system directory */
- /** !checksrc! disable BANNEDFUNC 1 **/
- hModule = pLoadLibraryEx ?
- pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
- LoadLibrary(path);
-
- }
- free(path);
- }
- }
-
- return hModule;
-}
-
-#else /* defined(_WIN32) */
-
-/* ISO C requires a translation unit to contain at least one declaration
- [-Wempty-translation-unit] */
-typedef int _TRANSLATION_UNIT_LOAD_LIBRARY_C_NOT_EMTPY;
-
-#endif /* defined(_WIN32) */
diff --git a/contrib/expat/lib/nametab.h b/contrib/expat/lib/nametab.h
index 3681df348eeb..63485446b967 100644
--- a/contrib/expat/lib/nametab.h
+++ b/contrib/expat/lib/nametab.h
@@ -6,8 +6,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/lib/siphash.h b/contrib/expat/lib/siphash.h
index bfee65a332f1..a1ed99e687bd 100644
--- a/contrib/expat/lib/siphash.h
+++ b/contrib/expat/lib/siphash.h
@@ -11,6 +11,9 @@
* --------------------------------------------------------------------------
* HISTORY:
*
+ * 2020-10-03 (Sebastian Pipping)
+ * - Drop support for Visual Studio 9.0/2008 and earlier
+ *
* 2019-08-03 (Sebastian Pipping)
* - Mark part of sip24_valid as to be excluded from clang-format
* - Re-format code using clang-format 9
@@ -96,22 +99,14 @@
#define SIPHASH_H
#include <stddef.h> /* size_t */
-
-#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
-/* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-#else
-# include <stdint.h> /* uint64_t uint32_t uint8_t */
-#endif
+#include <stdint.h> /* uint64_t uint32_t uint8_t */
/*
* Workaround to not require a C++11 compiler for using ULL suffix
* if this code is included and compiled as C++; related GCC warning is:
* warning: use of C++11 long long integer constant [-Wlong-long]
*/
-#define _SIP_ULL(high, low) (((uint64_t)high << 32) | low)
+#define SIP_ULL(high, low) ((((uint64_t)high) << 32) | (low))
#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
@@ -195,10 +190,10 @@ sip_round(struct siphash *H, const int rounds) {
static struct siphash *
sip24_init(struct siphash *H, const struct sipkey *key) {
- H->v0 = _SIP_ULL(0x736f6d65U, 0x70736575U) ^ key->k[0];
- H->v1 = _SIP_ULL(0x646f7261U, 0x6e646f6dU) ^ key->k[1];
- H->v2 = _SIP_ULL(0x6c796765U, 0x6e657261U) ^ key->k[0];
- H->v3 = _SIP_ULL(0x74656462U, 0x79746573U) ^ key->k[1];
+ H->v0 = SIP_ULL(0x736f6d65U, 0x70736575U) ^ key->k[0];
+ H->v1 = SIP_ULL(0x646f7261U, 0x6e646f6dU) ^ key->k[1];
+ H->v2 = SIP_ULL(0x6c796765U, 0x6e657261U) ^ key->k[0];
+ H->v3 = SIP_ULL(0x74656462U, 0x79746573U) ^ key->k[1];
H->p = H->buf;
H->c = 0;
diff --git a/contrib/expat/lib/utf8tab.h b/contrib/expat/lib/utf8tab.h
index a22986acbb95..88efcf91cc16 100644
--- a/contrib/expat/lib/utf8tab.h
+++ b/contrib/expat/lib/utf8tab.h
@@ -7,7 +7,9 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/lib/xmlparse.c b/contrib/expat/lib/xmlparse.c
index 3aaf35b94b1d..aaf0fa9c8f96 100644
--- a/contrib/expat/lib/xmlparse.c
+++ b/contrib/expat/lib/xmlparse.c
@@ -1,4 +1,4 @@
-/* f519f27c7c3b79fee55aeb8b1e53b7384b079d9118bf3a62eb3a60986a6742f2 (2.2.9+)
+/* 628e24d4966bedbd4800f6ed128d06d29703765b4bce12d3b7f099f90f842fc9 (2.6.0+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -7,7 +7,38 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2000-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016 Eric Rahm <erahm@mozilla.com>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016 Gaurav <g.gupta@samsung.com>
+ Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
+ Copyright (c) 2016 Gustavo Grieco <gustavo.grieco@imag.fr>
+ Copyright (c) 2016 Pascal Cuoq <cuoq@trust-in-soft.com>
+ Copyright (c) 2016 Ed Schouten <ed@nuxi.nl>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Václav Slavík <vaclav@slavik.io>
+ Copyright (c) 2017 Viktor Szakats <commit@vsz.me>
+ Copyright (c) 2017 Chanho Park <chanho61.park@samsung.com>
+ Copyright (c) 2017 Rolf Eike Beer <eike@sf-mail.de>
+ Copyright (c) 2017 Hans Wennborg <hans@chromium.org>
+ Copyright (c) 2018 Anton Maklakov <antmak.pub@gmail.com>
+ Copyright (c) 2018 Benjamin Peterson <benjamin@python.org>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2018 Mariusz Zaborski <oshogbo@vexillium.org>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2019-2020 Ben Wagner <bungeman@chromium.org>
+ Copyright (c) 2019 Vadim Zeitlin <vadim@zeitlins.org>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2022 Samanta Navarro <ferivoz@riseup.net>
+ Copyright (c) 2022 Jeffrey Walton <noloader@gmail.com>
+ Copyright (c) 2022 Jann Horn <jannh@google.com>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
+ Copyright (c) 2023 Owain Davies <owaind@bath.edu>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,8 +61,27 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#if ! defined(_GNU_SOURCE)
-# define _GNU_SOURCE 1 /* syscall prototype */
+#define XML_BUILDING_EXPAT 1
+
+#include "expat_config.h"
+
+#if ! defined(XML_GE) || (1 - XML_GE - 1 == 2) || (XML_GE < 0) || (XML_GE > 1)
+# error XML_GE (for general entities) must be defined, non-empty, either 1 or 0 (0 to disable, 1 to enable; 1 is a common default)
+#endif
+
+#if defined(XML_DTD) && XML_GE == 0
+# error Either undefine XML_DTD or define XML_GE to 1.
+#endif
+
+#if ! defined(XML_CONTEXT_BYTES) || (1 - XML_CONTEXT_BYTES - 1 == 2) \
+ || (XML_CONTEXT_BYTES + 0 < 0)
+# error XML_CONTEXT_BYTES must be defined, non-empty and >=0 (0 to disable, >=1 to enable; 1024 is a common default)
+#endif
+
+#if defined(HAVE_SYSCALL_GETRANDOM)
+# if ! defined(_GNU_SOURCE)
+# define _GNU_SOURCE 1 /* syscall prototype */
+# endif
#endif
#ifdef _WIN32
@@ -41,12 +91,15 @@
# endif
#endif
+#include <stdbool.h>
#include <stddef.h>
#include <string.h> /* memset(), memcpy() */
#include <assert.h>
#include <limits.h> /* UINT_MAX */
#include <stdio.h> /* fprintf */
#include <stdlib.h> /* getenv, rand_s */
+#include <stdint.h> /* uintptr_t */
+#include <math.h> /* isnan */
#ifdef _WIN32
# define getpid GetCurrentProcessId
@@ -58,13 +111,9 @@
# include <errno.h>
#endif
-#define XML_BUILDING_EXPAT 1
-
#ifdef _WIN32
# include "winconfig.h"
-#elif defined(HAVE_EXPAT_CONFIG_H)
-# include <expat_config.h>
-#endif /* ndef _WIN32 */
+#endif
#include "ascii.h"
#include "expat.h"
@@ -99,14 +148,14 @@
enabled. For end user security, that is probably not what you want. \
\
Your options include: \
- * Linux + glibc >=2.25 (getrandom): HAVE_GETRANDOM, \
- * Linux + glibc <2.25 (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \
- * BSD / macOS >=10.7 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
- * BSD / macOS <10.7 (arc4random): HAVE_ARC4RANDOM, \
+ * Linux >=3.17 + glibc >=2.25 (getrandom): HAVE_GETRANDOM, \
+ * Linux >=3.17 + glibc (including <2.25) (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \
+ * BSD / macOS >=10.7 / glibc >=2.36 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
+ * BSD / macOS (including <10.7) / glibc >=2.36 (arc4random): HAVE_ARC4RANDOM, \
* libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \
* libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \
- * Linux / BSD / macOS (/dev/urandom): XML_DEV_URANDOM \
- * Windows (rand_s): _WIN32. \
+ * Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \
+ * Windows >=Vista (rand_s): _WIN32. \
\
If insist on not using any of these, bypass this error by defining \
XML_POOR_ENTROPY; you have been warned. \
@@ -121,9 +170,7 @@
# define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
# define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
# define XmlEncode XmlUtf16Encode
-/* Using pointer subtraction to convert to integer type. */
-# define MUST_CONVERT(enc, s) \
- (! (enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
+# define MUST_CONVERT(enc, s) (! (enc)->isUtf16 || (((uintptr_t)(s)) & 1))
typedef unsigned short ICHAR;
#else
# define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
@@ -168,6 +215,8 @@ typedef char ICHAR;
/* Do safe (NULL-aware) pointer arithmetic */
#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
+#define EXPAT_MIN(a, b) (((a) < (b)) ? (a) : (b))
+
#include "internal.h"
#include "xmltok.h"
#include "xmlrole.h"
@@ -251,7 +300,7 @@ typedef struct {
XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
contain the 'raw' name as well.
- A parser re-uses these structures, maintaining a list of allocated
+ A parser reuses these structures, maintaining a list of allocated
TAG objects in a free list.
*/
typedef struct tag {
@@ -373,6 +422,31 @@ typedef struct open_internal_entity {
XML_Bool betweenDecl; /* WFC: PE Between Declarations */
} OPEN_INTERNAL_ENTITY;
+enum XML_Account {
+ XML_ACCOUNT_DIRECT, /* bytes directly passed to the Expat parser */
+ XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity
+ expansion */
+ XML_ACCOUNT_NONE /* i.e. do not account, was accounted already */
+};
+
+#if XML_GE == 1
+typedef unsigned long long XmlBigCount;
+typedef struct accounting {
+ XmlBigCount countBytesDirect;
+ XmlBigCount countBytesIndirect;
+ unsigned long debugLevel;
+ float maximumAmplificationFactor; // >=1.0
+ unsigned long long activationThresholdBytes;
+} ACCOUNTING;
+
+typedef struct entity_stats {
+ unsigned int countEverOpened;
+ unsigned int currentDepth;
+ unsigned int maximumDepthSeen;
+ unsigned long debugLevel;
+} ENTITY_STATS;
+#endif /* XML_GE == 1 */
+
typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
const char *end, const char **endPtr);
@@ -403,43 +477,55 @@ static enum XML_Error initializeEncoding(XML_Parser parser);
static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
const char *s, const char *end, int tok,
const char *next, const char **nextPtr,
- XML_Bool haveMore, XML_Bool allowClosingDoctype);
+ XML_Bool haveMore, XML_Bool allowClosingDoctype,
+ enum XML_Account account);
static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
XML_Bool betweenDecl);
static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc, const char *start,
const char *end, const char **endPtr,
- XML_Bool haveMore);
-static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
+ XML_Bool haveMore, enum XML_Account account);
+static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *enc,
const char **startPtr, const char *end,
- const char **nextPtr, XML_Bool haveMore);
+ const char **nextPtr, XML_Bool haveMore,
+ enum XML_Account account);
#ifdef XML_DTD
-static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
+static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *enc,
const char **startPtr, const char *end,
const char **nextPtr, XML_Bool haveMore);
#endif /* XML_DTD */
static void freeBindings(XML_Parser parser, BINDING *bindings);
-static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
- const char *s, TAG_NAME *tagNamePtr,
- BINDING **bindingsPtr);
+static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
+ const char *attStr, TAG_NAME *tagNamePtr,
+ BINDING **bindingsPtr,
+ enum XML_Account account);
static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
const ATTRIBUTE_ID *attId, const XML_Char *uri,
BINDING **bindingsPtr);
-static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
- XML_Bool isId, const XML_Char *dfltValue,
- XML_Parser parser);
-static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
- XML_Bool isCdata, const char *,
- const char *, STRING_POOL *);
-static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
- XML_Bool isCdata, const char *,
- const char *, STRING_POOL *);
+static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId,
+ XML_Bool isCdata, XML_Bool isId,
+ const XML_Char *value, XML_Parser parser);
+static enum XML_Error storeAttributeValue(XML_Parser parser,
+ const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool,
+ enum XML_Account account);
+static enum XML_Error appendAttributeValue(XML_Parser parser,
+ const ENCODING *enc,
+ XML_Bool isCdata, const char *ptr,
+ const char *end, STRING_POOL *pool,
+ enum XML_Account account);
static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end);
-static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType);
+#if XML_GE == 1
static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
- const char *start, const char *end);
+ const char *start, const char *end,
+ enum XML_Account account);
+#else
+static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
+#endif
static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end);
static int reportComment(XML_Parser parser, const ENCODING *enc,
@@ -459,21 +545,22 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity,
const XML_Memory_Handling_Suite *ms);
static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
const XML_Memory_Handling_Suite *ms);
-static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *, STRING_POOL *,
- const HASH_TABLE *);
+static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
+ STRING_POOL *newPool, const HASH_TABLE *oldTable);
static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name,
size_t createSize);
-static void FASTCALL hashTableInit(HASH_TABLE *,
+static void FASTCALL hashTableInit(HASH_TABLE *table,
const XML_Memory_Handling_Suite *ms);
-static void FASTCALL hashTableClear(HASH_TABLE *);
-static void FASTCALL hashTableDestroy(HASH_TABLE *);
-static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
-static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
+static void FASTCALL hashTableClear(HASH_TABLE *table);
+static void FASTCALL hashTableDestroy(HASH_TABLE *table);
+static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter,
+ const HASH_TABLE *table);
+static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter);
-static void FASTCALL poolInit(STRING_POOL *,
+static void FASTCALL poolInit(STRING_POOL *pool,
const XML_Memory_Handling_Suite *ms);
-static void FASTCALL poolClear(STRING_POOL *);
-static void FASTCALL poolDestroy(STRING_POOL *);
+static void FASTCALL poolClear(STRING_POOL *pool);
+static void FASTCALL poolDestroy(STRING_POOL *pool);
static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
const char *ptr, const char *end);
static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
@@ -503,8 +590,35 @@ static XML_Parser parserCreate(const XML_Char *encodingName,
static void parserInit(XML_Parser parser, const XML_Char *encodingName);
+#if XML_GE == 1
+static float accountingGetCurrentAmplification(XML_Parser rootParser);
+static void accountingReportStats(XML_Parser originParser, const char *epilog);
+static void accountingOnAbort(XML_Parser originParser);
+static void accountingReportDiff(XML_Parser rootParser,
+ unsigned int levelsAwayFromRootParser,
+ const char *before, const char *after,
+ ptrdiff_t bytesMore, int source_line,
+ enum XML_Account account);
+static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok,
+ const char *before, const char *after,
+ int source_line,
+ enum XML_Account account);
+
+static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity,
+ const char *action, int sourceLine);
+static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
+ int sourceLine);
+static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
+ int sourceLine);
+
+static XML_Parser getRootParserOf(XML_Parser parser,
+ unsigned int *outLevelDiff);
+#endif /* XML_GE == 1 */
+
+static unsigned long getDebugLevel(const char *variableName,
+ unsigned long defaultDebugLevel);
+
#define poolStart(pool) ((pool)->start)
-#define poolEnd(pool) ((pool)->ptr)
#define poolLength(pool) ((pool)->ptr - (pool)->start)
#define poolChop(pool) ((void)--(pool->ptr))
#define poolLastChar(pool) (((pool)->ptr)[-1])
@@ -515,21 +629,35 @@ static void parserInit(XML_Parser parser, const XML_Char *encodingName);
? 0 \
: ((*((pool)->ptr)++ = c), 1))
+XML_Bool g_reparseDeferralEnabledDefault = XML_TRUE; // write ONLY in runtests.c
+unsigned int g_parseAttempts = 0; // used for testing only
+
struct XML_ParserStruct {
/* The first member must be m_userData so that the XML_GetUserData
macro works. */
void *m_userData;
void *m_handlerArg;
- char *m_buffer;
+
+ // How the four parse buffer pointers below relate in time and space:
+ //
+ // m_buffer <= m_bufferPtr <= m_bufferEnd <= m_bufferLim
+ // | | | |
+ // <--parsed-->| | |
+ // <---parsing--->| |
+ // <--unoccupied-->|
+ // <---------total-malloced/realloced-------->|
+
+ char *m_buffer; // malloc/realloc base pointer of parse buffer
const XML_Memory_Handling_Suite m_mem;
- /* first character to be parsed */
- const char *m_bufferPtr;
- /* past last character to be parsed */
- char *m_bufferEnd;
- /* allocated end of m_buffer */
- const char *m_bufferLim;
+ const char *m_bufferPtr; // first character to be parsed
+ char *m_bufferEnd; // past last character to be parsed
+ const char *m_bufferLim; // allocated end of m_buffer
+
XML_Index m_parseEndByteIndex;
const char *m_parseEndPtr;
+ size_t m_partialTokenBytesBefore; /* used in heuristic to avoid O(n^2) */
+ XML_Bool m_reparseDeferralEnabled;
+ int m_lastBufferRequestSize;
XML_Char *m_dataBuf;
XML_Char *m_dataBufEnd;
XML_StartElementHandler m_startElementHandler;
@@ -616,6 +744,10 @@ struct XML_ParserStruct {
enum XML_ParamEntityParsing m_paramEntityParsing;
#endif
unsigned long m_hash_secret_salt;
+#if XML_GE == 1
+ ACCOUNTING m_accounting;
+ ENTITY_STATS m_entity_stats;
+#endif
};
#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
@@ -629,11 +761,11 @@ XML_ParserCreate(const XML_Char *encodingName) {
XML_Parser XMLCALL
XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
- XML_Char tmp[2];
- *tmp = nsSep;
+ XML_Char tmp[2] = {nsSep, 0};
return XML_ParserCreate_MM(encodingName, NULL, tmp);
}
+// "xml=http://www.w3.org/XML/1998/namespace"
static const XML_Char implicitContext[]
= {ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h,
ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
@@ -736,6 +868,15 @@ writeRandomBytes_arc4random(void *target, size_t count) {
#ifdef _WIN32
+/* Provide declaration of rand_s() for MinGW-32 (not 64, which has it),
+ as it didn't declare it in its header prior to version 5.3.0 of its
+ runtime package (mingwrt, containing stdlib.h). The upstream fix
+ was introduced at https://osdn.net/projects/mingw/ticket/39658 . */
+# if defined(__MINGW32__) && defined(__MINGW32_VERSION) \
+ && __MINGW32_VERSION < 5003000L && ! defined(__MINGW64_VERSION_MAJOR)
+__declspec(dllimport) int rand_s(unsigned int *);
+# endif
+
/* Obtain entropy on Windows using the rand_s() function which
* generates cryptographically secure random numbers. Internally it
* uses RtlGenRandom API which is present in Windows XP and later.
@@ -791,9 +932,8 @@ gather_time_entropy(void) {
static unsigned long
ENTROPY_DEBUG(const char *label, unsigned long entropy) {
- const char *const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
- if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
- fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
+ if (getDebugLevel("EXPAT_ENTROPY_DEBUG", 0) >= 1u) {
+ fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
(int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
}
return entropy;
@@ -849,6 +989,47 @@ get_hash_secret_salt(XML_Parser parser) {
return parser->m_hash_secret_salt;
}
+static enum XML_Error
+callProcessor(XML_Parser parser, const char *start, const char *end,
+ const char **endPtr) {
+ const size_t have_now = EXPAT_SAFE_PTR_DIFF(end, start);
+
+ if (parser->m_reparseDeferralEnabled
+ && ! parser->m_parsingStatus.finalBuffer) {
+ // Heuristic: don't try to parse a partial token again until the amount of
+ // available data has increased significantly.
+ const size_t had_before = parser->m_partialTokenBytesBefore;
+ // ...but *do* try anyway if we're close to causing a reallocation.
+ size_t available_buffer
+ = EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
+#if XML_CONTEXT_BYTES > 0
+ available_buffer -= EXPAT_MIN(available_buffer, XML_CONTEXT_BYTES);
+#endif
+ available_buffer
+ += EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd);
+ // m_lastBufferRequestSize is never assigned a value < 0, so the cast is ok
+ const bool enough
+ = (have_now >= 2 * had_before)
+ || ((size_t)parser->m_lastBufferRequestSize > available_buffer);
+
+ if (! enough) {
+ *endPtr = start; // callers may expect this to be set
+ return XML_ERROR_NONE;
+ }
+ }
+ g_parseAttempts += 1;
+ const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
+ if (ret == XML_ERROR_NONE) {
+ // if we consumed nothing, remember what we had on this parse attempt.
+ if (*endPtr == start) {
+ parser->m_partialTokenBytesBefore = have_now;
+ } else {
+ parser->m_partialTokenBytesBefore = 0;
+ }
+ }
+ return ret;
+}
+
static XML_Bool /* only valid for root parser */
startParsing(XML_Parser parser) {
/* hash functions must be initialized before setContext() is called */
@@ -878,7 +1059,7 @@ parserCreate(const XML_Char *encodingName,
if (memsuite) {
XML_Memory_Handling_Suite *mtemp;
- parser = (XML_Parser)memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+ parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
if (parser != NULL) {
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
mtemp->malloc_fcn = memsuite->malloc_fcn;
@@ -970,6 +1151,14 @@ parserCreate(const XML_Char *encodingName,
parserInit(parser, encodingName);
if (encodingName && ! parser->m_protocolEncodingName) {
+ if (dtd) {
+ // We need to stop the upcoming call to XML_ParserFree from happily
+ // destroying parser->m_dtd because the DTD is shared with the parent
+ // parser and the only guard that keeps XML_ParserFree from destroying
+ // parser->m_dtd is parser->m_isParamEntity but it will be set to
+ // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all).
+ parser->m_dtd = NULL;
+ }
XML_ParserFree(parser);
return NULL;
}
@@ -1022,6 +1211,9 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_bufferEnd = parser->m_buffer;
parser->m_parseEndByteIndex = 0;
parser->m_parseEndPtr = NULL;
+ parser->m_partialTokenBytesBefore = 0;
+ parser->m_reparseDeferralEnabled = g_reparseDeferralEnabledDefault;
+ parser->m_lastBufferRequestSize = 0;
parser->m_declElementType = NULL;
parser->m_declAttributeId = NULL;
parser->m_declEntity = NULL;
@@ -1055,6 +1247,18 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif
parser->m_hash_secret_salt = 0;
+
+#if XML_GE == 1
+ memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
+ parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
+ parser->m_accounting.maximumAmplificationFactor
+ = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
+ parser->m_accounting.activationThresholdBytes
+ = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
+
+ memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
+ parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
+#endif
}
/* moves list of bindings to m_freeBindingList */
@@ -1179,6 +1383,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
to worry which hash secrets each table has.
*/
unsigned long oldhash_secret_salt;
+ XML_Bool oldReparseDeferralEnabled;
/* Validate the oldParser parameter before we pull everything out of it */
if (oldParser == NULL)
@@ -1223,6 +1428,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
to worry which hash secrets each table has.
*/
oldhash_secret_salt = parser->m_hash_secret_salt;
+ oldReparseDeferralEnabled = parser->m_reparseDeferralEnabled;
#ifdef XML_DTD
if (! context)
@@ -1235,8 +1441,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
would be otherwise.
*/
if (parser->m_ns) {
- XML_Char tmp[2];
- *tmp = parser->m_namespaceSeparator;
+ XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
} else {
parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
@@ -1276,6 +1481,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
parser->m_ns_triplets = oldns_triplets;
parser->m_hash_secret_salt = oldhash_secret_salt;
+ parser->m_reparseDeferralEnabled = oldReparseDeferralEnabled;
parser->m_parentParser = oldParser;
#ifdef XML_DTD
parser->m_paramEntityParsing = oldParamEntityParsing;
@@ -1401,6 +1607,7 @@ XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) {
parser->m_useForeignDTD = useDTD;
return XML_ERROR_NONE;
#else
+ UNUSED_P(useDTD);
return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
#endif
}
@@ -1729,71 +1936,27 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
parser->m_parsingStatus.parsing = XML_PARSING;
}
- if (len == 0) {
- parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- if (! isFinal)
- return XML_STATUS_OK;
- parser->m_positionPtr = parser->m_bufferPtr;
- parser->m_parseEndPtr = parser->m_bufferEnd;
-
- /* If data are left over from last buffer, and we now know that these
- data are the final chunk of input, then we have to check them again
- to detect errors based on that fact.
- */
- parser->m_errorCode
- = parser->m_processor(parser, parser->m_bufferPtr,
- parser->m_parseEndPtr, &parser->m_bufferPtr);
-
- if (parser->m_errorCode == XML_ERROR_NONE) {
- switch (parser->m_parsingStatus.parsing) {
- case XML_SUSPENDED:
- /* It is hard to be certain, but it seems that this case
- * cannot occur. This code is cleaning up a previous parse
- * with no new data (since len == 0). Changing the parsing
- * state requires getting to execute a handler function, and
- * there doesn't seem to be an opportunity for that while in
- * this circumstance.
- *
- * Given the uncertainty, we retain the code but exclude it
- * from coverage tests.
- *
- * LCOV_EXCL_START
- */
- XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
- parser->m_bufferPtr, &parser->m_position);
- parser->m_positionPtr = parser->m_bufferPtr;
- return XML_STATUS_SUSPENDED;
- /* LCOV_EXCL_STOP */
- case XML_INITIALIZED:
- case XML_PARSING:
- parser->m_parsingStatus.parsing = XML_FINISHED;
- /* fall through */
- default:
- return XML_STATUS_OK;
- }
- }
- parser->m_eventEndPtr = parser->m_eventPtr;
- parser->m_processor = errorProcessor;
- return XML_STATUS_ERROR;
- }
-#ifndef XML_CONTEXT_BYTES
- else if (parser->m_bufferPtr == parser->m_bufferEnd) {
+#if XML_CONTEXT_BYTES == 0
+ if (parser->m_bufferPtr == parser->m_bufferEnd) {
const char *end;
int nLeftOver;
enum XML_Status result;
/* Detect overflow (a+b > MAX <==> b > MAX-a) */
- if (len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) {
+ if ((XML_Size)len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
parser->m_eventPtr = parser->m_eventEndPtr = NULL;
parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
+ // though this isn't a buffer request, we assume that `len` is the app's
+ // preferred buffer fill size, and therefore save it here.
+ parser->m_lastBufferRequestSize = len;
parser->m_parseEndByteIndex += len;
parser->m_positionPtr = s;
parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
parser->m_errorCode
- = parser->m_processor(parser, s, parser->m_parseEndPtr = s + len, &end);
+ = callProcessor(parser, s, parser->m_parseEndPtr = s + len, &end);
if (parser->m_errorCode != XML_ERROR_NONE) {
parser->m_eventEndPtr = parser->m_eventPtr;
@@ -1820,23 +1983,25 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
&parser->m_position);
nLeftOver = s + len - end;
if (nLeftOver) {
- if (parser->m_buffer == NULL
- || nLeftOver > parser->m_bufferLim - parser->m_buffer) {
- /* avoid _signed_ integer overflow */
- char *temp = NULL;
- const int bytesToAllocate = (int)((unsigned)len * 2U);
- if (bytesToAllocate > 0) {
- temp = (char *)REALLOC(parser, parser->m_buffer, bytesToAllocate);
- }
- if (temp == NULL) {
- parser->m_errorCode = XML_ERROR_NO_MEMORY;
- parser->m_eventPtr = parser->m_eventEndPtr = NULL;
- parser->m_processor = errorProcessor;
- return XML_STATUS_ERROR;
- }
- parser->m_buffer = temp;
- parser->m_bufferLim = parser->m_buffer + bytesToAllocate;
+ // Back up and restore the parsing status to avoid XML_ERROR_SUSPENDED
+ // (and XML_ERROR_FINISHED) from XML_GetBuffer.
+ const enum XML_Parsing originalStatus = parser->m_parsingStatus.parsing;
+ parser->m_parsingStatus.parsing = XML_PARSING;
+ void *const temp = XML_GetBuffer(parser, nLeftOver);
+ parser->m_parsingStatus.parsing = originalStatus;
+ // GetBuffer may have overwritten this, but we want to remember what the
+ // app requested, not how many bytes were left over after parsing.
+ parser->m_lastBufferRequestSize = len;
+ if (temp == NULL) {
+ // NOTE: parser->m_errorCode has already been set by XML_GetBuffer().
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
+ return XML_STATUS_ERROR;
}
+ // Since we know that the buffer was empty and XML_CONTEXT_BYTES is 0, we
+ // don't have any data to preserve, and can copy straight into the start
+ // of the buffer rather than the GetBuffer return pointer (which may be
+ // pointing further into the allocated buffer).
memcpy(parser->m_buffer, end, nLeftOver);
}
parser->m_bufferPtr = parser->m_buffer;
@@ -1847,16 +2012,15 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
parser->m_eventEndPtr = parser->m_bufferPtr;
return result;
}
-#endif /* not defined XML_CONTEXT_BYTES */
- else {
- void *buff = XML_GetBuffer(parser, len);
- if (buff == NULL)
- return XML_STATUS_ERROR;
- else {
- memcpy(buff, s, len);
- return XML_ParseBuffer(parser, len, isFinal);
- }
+#endif /* XML_CONTEXT_BYTES == 0 */
+ void *buff = XML_GetBuffer(parser, len);
+ if (buff == NULL)
+ return XML_STATUS_ERROR;
+ if (len > 0) {
+ assert(s != NULL); // make sure s==NULL && len!=0 was rejected above
+ memcpy(buff, s, len);
}
+ return XML_ParseBuffer(parser, len, isFinal);
}
enum XML_Status XMLCALL
@@ -1874,6 +2038,12 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
case XML_INITIALIZED:
+ /* Has someone called XML_GetBuffer successfully before? */
+ if (! parser->m_bufferPtr) {
+ parser->m_errorCode = XML_ERROR_NO_BUFFER;
+ return XML_STATUS_ERROR;
+ }
+
if (parser->m_parentParser == NULL && ! startParsing(parser)) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
@@ -1890,8 +2060,8 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
parser->m_parseEndByteIndex += len;
parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- parser->m_errorCode = parser->m_processor(
- parser, start, parser->m_parseEndPtr, &parser->m_bufferPtr);
+ parser->m_errorCode = callProcessor(parser, start, parser->m_parseEndPtr,
+ &parser->m_bufferPtr);
if (parser->m_errorCode != XML_ERROR_NONE) {
parser->m_eventEndPtr = parser->m_eventPtr;
@@ -1936,10 +2106,14 @@ XML_GetBuffer(XML_Parser parser, int len) {
default:;
}
- if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
-#ifdef XML_CONTEXT_BYTES
+ // whether or not the request succeeds, `len` seems to be the app's preferred
+ // buffer fill size; remember it.
+ parser->m_lastBufferRequestSize = len;
+ if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
+ || parser->m_buffer == NULL) {
+#if XML_CONTEXT_BYTES > 0
int keep;
-#endif /* defined XML_CONTEXT_BYTES */
+#endif /* XML_CONTEXT_BYTES > 0 */
/* Do not invoke signed arithmetic overflow: */
int neededSize = (int)((unsigned)len
+ (unsigned)EXPAT_SAFE_PTR_DIFF(
@@ -1948,15 +2122,21 @@ XML_GetBuffer(XML_Parser parser, int len) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
-#ifdef XML_CONTEXT_BYTES
+#if XML_CONTEXT_BYTES > 0
keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
+ /* Detect and prevent integer overflow */
+ if (keep > INT_MAX - neededSize) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
neededSize += keep;
-#endif /* defined XML_CONTEXT_BYTES */
- if (neededSize
- <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
-#ifdef XML_CONTEXT_BYTES
+#endif /* XML_CONTEXT_BYTES > 0 */
+ if (parser->m_buffer && parser->m_bufferPtr
+ && neededSize
+ <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
+#if XML_CONTEXT_BYTES > 0
if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
int offset
= (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)
@@ -1969,19 +2149,17 @@ XML_GetBuffer(XML_Parser parser, int len) {
parser->m_bufferPtr -= offset;
}
#else
- if (parser->m_buffer && parser->m_bufferPtr) {
- memmove(parser->m_buffer, parser->m_bufferPtr,
- EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
- parser->m_bufferEnd
- = parser->m_buffer
- + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
- parser->m_bufferPtr = parser->m_buffer;
- }
-#endif /* not defined XML_CONTEXT_BYTES */
+ memmove(parser->m_buffer, parser->m_bufferPtr,
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
+ parser->m_bufferEnd
+ = parser->m_buffer
+ + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ parser->m_bufferPtr = parser->m_buffer;
+#endif /* XML_CONTEXT_BYTES > 0 */
} else {
char *newBuf;
int bufferSize
- = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr);
+ = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer);
if (bufferSize == 0)
bufferSize = INIT_BUFFER_SIZE;
do {
@@ -1998,7 +2176,7 @@ XML_GetBuffer(XML_Parser parser, int len) {
return NULL;
}
parser->m_bufferLim = newBuf + bufferSize;
-#ifdef XML_CONTEXT_BYTES
+#if XML_CONTEXT_BYTES > 0
if (parser->m_bufferPtr) {
memcpy(newBuf, &parser->m_bufferPtr[-keep],
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
@@ -2028,7 +2206,7 @@ XML_GetBuffer(XML_Parser parser, int len) {
parser->m_bufferEnd = newBuf;
}
parser->m_bufferPtr = parser->m_buffer = newBuf;
-#endif /* not defined XML_CONTEXT_BYTES */
+#endif /* XML_CONTEXT_BYTES > 0 */
}
parser->m_eventPtr = parser->m_eventEndPtr = NULL;
parser->m_positionPtr = NULL;
@@ -2078,7 +2256,7 @@ XML_ResumeParser(XML_Parser parser) {
}
parser->m_parsingStatus.parsing = XML_PARSING;
- parser->m_errorCode = parser->m_processor(
+ parser->m_errorCode = callProcessor(
parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
if (parser->m_errorCode != XML_ERROR_NONE) {
@@ -2142,7 +2320,7 @@ XML_GetCurrentByteCount(XML_Parser parser) {
const char *XMLCALL
XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
-#ifdef XML_CONTEXT_BYTES
+#if XML_CONTEXT_BYTES > 0
if (parser == NULL)
return NULL;
if (parser->m_eventPtr && parser->m_buffer) {
@@ -2156,8 +2334,8 @@ XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
(void)parser;
(void)offset;
(void)size;
-#endif /* defined XML_CONTEXT_BYTES */
- return (char *)0;
+#endif /* XML_CONTEXT_BYTES > 0 */
+ return (const char *)0;
}
XML_Size XMLCALL
@@ -2318,6 +2496,14 @@ XML_ErrorString(enum XML_Error code) {
/* Added in 2.2.5. */
case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
return XML_L("invalid argument");
+ /* Added in 2.3.0. */
+ case XML_ERROR_NO_BUFFER:
+ return XML_L(
+ "a successful prior call to function XML_GetBuffer is required");
+ /* Added in 2.4.0. */
+ case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
+ return XML_L(
+ "limit on input amplification factor (from DTD and entities) breached");
}
return NULL;
}
@@ -2354,41 +2540,87 @@ XML_ExpatVersionInfo(void) {
const XML_Feature *XMLCALL
XML_GetFeatureList(void) {
- static const XML_Feature features[]
- = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
- sizeof(XML_Char)},
- {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
- sizeof(XML_LChar)},
+ static const XML_Feature features[] = {
+ {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+ sizeof(XML_Char)},
+ {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+ sizeof(XML_LChar)},
#ifdef XML_UNICODE
- {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+ {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
#endif
#ifdef XML_UNICODE_WCHAR_T
- {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+ {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
#endif
#ifdef XML_DTD
- {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+ {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
#endif
-#ifdef XML_CONTEXT_BYTES
- {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
- XML_CONTEXT_BYTES},
+#if XML_CONTEXT_BYTES > 0
+ {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+ XML_CONTEXT_BYTES},
#endif
#ifdef XML_MIN_SIZE
- {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+ {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
#endif
#ifdef XML_NS
- {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+ {XML_FEATURE_NS, XML_L("XML_NS"), 0},
#endif
#ifdef XML_LARGE_SIZE
- {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+ {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
#endif
#ifdef XML_ATTR_INFO
- {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+ {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+#endif
+#if XML_GE == 1
+ /* Added in Expat 2.4.0 for XML_DTD defined and
+ * added in Expat 2.6.0 for XML_GE == 1. */
+ {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
+ XML_L("XML_BLAP_MAX_AMP"),
+ (long int)
+ EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
+ {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
+ XML_L("XML_BLAP_ACT_THRES"),
+ EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
+ /* Added in Expat 2.6.0. */
+ {XML_FEATURE_GE, XML_L("XML_GE"), 0},
#endif
- {XML_FEATURE_END, NULL, 0}};
+ {XML_FEATURE_END, NULL, 0}};
return features;
}
+#if XML_GE == 1
+XML_Bool XMLCALL
+XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ XML_Parser parser, float maximumAmplificationFactor) {
+ if ((parser == NULL) || (parser->m_parentParser != NULL)
+ || isnan(maximumAmplificationFactor)
+ || (maximumAmplificationFactor < 1.0f)) {
+ return XML_FALSE;
+ }
+ parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
+ return XML_TRUE;
+}
+
+XML_Bool XMLCALL
+XML_SetBillionLaughsAttackProtectionActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes) {
+ if ((parser == NULL) || (parser->m_parentParser != NULL)) {
+ return XML_FALSE;
+ }
+ parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
+ return XML_TRUE;
+}
+#endif /* XML_GE == 1 */
+
+XML_Bool XMLCALL
+XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
+ if (parser != NULL && (enabled == XML_TRUE || enabled == XML_FALSE)) {
+ parser->m_reparseDeferralEnabled = enabled;
+ return XML_TRUE;
+ }
+ return XML_FALSE;
+}
+
/* Initially tag->rawName always points into the parse buffer;
for those TAG instances opened while the current parse buffer was
processed, and not yet closed, we need to store tag->rawName in a more
@@ -2400,6 +2632,7 @@ storeRawNames(XML_Parser parser) {
while (tag) {
int bufSize;
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+ size_t rawNameLen;
char *rawNameBuf = tag->buf + nameLen;
/* Stop if already stored. Since m_tagStack is a stack, we can stop
at the first entry that has already been copied; everything
@@ -2408,10 +2641,14 @@ storeRawNames(XML_Parser parser) {
*/
if (tag->rawName == rawNameBuf)
break;
- /* For re-use purposes we need to ensure that the
+ /* For reuse purposes we need to ensure that the
size of tag->buf is a multiple of sizeof(XML_Char).
*/
- bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+ rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+ /* Detect and prevent integer overflow. */
+ if (rawNameLen > (size_t)INT_MAX - nameLen)
+ return XML_FALSE;
+ bufSize = nameLen + (int)rawNameLen;
if (bufSize > tag->bufEnd - tag->buf) {
char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
if (temp == NULL)
@@ -2441,9 +2678,9 @@ storeRawNames(XML_Parser parser) {
static enum XML_Error PTRCALL
contentProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
- enum XML_Error result
- = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+ enum XML_Error result = doContent(
+ parser, 0, parser->m_encoding, start, end, endPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
if (result == XML_ERROR_NONE) {
if (! storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
@@ -2468,6 +2705,14 @@ externalEntityInitProcessor2(XML_Parser parser, const char *start,
int tok = XmlContentTok(parser->m_encoding, start, end, &next);
switch (tok) {
case XML_TOK_BOM:
+#if XML_GE == 1
+ if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
+ XML_ACCOUNT_DIRECT)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+#endif /* XML_GE == 1 */
+
/* If we are at the end of the buffer, this would cause the next stage,
i.e. externalEntityInitProcessor3, to pass control directly to
doContent (by detecting XML_TOK_NONE) without processing any xml text
@@ -2505,6 +2750,10 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start,
const char *next = start; /* XmlContentTok doesn't always set the last arg */
parser->m_eventPtr = start;
tok = XmlContentTok(parser->m_encoding, start, end, &next);
+ /* Note: These bytes are accounted later in:
+ - processXmlDecl
+ - externalEntityContentProcessor
+ */
parser->m_eventEndPtr = next;
switch (tok) {
@@ -2546,7 +2795,8 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
const char *end, const char **endPtr) {
enum XML_Error result
= doContent(parser, 1, parser->m_encoding, start, end, endPtr,
- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer,
+ XML_ACCOUNT_ENTITY_EXPANSION);
if (result == XML_ERROR_NONE) {
if (! storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
@@ -2557,7 +2807,7 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
static enum XML_Error
doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
const char *s, const char *end, const char **nextPtr,
- XML_Bool haveMore) {
+ XML_Bool haveMore, enum XML_Account account) {
/* save one level of indirection */
DTD *const dtd = parser->m_dtd;
@@ -2575,6 +2825,17 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
for (;;) {
const char *next = s; /* XmlContentTok doesn't always set the last arg */
int tok = XmlContentTok(enc, s, end, &next);
+#if XML_GE == 1
+ const char *accountAfter
+ = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
+ ? (haveMore ? s /* i.e. 0 bytes */ : end)
+ : next;
+ if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
+ account)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+#endif
*eventEndPP = next;
switch (tok) {
case XML_TOK_TRAILING_CR:
@@ -2630,6 +2891,14 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
XML_Char ch = (XML_Char)XmlPredefinedEntityName(
enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
if (ch) {
+#if XML_GE == 1
+ /* NOTE: We are replacing 4-6 characters original input for 1 character
+ * so there is no amplification and hence recording without
+ * protection. */
+ accountingDiffTolerated(parser, tok, (char *)&ch,
+ ((char *)&ch) + sizeof(XML_Char), __LINE__,
+ XML_ACCOUNT_ENTITY_EXPANSION);
+#endif /* XML_GE == 1 */
if (parser->m_characterDataHandler)
parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
else if (parser->m_defaultHandler)
@@ -2748,7 +3017,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
}
tag->name.str = (XML_Char *)tag->buf;
*toPtr = XML_T('\0');
- result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+ result
+ = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
if (result)
return result;
if (parser->m_startElementHandler)
@@ -2772,7 +3042,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
if (! name.str)
return XML_ERROR_NO_MEMORY;
poolFinish(&parser->m_tempPool);
- result = storeAtts(parser, enc, s, &name, &bindings);
+ result = storeAtts(parser, enc, s, &name, &bindings,
+ XML_ACCOUNT_NONE /* token spans whole start tag */);
if (result != XML_ERROR_NONE) {
freeBindings(parser, bindings);
return result;
@@ -2809,9 +3080,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
int len;
const char *rawName;
TAG *tag = parser->m_tagStack;
- parser->m_tagStack = tag->parent;
- tag->parent = parser->m_freeTagList;
- parser->m_freeTagList = tag;
rawName = s + enc->minBytesPerChar * 2;
len = XmlNameLength(enc, rawName);
if (len != tag->rawNameLength
@@ -2819,6 +3087,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
*eventPP = rawName;
return XML_ERROR_TAG_MISMATCH;
}
+ parser->m_tagStack = tag->parent;
+ tag->parent = parser->m_freeTagList;
+ parser->m_freeTagList = tag;
--parser->m_tagLevel;
if (parser->m_endElementHandler) {
const XML_Char *localPart;
@@ -2828,13 +3099,13 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
if (parser->m_ns && localPart) {
/* localPart and prefix may have been overwritten in
tag->name.str, since this points to the binding->uri
- buffer which gets re-used; so we have to add them again
+ buffer which gets reused; so we have to add them again
*/
uri = (XML_Char *)tag->name.str + tag->name.uriLen;
/* don't need to check for space - already done in storeAtts() */
while (*localPart)
*uri++ = *localPart++;
- prefix = (XML_Char *)tag->name.prefix;
+ prefix = tag->name.prefix;
if (parser->m_ns_triplets && prefix) {
*uri++ = parser->m_namespaceSeparator;
while (*prefix)
@@ -2901,13 +3172,14 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
However, now we have a start/endCdataSectionHandler, so it seems
easier to let the user deal with this.
*/
- else if (0 && parser->m_characterDataHandler)
+ else if ((0) && parser->m_characterDataHandler)
parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
0);
/* END disabled code */
else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+ result
+ = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account);
if (result != XML_ERROR_NONE)
return result;
else if (! next) {
@@ -2929,8 +3201,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
(int)(dataPtr - (ICHAR *)parser->m_dataBuf));
} else
parser->m_characterDataHandler(
- parser->m_handlerArg, (XML_Char *)s,
- (int)((XML_Char *)end - (XML_Char *)s));
+ parser->m_handlerArg, (const XML_Char *)s,
+ (int)((const XML_Char *)end - (const XML_Char *)s));
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
@@ -2963,8 +3235,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
*eventPP = s;
}
} else
- charDataHandler(parser->m_handlerArg, (XML_Char *)s,
- (int)((XML_Char *)next - (XML_Char *)s));
+ charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
+ (int)((const XML_Char *)next - (const XML_Char *)s));
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
} break;
@@ -3036,7 +3308,8 @@ freeBindings(XML_Parser parser, BINDING *bindings) {
*/
static enum XML_Error
storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
- TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
+ TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
+ enum XML_Account account) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
ELEMENT_TYPE *elementType;
int nDefaultAtts;
@@ -3068,13 +3341,38 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
/* get the attributes from the tokenizer */
n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
+
+ /* Detect and prevent integer overflow */
+ if (n > INT_MAX - nDefaultAtts) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
if (n + nDefaultAtts > parser->m_attsSize) {
int oldAttsSize = parser->m_attsSize;
ATTRIBUTE *temp;
#ifdef XML_ATTR_INFO
XML_AttrInfo *temp2;
#endif
+
+ /* Detect and prevent integer overflow */
+ if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE)
+ || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) {
+ parser->m_attsSize = oldAttsSize;
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts,
parser->m_attsSize * sizeof(ATTRIBUTE));
if (temp == NULL) {
@@ -3083,6 +3381,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
}
parser->m_atts = temp;
#ifdef XML_ATTR_INFO
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+# if UINT_MAX >= SIZE_MAX
+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) {
+ parser->m_attsSize = oldAttsSize;
+ return XML_ERROR_NO_MEMORY;
+ }
+# endif
+
temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo,
parser->m_attsSize * sizeof(XML_AttrInfo));
if (temp2 == NULL) {
@@ -3146,7 +3455,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
/* normalize the attribute value */
result = storeAttributeValue(
parser, enc, isCdata, parser->m_atts[i].valuePtr,
- parser->m_atts[i].valueEnd, &parser->m_tempPool);
+ parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
if (result)
return result;
appAtts[attIndex] = poolStart(&parser->m_tempPool);
@@ -3221,7 +3530,13 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
if (nPrefixes) {
int j; /* hash table index */
unsigned long version = parser->m_nsAttsVersion;
- int nsAttsSize = (int)1 << parser->m_nsAttsPower;
+
+ /* Detect and prevent invalid shift */
+ if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ unsigned int nsAttsSize = 1u << parser->m_nsAttsPower;
unsigned char oldNsAttsPower = parser->m_nsAttsPower;
/* size of hash table must be at least 2 * (# of prefixed attributes) */
if ((nPrefixes << 1)
@@ -3232,7 +3547,28 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
;
if (parser->m_nsAttsPower < 3)
parser->m_nsAttsPower = 3;
- nsAttsSize = (int)1 << parser->m_nsAttsPower;
+
+ /* Detect and prevent invalid shift */
+ if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) {
+ /* Restore actual size of memory in m_nsAtts */
+ parser->m_nsAttsPower = oldNsAttsPower;
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ nsAttsSize = 1u << parser->m_nsAttsPower;
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) {
+ /* Restore actual size of memory in m_nsAtts */
+ parser->m_nsAttsPower = oldNsAttsPower;
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts,
nsAttsSize * sizeof(NS_ATT));
if (! temp) {
@@ -3390,9 +3726,31 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
tagNamePtr->prefixLen = prefixLen;
for (i = 0; localPart[i++];)
; /* i includes null terminator */
+
+ /* Detect and prevent integer overflow */
+ if (binding->uriLen > INT_MAX - prefixLen
+ || i > INT_MAX - (binding->uriLen + prefixLen)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
n = i + binding->uriLen + prefixLen;
if (n > binding->uriAlloc) {
TAG *p;
+
+ /* Detect and prevent integer overflow */
+ if (n > INT_MAX - EXPAND_SPARE) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
if (! uri)
return XML_ERROR_NO_MEMORY;
@@ -3417,12 +3775,124 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
return XML_ERROR_NONE;
}
+static XML_Bool
+is_rfc3986_uri_char(XML_Char candidate) {
+ // For the RFC 3986 ANBF grammar see
+ // https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
+
+ switch (candidate) {
+ // From rule "ALPHA" (uppercase half)
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+
+ // From rule "ALPHA" (lowercase half)
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+
+ // From rule "DIGIT"
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+
+ // From rule "pct-encoded"
+ case '%':
+
+ // From rule "unreserved"
+ case '-':
+ case '.':
+ case '_':
+ case '~':
+
+ // From rule "gen-delims"
+ case ':':
+ case '/':
+ case '?':
+ case '#':
+ case '[':
+ case ']':
+ case '@':
+
+ // From rule "sub-delims"
+ case '!':
+ case '$':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case ';':
+ case '=':
+ return XML_TRUE;
+
+ default:
+ return XML_FALSE;
+ }
+}
+
/* addBinding() overwrites the value of prefix->binding without checking.
Therefore one must keep track of the old value outside of addBinding().
*/
static enum XML_Error
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
const XML_Char *uri, BINDING **bindingsPtr) {
+ // "http://www.w3.org/XML/1998/namespace"
static const XML_Char xmlNamespace[]
= {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON,
ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
@@ -3433,6 +3903,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
ASCII_e, '\0'};
static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
+ // "http://www.w3.org/2000/xmlns/"
static const XML_Char xmlnsNamespace[]
= {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w,
@@ -3472,6 +3943,29 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (! mustBeXML && isXMLNS
&& (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
isXMLNS = XML_FALSE;
+
+ // NOTE: While Expat does not validate namespace URIs against RFC 3986
+ // today (and is not REQUIRED to do so with regard to the XML 1.0
+ // namespaces specification) we have to at least make sure, that
+ // the application on top of Expat (that is likely splitting expanded
+ // element names ("qualified names") of form
+ // "[uri sep] local [sep prefix] '\0'" back into 1, 2 or 3 pieces
+ // in its element handler code) cannot be confused by an attacker
+ // putting additional namespace separator characters into namespace
+ // declarations. That would be ambiguous and not to be expected.
+ //
+ // While the HTML API docs of function XML_ParserCreateNS have been
+ // advising against use of a namespace separator character that can
+ // appear in a URI for >20 years now, some widespread applications
+ // are using URI characters (':' (colon) in particular) for a
+ // namespace separator, in practice. To keep these applications
+ // functional, we only reject namespaces URIs containing the
+ // application-chosen namespace separator if the chosen separator
+ // is a non-URI character with regard to RFC 3986.
+ if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)
+ && ! is_rfc3986_uri_char(uri[len])) {
+ return XML_ERROR_SYNTAX;
+ }
}
isXML = isXML && len == xmlLen;
isXMLNS = isXMLNS && len == xmlnsLen;
@@ -3488,6 +3982,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (parser->m_freeBindingList) {
b = parser->m_freeBindingList;
if (len > b->uriAlloc) {
+ /* Detect and prevent integer overflow */
+ if (len > INT_MAX - EXPAND_SPARE) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
XML_Char *temp = (XML_Char *)REALLOC(
parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (temp == NULL)
@@ -3500,6 +4009,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
b = (BINDING *)MALLOC(parser, sizeof(BINDING));
if (! b)
return XML_ERROR_NO_MEMORY;
+
+ /* Detect and prevent integer overflow */
+ if (len > INT_MAX - EXPAND_SPARE) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
b->uri
= (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (! b->uri) {
@@ -3535,9 +4059,9 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
static enum XML_Error PTRCALL
cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
- enum XML_Error result
- = doCdataSection(parser, parser->m_encoding, &start, end, endPtr,
- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+ enum XML_Error result = doCdataSection(
+ parser, parser->m_encoding, &start, end, endPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
if (result != XML_ERROR_NONE)
return result;
if (start) {
@@ -3557,7 +4081,8 @@ cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
*/
static enum XML_Error
doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
- const char *end, const char **nextPtr, XML_Bool haveMore) {
+ const char *end, const char **nextPtr, XML_Bool haveMore,
+ enum XML_Account account) {
const char *s = *startPtr;
const char **eventPP;
const char **eventEndPP;
@@ -3573,8 +4098,16 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
*startPtr = NULL;
for (;;) {
- const char *next;
+ const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
int tok = XmlCdataSectionTok(enc, s, end, &next);
+#if XML_GE == 1
+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+#else
+ UNUSED_P(account);
+#endif
*eventEndPP = next;
switch (tok) {
case XML_TOK_CDATA_SECT_CLOSE:
@@ -3582,7 +4115,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
parser->m_endCdataSectionHandler(parser->m_handlerArg);
/* BEGIN disabled code */
/* see comment under XML_TOK_CDATA_SECT_OPEN */
- else if (0 && parser->m_characterDataHandler)
+ else if ((0) && parser->m_characterDataHandler)
parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
0);
/* END disabled code */
@@ -3618,8 +4151,8 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
*eventPP = s;
}
} else
- charDataHandler(parser->m_handlerArg, (XML_Char *)s,
- (int)((XML_Char *)next - (XML_Char *)s));
+ charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
+ (int)((const XML_Char *)next - (const XML_Char *)s));
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
} break;
@@ -3691,7 +4224,7 @@ ignoreSectionProcessor(XML_Parser parser, const char *start, const char *end,
static enum XML_Error
doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
const char *end, const char **nextPtr, XML_Bool haveMore) {
- const char *next;
+ const char *next = *startPtr; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
int tok;
const char *s = *startPtr;
const char **eventPP;
@@ -3719,6 +4252,13 @@ doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
*eventPP = s;
*startPtr = NULL;
tok = XmlIgnoreSectionTok(enc, s, end, &next);
+# if XML_GE == 1
+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+ XML_ACCOUNT_DIRECT)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+# endif
*eventEndPP = next;
switch (tok) {
case XML_TOK_IGNORE_SECT:
@@ -3768,7 +4308,7 @@ initializeEncoding(XML_Parser parser) {
const char *s;
#ifdef XML_UNICODE
char encodingBuf[128];
- /* See comments abount `protoclEncodingName` in parserInit() */
+ /* See comments about `protocolEncodingName` in parserInit() */
if (! parser->m_protocolEncodingName)
s = NULL;
else {
@@ -3800,9 +4340,18 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
const XML_Char *storedEncName = NULL;
const ENCODING *newEncoding = NULL;
const char *version = NULL;
- const char *versionend;
+ const char *versionend = NULL;
const XML_Char *storedversion = NULL;
int standalone = -1;
+
+#if XML_GE == 1
+ if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
+ XML_ACCOUNT_DIRECT)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+#endif
+
if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
&version, &versionend, &encodingName, &newEncoding, &standalone)) {
@@ -3952,6 +4501,10 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
for (;;) {
tok = XmlPrologTok(parser->m_encoding, start, end, &next);
+ /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in:
+ - storeEntityValue
+ - processXmlDecl
+ */
parser->m_eventEndPtr = next;
if (tok <= 0) {
if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
@@ -3970,7 +4523,8 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
break;
}
/* found end of entity value - can store it now */
- return storeEntityValue(parser, parser->m_encoding, s, end);
+ return storeEntityValue(parser, parser->m_encoding, s, end,
+ XML_ACCOUNT_DIRECT);
} else if (tok == XML_TOK_XML_DECL) {
enum XML_Error result;
result = processXmlDecl(parser, 0, start, next);
@@ -3988,17 +4542,25 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
parser->m_processor = entityValueProcessor;
return entityValueProcessor(parser, next, end, nextPtr);
}
- /* If we are at the end of the buffer, this would cause XmlPrologTok to
- return XML_TOK_NONE on the next call, which would then cause the
- function to exit with *nextPtr set to s - that is what we want for other
- tokens, but not for the BOM - we would rather like to skip it;
- then, when this routine is entered the next time, XmlPrologTok will
- return XML_TOK_INVALID, since the BOM is still in the buffer
+ /* XmlPrologTok has now set the encoding based on the BOM it found, and we
+ must move s and nextPtr forward to consume the BOM.
+
+ If we didn't, and got XML_TOK_NONE from the next XmlPrologTok call, we
+ would leave the BOM in the buffer and return. On the next call to this
+ function, our XmlPrologTok call would return XML_TOK_INVALID, since it
+ is not valid to have multiple BOMs.
*/
- else if (tok == XML_TOK_BOM && next == end
- && ! parser->m_parsingStatus.finalBuffer) {
+ else if (tok == XML_TOK_BOM) {
+# if XML_GE == 1
+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+ XML_ACCOUNT_DIRECT)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+# endif
+
*nextPtr = next;
- return XML_ERROR_NONE;
+ s = next;
}
/* If we get this token, we have the start of what might be a
normal tag, but not a declaration (i.e. it doesn't begin with
@@ -4039,16 +4601,24 @@ externalParEntProcessor(XML_Parser parser, const char *s, const char *end,
}
/* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
However, when parsing an external subset, doProlog will not accept a BOM
- as valid, and report a syntax error, so we have to skip the BOM
+ as valid, and report a syntax error, so we have to skip the BOM, and
+ account for the BOM bytes.
*/
else if (tok == XML_TOK_BOM) {
+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+ XML_ACCOUNT_DIRECT)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+
s = next;
tok = XmlPrologTok(parser->m_encoding, s, end, &next);
}
parser->m_processor = prologProcessor;
return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
+ XML_ACCOUNT_DIRECT);
}
static enum XML_Error PTRCALL
@@ -4061,6 +4631,9 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
for (;;) {
tok = XmlPrologTok(enc, start, end, &next);
+ /* Note: These bytes are accounted later in:
+ - storeEntityValue
+ */
if (tok <= 0) {
if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
@@ -4078,7 +4651,7 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
break;
}
/* found end of entity value - can store it now */
- return storeEntityValue(parser, enc, s, end);
+ return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
}
start = next;
}
@@ -4092,13 +4665,14 @@ prologProcessor(XML_Parser parser, const char *s, const char *end,
const char *next = s;
int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
+ XML_ACCOUNT_DIRECT);
}
static enum XML_Error
doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
- XML_Bool allowClosingDoctype) {
+ XML_Bool allowClosingDoctype, enum XML_Account account) {
#ifdef XML_DTD
static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
#endif /* XML_DTD */
@@ -4125,6 +4699,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
+#ifndef XML_DTD
+ UNUSED_P(account);
+#endif
+
/* save one level of indirection */
DTD *const dtd = parser->m_dtd;
@@ -4189,6 +4767,21 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
}
}
role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
+#if XML_GE == 1
+ switch (role) {
+ case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
+ case XML_ROLE_XML_DECL: // bytes accounted in processXmlDecl
+# ifdef XML_DTD
+ case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
+# endif
+ break;
+ default:
+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+ }
+#endif
switch (role) {
case XML_ROLE_XML_DECL: {
enum XML_Error result = processXmlDecl(parser, 0, s, next);
@@ -4453,10 +5046,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
parser->m_handlerArg, parser->m_declElementType->name,
parser->m_declAttributeId->name, parser->m_declAttributeType, 0,
role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
- poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
}
+ poolClear(&parser->m_tempPool);
break;
case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
@@ -4464,7 +5057,8 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
const XML_Char *attVal;
enum XML_Error result = storeAttributeValue(
parser, enc, parser->m_declAttributeIsCdata,
- s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool);
+ s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool,
+ XML_ACCOUNT_NONE);
if (result)
return result;
attVal = poolStart(&dtd->pool);
@@ -4497,8 +5091,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
break;
case XML_ROLE_ENTITY_VALUE:
if (dtd->keepProcessing) {
- enum XML_Error result = storeEntityValue(
- parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
+#if XML_GE == 1
+ // This will store the given replacement text in
+ // parser->m_declEntity->textPtr.
+ enum XML_Error result
+ = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
if (parser->m_declEntity) {
parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
parser->m_declEntity->textLen
@@ -4516,6 +5114,25 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
poolDiscard(&dtd->entityValuePool);
if (result != XML_ERROR_NONE)
return result;
+#else
+ // This will store "&amp;entity123;" in parser->m_declEntity->textPtr
+ // to end up as "&entity123;" in the handler.
+ if (parser->m_declEntity != NULL) {
+ const enum XML_Error result
+ = storeSelfEntityValue(parser, parser->m_declEntity);
+ if (result != XML_ERROR_NONE)
+ return result;
+
+ if (parser->m_entityDeclHandler) {
+ *eventEndPP = s;
+ parser->m_entityDeclHandler(
+ parser->m_handlerArg, parser->m_declEntity->name,
+ parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
+ parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
+ handleDefault = XML_FALSE;
+ }
+ }
+#endif
}
break;
case XML_ROLE_DOCTYPE_SYSTEM_ID:
@@ -4574,6 +5191,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
}
break;
case XML_ROLE_ENTITY_COMPLETE:
+#if XML_GE == 0
+ // This will store "&amp;entity123;" in entity->textPtr
+ // to end up as "&entity123;" in the handler.
+ if (parser->m_declEntity != NULL) {
+ const enum XML_Error result
+ = storeSelfEntityValue(parser, parser->m_declEntity);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+#endif
if (dtd->keepProcessing && parser->m_declEntity
&& parser->m_entityDeclHandler) {
*eventEndPP = s;
@@ -4757,6 +5384,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
if (parser->m_prologState.level >= parser->m_groupSize) {
if (parser->m_groupSize) {
{
+ /* Detect and prevent integer overflow */
+ if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
char *const new_connector = (char *)REALLOC(
parser, parser->m_groupConnector, parser->m_groupSize *= 2);
if (new_connector == NULL) {
@@ -4767,6 +5399,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
}
if (dtd->scaffIndex) {
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
int *const new_scaff_index = (int *)REALLOC(
parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
if (new_scaff_index == NULL)
@@ -4847,7 +5489,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
*
* If 'standalone' is false, the DTD must have no
* parameter entities or we wouldn't have passed the outer
- * 'if' statement. That measn the only entity in the hash
+ * 'if' statement. That means the only entity in the hash
* table is the external subset name "#" which cannot be
* given as a parameter entity name in XML syntax, so the
* lookup must have returned NULL and we don't even reach
@@ -4888,12 +5530,15 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
+ entityTrackingOnOpen(parser, entity, __LINE__);
if (! parser->m_externalEntityRefHandler(
parser->m_externalEntityRefHandlerArg, 0, entity->base,
entity->systemId, entity->publicId)) {
+ entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
}
+ entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
handleDefault = XML_FALSE;
if (! dtd->paramEntityRead) {
@@ -4972,7 +5617,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
if (dtd->in_eldecl) {
ELEMENT_TYPE *el;
const XML_Char *name;
- int nameLen;
+ size_t nameLen;
const char *nxt
= (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar);
int myindex = nextScaffoldPart(parser);
@@ -4988,7 +5633,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
nameLen = 0;
for (; name[nameLen++];)
;
- dtd->contentStringLen += nameLen;
+
+ /* Detect and prevent integer overflow */
+ if (nameLen > UINT_MAX - dtd->contentStringLen) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ dtd->contentStringLen += (unsigned)nameLen;
if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
@@ -5091,6 +5742,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
for (;;) {
const char *next = NULL;
int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+#if XML_GE == 1
+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+ XML_ACCOUNT_DIRECT)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+#endif
parser->m_eventEndPtr = next;
switch (tok) {
/* report partial linebreak - it might be the last token */
@@ -5164,6 +5822,9 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
return XML_ERROR_NO_MEMORY;
}
entity->open = XML_TRUE;
+#if XML_GE == 1
+ entityTrackingOnOpen(parser, entity, __LINE__);
+#endif
entity->processed = 0;
openEntity->next = parser->m_openInternalEntities;
parser->m_openInternalEntities = openEntity;
@@ -5172,8 +5833,8 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
openEntity->betweenDecl = betweenDecl;
openEntity->internalEventPtr = NULL;
openEntity->internalEventEndPtr = NULL;
- textStart = (char *)entity->textPtr;
- textEnd = (char *)(entity->textPtr + entity->textLen);
+ textStart = (const char *)entity->textPtr;
+ textEnd = (const char *)(entity->textPtr + entity->textLen);
/* Set a safe default value in case 'next' does not get set */
next = textStart;
@@ -5182,17 +5843,22 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
int tok
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
- tok, next, &next, XML_FALSE, XML_FALSE);
+ tok, next, &next, XML_FALSE, XML_FALSE,
+ XML_ACCOUNT_ENTITY_EXPANSION);
} else
#endif /* XML_DTD */
result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
- textStart, textEnd, &next, XML_FALSE);
+ textStart, textEnd, &next, XML_FALSE,
+ XML_ACCOUNT_ENTITY_EXPANSION);
if (result == XML_ERROR_NONE) {
if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - textStart);
parser->m_processor = internalEntityProcessor;
- } else {
+ } else if (parser->m_openInternalEntities->entity == entity) {
+#if XML_GE == 1
+ entityTrackingOnClose(parser, entity, __LINE__);
+#endif /* XML_GE == 1 */
entity->open = XML_FALSE;
parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
@@ -5215,8 +5881,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
return XML_ERROR_UNEXPECTED_STATE;
entity = openEntity->entity;
- textStart = ((char *)entity->textPtr) + entity->processed;
- textEnd = (char *)(entity->textPtr + entity->textLen);
+ textStart = ((const char *)entity->textPtr) + entity->processed;
+ textEnd = (const char *)(entity->textPtr + entity->textLen);
/* Set a safe default value in case 'next' does not get set */
next = textStart;
@@ -5225,25 +5891,37 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
int tok
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
- tok, next, &next, XML_FALSE, XML_TRUE);
+ tok, next, &next, XML_FALSE, XML_TRUE,
+ XML_ACCOUNT_ENTITY_EXPANSION);
} else
#endif /* XML_DTD */
result = doContent(parser, openEntity->startTagLevel,
parser->m_internalEncoding, textStart, textEnd, &next,
- XML_FALSE);
+ XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
if (result != XML_ERROR_NONE)
return result;
- else if (textEnd != next
- && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
- entity->processed = (int)(next - (char *)entity->textPtr);
+
+ if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - (const char *)entity->textPtr);
return result;
- } else {
- entity->open = XML_FALSE;
- parser->m_openInternalEntities = openEntity->next;
- /* put openEntity back in list of free instances */
- openEntity->next = parser->m_freeInternalEntities;
- parser->m_freeInternalEntities = openEntity;
+ }
+
+#if XML_GE == 1
+ entityTrackingOnClose(parser, entity, __LINE__);
+#endif
+ entity->open = XML_FALSE;
+ parser->m_openInternalEntities = openEntity->next;
+ /* put openEntity back in list of free instances */
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
+
+ // If there are more open entities we want to stop right here and have the
+ // upcoming call to XML_ResumeParser continue with entity content, or it would
+ // be ignored altogether.
+ if (parser->m_openInternalEntities != NULL
+ && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+ return XML_ERROR_NONE;
}
#ifdef XML_DTD
@@ -5252,15 +5930,22 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
parser->m_processor = prologProcessor;
tok = XmlPrologTok(parser->m_encoding, s, end, &next);
return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
+ XML_ACCOUNT_DIRECT);
} else
#endif /* XML_DTD */
{
parser->m_processor = contentProcessor;
/* see externalEntityContentProcessor vs contentProcessor */
- return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
- s, end, nextPtr,
- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+ result = doContent(parser, parser->m_parentParser ? 1 : 0,
+ parser->m_encoding, s, end, nextPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer,
+ XML_ACCOUNT_DIRECT);
+ if (result == XML_ERROR_NONE) {
+ if (! storeRawNames(parser))
+ return XML_ERROR_NO_MEMORY;
+ }
+ return result;
}
}
@@ -5275,9 +5960,10 @@ errorProcessor(XML_Parser parser, const char *s, const char *end,
static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
- const char *ptr, const char *end, STRING_POOL *pool) {
+ const char *ptr, const char *end, STRING_POOL *pool,
+ enum XML_Account account) {
enum XML_Error result
- = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
+ = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
if (result)
return result;
if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
@@ -5289,11 +5975,23 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
- const char *ptr, const char *end, STRING_POOL *pool) {
+ const char *ptr, const char *end, STRING_POOL *pool,
+ enum XML_Account account) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+#ifndef XML_DTD
+ UNUSED_P(account);
+#endif
+
for (;;) {
- const char *next;
+ const char *next
+ = ptr; /* XmlAttributeValueTok doesn't always set the last arg */
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+#if XML_GE == 1
+ if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
+ accountingOnAbort(parser);
+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ }
+#endif
switch (tok) {
case XML_TOK_NONE:
return XML_ERROR_NONE;
@@ -5353,6 +6051,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
XML_Char ch = (XML_Char)XmlPredefinedEntityName(
enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
if (ch) {
+#if XML_GE == 1
+ /* NOTE: We are replacing 4-6 characters original input for 1 character
+ * so there is no amplification and hence recording without
+ * protection. */
+ accountingDiffTolerated(parser, tok, (char *)&ch,
+ ((char *)&ch) + sizeof(XML_Char), __LINE__,
+ XML_ACCOUNT_ENTITY_EXPANSION);
+#endif /* XML_GE == 1 */
if (! poolAppendChar(pool, ch))
return XML_ERROR_NO_MEMORY;
break;
@@ -5430,9 +6136,16 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
enum XML_Error result;
const XML_Char *textEnd = entity->textPtr + entity->textLen;
entity->open = XML_TRUE;
+#if XML_GE == 1
+ entityTrackingOnOpen(parser, entity, __LINE__);
+#endif
result = appendAttributeValue(parser, parser->m_internalEncoding,
- isCdata, (char *)entity->textPtr,
- (char *)textEnd, pool);
+ isCdata, (const char *)entity->textPtr,
+ (const char *)textEnd, pool,
+ XML_ACCOUNT_ENTITY_EXPANSION);
+#if XML_GE == 1
+ entityTrackingOnClose(parser, entity, __LINE__);
+#endif
entity->open = XML_FALSE;
if (result)
return result;
@@ -5460,16 +6173,20 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
/* not reached */
}
+#if XML_GE == 1
static enum XML_Error
storeEntityValue(XML_Parser parser, const ENCODING *enc,
- const char *entityTextPtr, const char *entityTextEnd) {
+ const char *entityTextPtr, const char *entityTextEnd,
+ enum XML_Account account) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
STRING_POOL *pool = &(dtd->entityValuePool);
enum XML_Error result = XML_ERROR_NONE;
-#ifdef XML_DTD
+# ifdef XML_DTD
int oldInEntityValue = parser->m_prologState.inEntityValue;
parser->m_prologState.inEntityValue = 1;
-#endif /* XML_DTD */
+# else
+ UNUSED_P(account);
+# endif /* XML_DTD */
/* never return Null for the value argument in EntityDeclHandler,
since this would indicate an external entity; therefore we
have to make sure that entityValuePool.start is not null */
@@ -5479,11 +6196,20 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
}
for (;;) {
- const char *next;
+ const char *next
+ = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
+
+ if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
+ account)) {
+ accountingOnAbort(parser);
+ result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+ goto endEntityValue;
+ }
+
switch (tok) {
case XML_TOK_PARAM_ENTITY_REF:
-#ifdef XML_DTD
+# ifdef XML_DTD
if (parser->m_isParamEntity || enc != parser->m_encoding) {
const XML_Char *name;
ENTITY *entity;
@@ -5516,13 +6242,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
+ entityTrackingOnOpen(parser, entity, __LINE__);
if (! parser->m_externalEntityRefHandler(
parser->m_externalEntityRefHandlerArg, 0, entity->base,
entity->systemId, entity->publicId)) {
+ entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
goto endEntityValue;
}
+ entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
if (! dtd->paramEntityRead)
dtd->keepProcessing = dtd->standalone;
@@ -5530,16 +6259,19 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
dtd->keepProcessing = dtd->standalone;
} else {
entity->open = XML_TRUE;
+ entityTrackingOnOpen(parser, entity, __LINE__);
result = storeEntityValue(
- parser, parser->m_internalEncoding, (char *)entity->textPtr,
- (char *)(entity->textPtr + entity->textLen));
+ parser, parser->m_internalEncoding, (const char *)entity->textPtr,
+ (const char *)(entity->textPtr + entity->textLen),
+ XML_ACCOUNT_ENTITY_EXPANSION);
+ entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
if (result)
goto endEntityValue;
}
break;
}
-#endif /* XML_DTD */
+# endif /* XML_DTD */
/* In the internal subset, PE references are not legal
within markup declarations, e.g entity values in this case. */
parser->m_eventPtr = entityTextPtr;
@@ -5620,12 +6352,38 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
entityTextPtr = next;
}
endEntityValue:
-#ifdef XML_DTD
+# ifdef XML_DTD
parser->m_prologState.inEntityValue = oldInEntityValue;
-#endif /* XML_DTD */
+# endif /* XML_DTD */
return result;
}
+#else /* XML_GE == 0 */
+
+static enum XML_Error
+storeSelfEntityValue(XML_Parser parser, ENTITY *entity) {
+ // This will store "&amp;entity123;" in entity->textPtr
+ // to end up as "&entity123;" in the handler.
+ const char *const entity_start = "&amp;";
+ const char *const entity_end = ";";
+
+ STRING_POOL *const pool = &(parser->m_dtd->entityValuePool);
+ if (! poolAppendString(pool, entity_start)
+ || ! poolAppendString(pool, entity->name)
+ || ! poolAppendString(pool, entity_end)) {
+ poolDiscard(pool);
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ entity->textPtr = poolStart(pool);
+ entity->textLen = (int)(poolLength(pool));
+ poolFinish(pool);
+
+ return XML_ERROR_NONE;
+}
+
+#endif /* XML_GE == 0 */
+
static void FASTCALL
normalizeLines(XML_Char *s) {
XML_Char *p;
@@ -5736,8 +6494,9 @@ reportDefault(XML_Parser parser, const ENCODING *enc, const char *s,
} while ((convert_res != XML_CONVERT_COMPLETED)
&& (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
} else
- parser->m_defaultHandler(parser->m_handlerArg, (XML_Char *)s,
- (int)((XML_Char *)end - (XML_Char *)s));
+ parser->m_defaultHandler(
+ parser->m_handlerArg, (const XML_Char *)s,
+ (int)((const XML_Char *)end - (const XML_Char *)s));
}
static int
@@ -5765,7 +6524,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
}
} else {
DEFAULT_ATTRIBUTE *temp;
+
+ /* Detect and prevent integer overflow */
+ if (type->allocDefaultAtts > INT_MAX / 2) {
+ return 0;
+ }
+
int count = type->allocDefaultAtts * 2;
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) {
+ return 0;
+ }
+#endif
+
temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts,
(count * sizeof(DEFAULT_ATTRIBUTE)));
if (temp == NULL)
@@ -5824,7 +6600,7 @@ getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
name = poolStoreString(&dtd->pool, enc, start, end);
if (! name)
return NULL;
- /* skip quotation mark - its storage will be re-used (like in name[-1]) */
+ /* skip quotation mark - its storage will be reused (like in name[-1]) */
++name;
id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name,
sizeof(ATTRIBUTE_ID));
@@ -5974,6 +6750,10 @@ getContext(XML_Parser parser) {
static XML_Bool
setContext(XML_Parser parser, const XML_Char *context) {
+ if (context == NULL) {
+ return XML_FALSE;
+ }
+
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *s = context;
@@ -6055,7 +6835,7 @@ normalizePublicId(XML_Char *publicId) {
static DTD *
dtdCreate(const XML_Memory_Handling_Suite *ms) {
- DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
+ DTD *p = ms->malloc_fcn(sizeof(DTD));
if (p == NULL)
return p;
poolInit(&(p->pool), ms);
@@ -6228,8 +7008,8 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
if (! newE)
return 0;
if (oldE->nDefaultAtts) {
- newE->defaultAtts = (DEFAULT_ATTRIBUTE *)ms->malloc_fcn(
- oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ newE->defaultAtts
+ = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
if (! newE->defaultAtts) {
return 0;
}
@@ -6391,7 +7171,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
/* table->size is a power of 2 */
table->size = (size_t)1 << INIT_POWER;
tsize = table->size * sizeof(NAMED *);
- table->v = (NAMED **)table->mem->malloc_fcn(tsize);
+ table->v = table->mem->malloc_fcn(tsize);
if (! table->v) {
table->size = 0;
return NULL;
@@ -6416,10 +7196,22 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
/* check for overflow (table is half full) */
if (table->used >> (table->power - 1)) {
unsigned char newPower = table->power + 1;
+
+ /* Detect and prevent invalid shift */
+ if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) {
+ return NULL;
+ }
+
size_t newSize = (size_t)1 << newPower;
unsigned long newMask = (unsigned long)newSize - 1;
+
+ /* Detect and prevent integer overflow */
+ if (newSize > (size_t)(-1) / sizeof(NAMED *)) {
+ return NULL;
+ }
+
size_t tsize = newSize * sizeof(NAMED *);
- NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
+ NAMED **newV = table->mem->malloc_fcn(tsize);
if (! newV)
return NULL;
memset(newV, 0, tsize);
@@ -6448,7 +7240,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
}
}
}
- table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
+ table->v[i] = table->mem->malloc_fcn(createSize);
if (! table->v[i])
return NULL;
memset(table->v[i], 0, createSize);
@@ -6487,7 +7279,7 @@ hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) {
static void FASTCALL
hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) {
iter->p = table->v;
- iter->end = iter->p + table->size;
+ iter->end = iter->p ? iter->p + table->size : NULL;
}
static NAMED *FASTCALL
@@ -6552,7 +7344,7 @@ poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr,
return NULL;
for (;;) {
const enum XML_Convert_Result convert_res = XmlConvert(
- enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+ enc, &ptr, end, (ICHAR **)&(pool->ptr), (const ICHAR *)pool->end);
if ((convert_res == XML_CONVERT_COMPLETED)
|| (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
@@ -6736,7 +7528,7 @@ poolGrow(STRING_POOL *pool) {
if (bytesToAllocate == 0)
return XML_FALSE;
- tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
+ tem = pool->mem->malloc_fcn(bytesToAllocate);
if (! tem)
return XML_FALSE;
tem->size = blockSize;
@@ -6767,6 +7559,20 @@ nextScaffoldPart(XML_Parser parser) {
if (dtd->scaffCount >= dtd->scaffSize) {
CONTENT_SCAFFOLD *temp;
if (dtd->scaffold) {
+ /* Detect and prevent integer overflow */
+ if (dtd->scaffSize > UINT_MAX / 2u) {
+ return -1;
+ }
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) {
+ return -1;
+ }
+#endif
+
temp = (CONTENT_SCAFFOLD *)REALLOC(
parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
@@ -6798,55 +7604,130 @@ nextScaffoldPart(XML_Parser parser) {
return next;
}
-static void
-build_node(XML_Parser parser, int src_node, XML_Content *dest,
- XML_Content **contpos, XML_Char **strpos) {
- DTD *const dtd = parser->m_dtd; /* save one level of indirection */
- dest->type = dtd->scaffold[src_node].type;
- dest->quant = dtd->scaffold[src_node].quant;
- if (dest->type == XML_CTYPE_NAME) {
- const XML_Char *src;
- dest->name = *strpos;
- src = dtd->scaffold[src_node].name;
- for (;;) {
- *(*strpos)++ = *src;
- if (! *src)
- break;
- src++;
- }
- dest->numchildren = 0;
- dest->children = NULL;
- } else {
- unsigned int i;
- int cn;
- dest->numchildren = dtd->scaffold[src_node].childcnt;
- dest->children = *contpos;
- *contpos += dest->numchildren;
- for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren;
- i++, cn = dtd->scaffold[cn].nextsib) {
- build_node(parser, cn, &(dest->children[i]), contpos, strpos);
- }
- dest->name = NULL;
- }
-}
-
static XML_Content *
build_model(XML_Parser parser) {
+ /* Function build_model transforms the existing parser->m_dtd->scaffold
+ * array of CONTENT_SCAFFOLD tree nodes into a new array of
+ * XML_Content tree nodes followed by a gapless list of zero-terminated
+ * strings. */
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
XML_Content *ret;
- XML_Content *cpos;
- XML_Char *str;
- int allocsize = (dtd->scaffCount * sizeof(XML_Content)
- + (dtd->contentStringLen * sizeof(XML_Char)));
+ XML_Char *str; /* the current string writing location */
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) {
+ return NULL;
+ }
+ if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) {
+ return NULL;
+ }
+#endif
+ if (dtd->scaffCount * sizeof(XML_Content)
+ > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) {
+ return NULL;
+ }
+
+ const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ + (dtd->contentStringLen * sizeof(XML_Char)));
ret = (XML_Content *)MALLOC(parser, allocsize);
if (! ret)
return NULL;
- str = (XML_Char *)(&ret[dtd->scaffCount]);
- cpos = &ret[1];
+ /* What follows is an iterative implementation (of what was previously done
+ * recursively in a dedicated function called "build_node". The old recursive
+ * build_node could be forced into stack exhaustion from input as small as a
+ * few megabyte, and so that was a security issue. Hence, a function call
+ * stack is avoided now by resolving recursion.)
+ *
+ * The iterative approach works as follows:
+ *
+ * - We have two writing pointers, both walking up the result array; one does
+ * the work, the other creates "jobs" for its colleague to do, and leads
+ * the way:
+ *
+ * - The faster one, pointer jobDest, always leads and writes "what job
+ * to do" by the other, once they reach that place in the
+ * array: leader "jobDest" stores the source node array index (relative
+ * to array dtd->scaffold) in field "numchildren".
+ *
+ * - The slower one, pointer dest, looks at the value stored in the
+ * "numchildren" field (which actually holds a source node array index
+ * at that time) and puts the real data from dtd->scaffold in.
+ *
+ * - Before the loop starts, jobDest writes source array index 0
+ * (where the root node is located) so that dest will have something to do
+ * when it starts operation.
+ *
+ * - Whenever nodes with children are encountered, jobDest appends
+ * them as new jobs, in order. As a result, tree node siblings are
+ * adjacent in the resulting array, for example:
+ *
+ * [0] root, has two children
+ * [1] first child of 0, has three children
+ * [3] first child of 1, does not have children
+ * [4] second child of 1, does not have children
+ * [5] third child of 1, does not have children
+ * [2] second child of 0, does not have children
+ *
+ * Or (the same data) presented in flat array view:
+ *
+ * [0] root, has two children
+ *
+ * [1] first child of 0, has three children
+ * [2] second child of 0, does not have children
+ *
+ * [3] first child of 1, does not have children
+ * [4] second child of 1, does not have children
+ * [5] third child of 1, does not have children
+ *
+ * - The algorithm repeats until all target array indices have been processed.
+ */
+ XML_Content *dest = ret; /* tree node writing location, moves upwards */
+ XML_Content *const destLimit = &ret[dtd->scaffCount];
+ XML_Content *jobDest = ret; /* next free writing location in target array */
+ str = (XML_Char *)&ret[dtd->scaffCount];
+
+ /* Add the starting job, the root node (index 0) of the source tree */
+ (jobDest++)->numchildren = 0;
+
+ for (; dest < destLimit; dest++) {
+ /* Retrieve source tree array index from job storage */
+ const int src_node = (int)dest->numchildren;
+
+ /* Convert item */
+ dest->type = dtd->scaffold[src_node].type;
+ dest->quant = dtd->scaffold[src_node].quant;
+ if (dest->type == XML_CTYPE_NAME) {
+ const XML_Char *src;
+ dest->name = str;
+ src = dtd->scaffold[src_node].name;
+ for (;;) {
+ *str++ = *src;
+ if (! *src)
+ break;
+ src++;
+ }
+ dest->numchildren = 0;
+ dest->children = NULL;
+ } else {
+ unsigned int i;
+ int cn;
+ dest->name = NULL;
+ dest->numchildren = dtd->scaffold[src_node].childcnt;
+ dest->children = jobDest;
+
+ /* Append scaffold indices of children to array */
+ for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+ i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib)
+ (jobDest++)->numchildren = (unsigned int)cn;
+ }
+ }
- build_node(parser, 0, ret, &cpos, &str);
return ret;
}
@@ -6875,7 +7756,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
static XML_Char *
copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
- int charsRequired = 0;
+ size_t charsRequired = 0;
XML_Char *result;
/* First determine how long the string is */
@@ -6893,3 +7774,755 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
memcpy(result, s, charsRequired * sizeof(XML_Char));
return result;
}
+
+#if XML_GE == 1
+
+static float
+accountingGetCurrentAmplification(XML_Parser rootParser) {
+ const XmlBigCount countBytesOutput
+ = rootParser->m_accounting.countBytesDirect
+ + rootParser->m_accounting.countBytesIndirect;
+ const float amplificationFactor
+ = rootParser->m_accounting.countBytesDirect
+ ? (countBytesOutput
+ / (float)(rootParser->m_accounting.countBytesDirect))
+ : 1.0f;
+ assert(! rootParser->m_parentParser);
+ return amplificationFactor;
+}
+
+static void
+accountingReportStats(XML_Parser originParser, const char *epilog) {
+ const XML_Parser rootParser = getRootParserOf(originParser, NULL);
+ assert(! rootParser->m_parentParser);
+
+ if (rootParser->m_accounting.debugLevel == 0u) {
+ return;
+ }
+
+ const float amplificationFactor
+ = accountingGetCurrentAmplification(rootParser);
+ fprintf(stderr,
+ "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
+ "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s",
+ (void *)rootParser, rootParser->m_accounting.countBytesDirect,
+ rootParser->m_accounting.countBytesIndirect,
+ (double)amplificationFactor, epilog);
+}
+
+static void
+accountingOnAbort(XML_Parser originParser) {
+ accountingReportStats(originParser, " ABORTING\n");
+}
+
+static void
+accountingReportDiff(XML_Parser rootParser,
+ unsigned int levelsAwayFromRootParser, const char *before,
+ const char *after, ptrdiff_t bytesMore, int source_line,
+ enum XML_Account account) {
+ assert(! rootParser->m_parentParser);
+
+ fprintf(stderr,
+ " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"",
+ bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
+ levelsAwayFromRootParser, source_line, 10, "");
+
+ const char ellipis[] = "[..]";
+ const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1;
+ const unsigned int contextLength = 10;
+
+ /* Note: Performance is of no concern here */
+ const char *walker = before;
+ if ((rootParser->m_accounting.debugLevel >= 3u)
+ || (after - before)
+ <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
+ for (; walker < after; walker++) {
+ fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
+ }
+ } else {
+ for (; walker < before + contextLength; walker++) {
+ fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
+ }
+ fprintf(stderr, ellipis);
+ walker = after - contextLength;
+ for (; walker < after; walker++) {
+ fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
+ }
+ }
+ fprintf(stderr, "\"\n");
+}
+
+static XML_Bool
+accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
+ const char *after, int source_line,
+ enum XML_Account account) {
+ /* Note: We need to check the token type *first* to be sure that
+ * we can even access variable <after>, safely.
+ * E.g. for XML_TOK_NONE <after> may hold an invalid pointer. */
+ switch (tok) {
+ case XML_TOK_INVALID:
+ case XML_TOK_PARTIAL:
+ case XML_TOK_PARTIAL_CHAR:
+ case XML_TOK_NONE:
+ return XML_TRUE;
+ }
+
+ if (account == XML_ACCOUNT_NONE)
+ return XML_TRUE; /* because these bytes have been accounted for, already */
+
+ unsigned int levelsAwayFromRootParser;
+ const XML_Parser rootParser
+ = getRootParserOf(originParser, &levelsAwayFromRootParser);
+ assert(! rootParser->m_parentParser);
+
+ const int isDirect
+ = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
+ const ptrdiff_t bytesMore = after - before;
+
+ XmlBigCount *const additionTarget
+ = isDirect ? &rootParser->m_accounting.countBytesDirect
+ : &rootParser->m_accounting.countBytesIndirect;
+
+ /* Detect and avoid integer overflow */
+ if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
+ return XML_FALSE;
+ *additionTarget += bytesMore;
+
+ const XmlBigCount countBytesOutput
+ = rootParser->m_accounting.countBytesDirect
+ + rootParser->m_accounting.countBytesIndirect;
+ const float amplificationFactor
+ = accountingGetCurrentAmplification(rootParser);
+ const XML_Bool tolerated
+ = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
+ || (amplificationFactor
+ <= rootParser->m_accounting.maximumAmplificationFactor);
+
+ if (rootParser->m_accounting.debugLevel >= 2u) {
+ accountingReportStats(rootParser, "");
+ accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
+ bytesMore, source_line, account);
+ }
+
+ return tolerated;
+}
+
+unsigned long long
+testingAccountingGetCountBytesDirect(XML_Parser parser) {
+ if (! parser)
+ return 0;
+ return parser->m_accounting.countBytesDirect;
+}
+
+unsigned long long
+testingAccountingGetCountBytesIndirect(XML_Parser parser) {
+ if (! parser)
+ return 0;
+ return parser->m_accounting.countBytesIndirect;
+}
+
+static void
+entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
+ const char *action, int sourceLine) {
+ assert(! rootParser->m_parentParser);
+ if (rootParser->m_entity_stats.debugLevel == 0u)
+ return;
+
+# if defined(XML_UNICODE)
+ const char *const entityName = "[..]";
+# else
+ const char *const entityName = entity->name;
+# endif
+
+ fprintf(
+ stderr,
+ "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n",
+ (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
+ rootParser->m_entity_stats.currentDepth,
+ rootParser->m_entity_stats.maximumDepthSeen,
+ (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
+ entity->is_param ? "%" : "&", entityName, action, entity->textLen,
+ sourceLine);
+}
+
+static void
+entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) {
+ const XML_Parser rootParser = getRootParserOf(originParser, NULL);
+ assert(! rootParser->m_parentParser);
+
+ rootParser->m_entity_stats.countEverOpened++;
+ rootParser->m_entity_stats.currentDepth++;
+ if (rootParser->m_entity_stats.currentDepth
+ > rootParser->m_entity_stats.maximumDepthSeen) {
+ rootParser->m_entity_stats.maximumDepthSeen++;
+ }
+
+ entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
+}
+
+static void
+entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) {
+ const XML_Parser rootParser = getRootParserOf(originParser, NULL);
+ assert(! rootParser->m_parentParser);
+
+ entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
+ rootParser->m_entity_stats.currentDepth--;
+}
+
+static XML_Parser
+getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
+ XML_Parser rootParser = parser;
+ unsigned int stepsTakenUpwards = 0;
+ while (rootParser->m_parentParser) {
+ rootParser = rootParser->m_parentParser;
+ stepsTakenUpwards++;
+ }
+ assert(! rootParser->m_parentParser);
+ if (outLevelDiff != NULL) {
+ *outLevelDiff = stepsTakenUpwards;
+ }
+ return rootParser;
+}
+
+const char *
+unsignedCharToPrintable(unsigned char c) {
+ switch (c) {
+ case 0:
+ return "\\0";
+ case 1:
+ return "\\x1";
+ case 2:
+ return "\\x2";
+ case 3:
+ return "\\x3";
+ case 4:
+ return "\\x4";
+ case 5:
+ return "\\x5";
+ case 6:
+ return "\\x6";
+ case 7:
+ return "\\x7";
+ case 8:
+ return "\\x8";
+ case 9:
+ return "\\t";
+ case 10:
+ return "\\n";
+ case 11:
+ return "\\xB";
+ case 12:
+ return "\\xC";
+ case 13:
+ return "\\r";
+ case 14:
+ return "\\xE";
+ case 15:
+ return "\\xF";
+ case 16:
+ return "\\x10";
+ case 17:
+ return "\\x11";
+ case 18:
+ return "\\x12";
+ case 19:
+ return "\\x13";
+ case 20:
+ return "\\x14";
+ case 21:
+ return "\\x15";
+ case 22:
+ return "\\x16";
+ case 23:
+ return "\\x17";
+ case 24:
+ return "\\x18";
+ case 25:
+ return "\\x19";
+ case 26:
+ return "\\x1A";
+ case 27:
+ return "\\x1B";
+ case 28:
+ return "\\x1C";
+ case 29:
+ return "\\x1D";
+ case 30:
+ return "\\x1E";
+ case 31:
+ return "\\x1F";
+ case 32:
+ return " ";
+ case 33:
+ return "!";
+ case 34:
+ return "\\\"";
+ case 35:
+ return "#";
+ case 36:
+ return "$";
+ case 37:
+ return "%";
+ case 38:
+ return "&";
+ case 39:
+ return "'";
+ case 40:
+ return "(";
+ case 41:
+ return ")";
+ case 42:
+ return "*";
+ case 43:
+ return "+";
+ case 44:
+ return ",";
+ case 45:
+ return "-";
+ case 46:
+ return ".";
+ case 47:
+ return "/";
+ case 48:
+ return "0";
+ case 49:
+ return "1";
+ case 50:
+ return "2";
+ case 51:
+ return "3";
+ case 52:
+ return "4";
+ case 53:
+ return "5";
+ case 54:
+ return "6";
+ case 55:
+ return "7";
+ case 56:
+ return "8";
+ case 57:
+ return "9";
+ case 58:
+ return ":";
+ case 59:
+ return ";";
+ case 60:
+ return "<";
+ case 61:
+ return "=";
+ case 62:
+ return ">";
+ case 63:
+ return "?";
+ case 64:
+ return "@";
+ case 65:
+ return "A";
+ case 66:
+ return "B";
+ case 67:
+ return "C";
+ case 68:
+ return "D";
+ case 69:
+ return "E";
+ case 70:
+ return "F";
+ case 71:
+ return "G";
+ case 72:
+ return "H";
+ case 73:
+ return "I";
+ case 74:
+ return "J";
+ case 75:
+ return "K";
+ case 76:
+ return "L";
+ case 77:
+ return "M";
+ case 78:
+ return "N";
+ case 79:
+ return "O";
+ case 80:
+ return "P";
+ case 81:
+ return "Q";
+ case 82:
+ return "R";
+ case 83:
+ return "S";
+ case 84:
+ return "T";
+ case 85:
+ return "U";
+ case 86:
+ return "V";
+ case 87:
+ return "W";
+ case 88:
+ return "X";
+ case 89:
+ return "Y";
+ case 90:
+ return "Z";
+ case 91:
+ return "[";
+ case 92:
+ return "\\\\";
+ case 93:
+ return "]";
+ case 94:
+ return "^";
+ case 95:
+ return "_";
+ case 96:
+ return "`";
+ case 97:
+ return "a";
+ case 98:
+ return "b";
+ case 99:
+ return "c";
+ case 100:
+ return "d";
+ case 101:
+ return "e";
+ case 102:
+ return "f";
+ case 103:
+ return "g";
+ case 104:
+ return "h";
+ case 105:
+ return "i";
+ case 106:
+ return "j";
+ case 107:
+ return "k";
+ case 108:
+ return "l";
+ case 109:
+ return "m";
+ case 110:
+ return "n";
+ case 111:
+ return "o";
+ case 112:
+ return "p";
+ case 113:
+ return "q";
+ case 114:
+ return "r";
+ case 115:
+ return "s";
+ case 116:
+ return "t";
+ case 117:
+ return "u";
+ case 118:
+ return "v";
+ case 119:
+ return "w";
+ case 120:
+ return "x";
+ case 121:
+ return "y";
+ case 122:
+ return "z";
+ case 123:
+ return "{";
+ case 124:
+ return "|";
+ case 125:
+ return "}";
+ case 126:
+ return "~";
+ case 127:
+ return "\\x7F";
+ case 128:
+ return "\\x80";
+ case 129:
+ return "\\x81";
+ case 130:
+ return "\\x82";
+ case 131:
+ return "\\x83";
+ case 132:
+ return "\\x84";
+ case 133:
+ return "\\x85";
+ case 134:
+ return "\\x86";
+ case 135:
+ return "\\x87";
+ case 136:
+ return "\\x88";
+ case 137:
+ return "\\x89";
+ case 138:
+ return "\\x8A";
+ case 139:
+ return "\\x8B";
+ case 140:
+ return "\\x8C";
+ case 141:
+ return "\\x8D";
+ case 142:
+ return "\\x8E";
+ case 143:
+ return "\\x8F";
+ case 144:
+ return "\\x90";
+ case 145:
+ return "\\x91";
+ case 146:
+ return "\\x92";
+ case 147:
+ return "\\x93";
+ case 148:
+ return "\\x94";
+ case 149:
+ return "\\x95";
+ case 150:
+ return "\\x96";
+ case 151:
+ return "\\x97";
+ case 152:
+ return "\\x98";
+ case 153:
+ return "\\x99";
+ case 154:
+ return "\\x9A";
+ case 155:
+ return "\\x9B";
+ case 156:
+ return "\\x9C";
+ case 157:
+ return "\\x9D";
+ case 158:
+ return "\\x9E";
+ case 159:
+ return "\\x9F";
+ case 160:
+ return "\\xA0";
+ case 161:
+ return "\\xA1";
+ case 162:
+ return "\\xA2";
+ case 163:
+ return "\\xA3";
+ case 164:
+ return "\\xA4";
+ case 165:
+ return "\\xA5";
+ case 166:
+ return "\\xA6";
+ case 167:
+ return "\\xA7";
+ case 168:
+ return "\\xA8";
+ case 169:
+ return "\\xA9";
+ case 170:
+ return "\\xAA";
+ case 171:
+ return "\\xAB";
+ case 172:
+ return "\\xAC";
+ case 173:
+ return "\\xAD";
+ case 174:
+ return "\\xAE";
+ case 175:
+ return "\\xAF";
+ case 176:
+ return "\\xB0";
+ case 177:
+ return "\\xB1";
+ case 178:
+ return "\\xB2";
+ case 179:
+ return "\\xB3";
+ case 180:
+ return "\\xB4";
+ case 181:
+ return "\\xB5";
+ case 182:
+ return "\\xB6";
+ case 183:
+ return "\\xB7";
+ case 184:
+ return "\\xB8";
+ case 185:
+ return "\\xB9";
+ case 186:
+ return "\\xBA";
+ case 187:
+ return "\\xBB";
+ case 188:
+ return "\\xBC";
+ case 189:
+ return "\\xBD";
+ case 190:
+ return "\\xBE";
+ case 191:
+ return "\\xBF";
+ case 192:
+ return "\\xC0";
+ case 193:
+ return "\\xC1";
+ case 194:
+ return "\\xC2";
+ case 195:
+ return "\\xC3";
+ case 196:
+ return "\\xC4";
+ case 197:
+ return "\\xC5";
+ case 198:
+ return "\\xC6";
+ case 199:
+ return "\\xC7";
+ case 200:
+ return "\\xC8";
+ case 201:
+ return "\\xC9";
+ case 202:
+ return "\\xCA";
+ case 203:
+ return "\\xCB";
+ case 204:
+ return "\\xCC";
+ case 205:
+ return "\\xCD";
+ case 206:
+ return "\\xCE";
+ case 207:
+ return "\\xCF";
+ case 208:
+ return "\\xD0";
+ case 209:
+ return "\\xD1";
+ case 210:
+ return "\\xD2";
+ case 211:
+ return "\\xD3";
+ case 212:
+ return "\\xD4";
+ case 213:
+ return "\\xD5";
+ case 214:
+ return "\\xD6";
+ case 215:
+ return "\\xD7";
+ case 216:
+ return "\\xD8";
+ case 217:
+ return "\\xD9";
+ case 218:
+ return "\\xDA";
+ case 219:
+ return "\\xDB";
+ case 220:
+ return "\\xDC";
+ case 221:
+ return "\\xDD";
+ case 222:
+ return "\\xDE";
+ case 223:
+ return "\\xDF";
+ case 224:
+ return "\\xE0";
+ case 225:
+ return "\\xE1";
+ case 226:
+ return "\\xE2";
+ case 227:
+ return "\\xE3";
+ case 228:
+ return "\\xE4";
+ case 229:
+ return "\\xE5";
+ case 230:
+ return "\\xE6";
+ case 231:
+ return "\\xE7";
+ case 232:
+ return "\\xE8";
+ case 233:
+ return "\\xE9";
+ case 234:
+ return "\\xEA";
+ case 235:
+ return "\\xEB";
+ case 236:
+ return "\\xEC";
+ case 237:
+ return "\\xED";
+ case 238:
+ return "\\xEE";
+ case 239:
+ return "\\xEF";
+ case 240:
+ return "\\xF0";
+ case 241:
+ return "\\xF1";
+ case 242:
+ return "\\xF2";
+ case 243:
+ return "\\xF3";
+ case 244:
+ return "\\xF4";
+ case 245:
+ return "\\xF5";
+ case 246:
+ return "\\xF6";
+ case 247:
+ return "\\xF7";
+ case 248:
+ return "\\xF8";
+ case 249:
+ return "\\xF9";
+ case 250:
+ return "\\xFA";
+ case 251:
+ return "\\xFB";
+ case 252:
+ return "\\xFC";
+ case 253:
+ return "\\xFD";
+ case 254:
+ return "\\xFE";
+ case 255:
+ return "\\xFF";
+ default:
+ assert(0); /* never gets here */
+ return "dead code";
+ }
+ assert(0); /* never gets here */
+}
+
+#endif /* XML_GE == 1 */
+
+static unsigned long
+getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
+ const char *const valueOrNull = getenv(variableName);
+ if (valueOrNull == NULL) {
+ return defaultDebugLevel;
+ }
+ const char *const value = valueOrNull;
+
+ errno = 0;
+ char *afterValue = NULL;
+ unsigned long debugLevel = strtoul(value, &afterValue, 10);
+ if ((errno != 0) || (afterValue == value) || (afterValue[0] != '\0')) {
+ errno = 0;
+ return defaultDebugLevel;
+ }
+
+ return debugLevel;
+}
diff --git a/contrib/expat/lib/xmlrole.c b/contrib/expat/lib/xmlrole.c
index 4d3e3e86e9e8..2c48bf408679 100644
--- a/contrib/expat/lib/xmlrole.c
+++ b/contrib/expat/lib/xmlrole.c
@@ -7,7 +7,15 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,15 +38,13 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "expat_config.h"
+
#include <stddef.h>
#ifdef _WIN32
# include "winconfig.h"
-#else
-# ifdef HAVE_EXPAT_CONFIG_H
-# include <expat_config.h>
-# endif
-#endif /* ndef _WIN32 */
+#endif
#include "expat_external.h"
#include "internal.h"
@@ -1220,6 +1226,8 @@ common(PROLOG_STATE *state, int tok) {
#ifdef XML_DTD
if (! state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
return XML_ROLE_INNER_PARAM_ENTITY_REF;
+#else
+ UNUSED_P(tok);
#endif
state->handler = error;
return XML_ROLE_ERROR;
diff --git a/contrib/expat/lib/xmlrole.h b/contrib/expat/lib/xmlrole.h
index 036aba64fd29..a7904274c91d 100644
--- a/contrib/expat/lib/xmlrole.h
+++ b/contrib/expat/lib/xmlrole.h
@@ -7,7 +7,10 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2017-2024 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -124,9 +127,9 @@ typedef struct prolog_state {
#endif /* XML_DTD */
} PROLOG_STATE;
-void XmlPrologStateInit(PROLOG_STATE *);
+void XmlPrologStateInit(PROLOG_STATE *state);
#ifdef XML_DTD
-void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
+void XmlPrologStateInitExternalEntity(PROLOG_STATE *state);
#endif /* XML_DTD */
#define XmlTokenRole(state, tok, ptr, end, enc) \
diff --git a/contrib/expat/lib/xmltok.c b/contrib/expat/lib/xmltok.c
index 11e9d1ccdad4..29a66d72ceea 100644
--- a/contrib/expat/lib/xmltok.c
+++ b/contrib/expat/lib/xmltok.c
@@ -7,7 +7,23 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2002 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016 Pascal Cuoq <cuoq@trust-in-soft.com>
+ Copyright (c) 2016 Don Lewis <truckman@apache.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Alexander Bluhm <alexander.bluhm@gmx.net>
+ Copyright (c) 2017 Benbuck Nason <bnason@netflix.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2022 Martin Ettl <ettl.martin78@googlemail.com>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
+ Copyright (c) 2023 Hanno Böck <hanno@gentoo.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,25 +46,15 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "expat_config.h"
+
#include <stddef.h>
#include <string.h> /* memcpy */
-
-#if defined(_MSC_VER) && (_MSC_VER <= 1700)
-/* for vs2012/11.0/1700 and earlier Visual Studio compilers */
-# define bool int
-# define false 0
-# define true 1
-#else
-# include <stdbool.h>
-#endif
+#include <stdbool.h>
#ifdef _WIN32
# include "winconfig.h"
-#else
-# ifdef HAVE_EXPAT_CONFIG_H
-# include <expat_config.h>
-# endif
-#endif /* ndef _WIN32 */
+#endif
#include "expat_external.h"
#include "internal.h"
@@ -72,7 +78,7 @@
#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
#define UCS2_GET_NAMING(pages, hi, lo) \
- (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1u << ((lo)&0x1F)))
+ (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1u << ((lo) & 0x1F)))
/* A 2 byte UTF-8 representation splits the characters 11 bits between
the bottom 5 and 6 bits of the bytes. We need 8 bits to index into
@@ -95,13 +101,8 @@
+ ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)] \
& (1u << (((byte)[2]) & 0x1F)))
-#define UTF8_GET_NAMING(pages, p, n) \
- ((n) == 2 \
- ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
- : ((n) == 3 ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) : 0))
-
/* Detection of invalid UTF-8 sequences is based on Table 3.1B
- of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
+ of Unicode 3.2: https://www.unicode.org/unicode/reports/tr28/
with the additional restriction of not allowing the Unicode
code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE).
Implementation details:
@@ -226,7 +227,7 @@ struct normal_encoding {
/* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \
/* isInvalid2 */ NULL, /* isInvalid3 */ NULL, /* isInvalid4 */ NULL
-static int FASTCALL checkCharRefNumber(int);
+static int FASTCALL checkCharRefNumber(int result);
#include "xmltok_impl.h"
#include "ascii.h"
@@ -244,7 +245,7 @@ static int FASTCALL checkCharRefNumber(int);
#endif
#define SB_BYTE_TYPE(enc, p) \
- (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
+ (((const struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
#ifdef XML_MIN_SIZE
static int PTRFASTCALL
@@ -269,8 +270,14 @@ sb_byteToAscii(const ENCODING *enc, const char *p) {
#define IS_NAME_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isName##n(enc, p))
#define IS_NMSTRT_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isNmstrt##n(enc, p))
-#define IS_INVALID_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
+#ifdef XML_MIN_SIZE
+# define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid##n \
+ && AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
+#else
+# define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
+#endif
#ifdef XML_MIN_SIZE
# define IS_NAME_CHAR_MINBPC(enc, p) \
@@ -292,7 +299,7 @@ sb_charMatches(const ENCODING *enc, const char *p, int c) {
}
#else
/* c is an ASCII character */
-# define CHAR_MATCHES(enc, p, c) (*(p) == c)
+# define CHAR_MATCHES(enc, p, c) (*(p) == (c))
#endif
#define PREFIX(ident) normal_##ident
@@ -402,7 +409,7 @@ utf8_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim,
unsigned short *to = *toP;
const char *from = *fromP;
while (from < fromLim && to < toLim) {
- switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
+ switch (SB_BYTE_TYPE(enc, from)) {
case BT_LEAD2:
if (fromLim - from < 2) {
res = XML_CONVERT_INPUT_INCOMPLETE;
@@ -589,13 +596,13 @@ static const struct normal_encoding ascii_encoding
static int PTRFASTCALL
unicode_byte_type(char hi, char lo) {
switch ((unsigned char)hi) {
- /* 0xD800–0xDBFF first 16-bit code unit or high surrogate (W1) */
+ /* 0xD800-0xDBFF first 16-bit code unit or high surrogate (W1) */
case 0xD8:
case 0xD9:
case 0xDA:
case 0xDB:
return BT_LEAD4;
- /* 0xDC00–0xDFFF second 16-bit code unit or low surrogate (W2) */
+ /* 0xDC00-0xDFFF second 16-bit code unit or low surrogate (W2) */
case 0xDC:
case 0xDD:
case 0xDE:
@@ -710,33 +717,28 @@ unicode_byte_type(char hi, char lo) {
return res; \
}
-#define SET2(ptr, ch) (((ptr)[0] = ((ch)&0xff)), ((ptr)[1] = ((ch) >> 8)))
#define GET_LO(ptr) ((unsigned char)(ptr)[0])
#define GET_HI(ptr) ((unsigned char)(ptr)[1])
DEFINE_UTF16_TO_UTF8(little2_)
DEFINE_UTF16_TO_UTF16(little2_)
-#undef SET2
#undef GET_LO
#undef GET_HI
-#define SET2(ptr, ch) (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch)&0xFF)))
#define GET_LO(ptr) ((unsigned char)(ptr)[1])
#define GET_HI(ptr) ((unsigned char)(ptr)[0])
DEFINE_UTF16_TO_UTF8(big2_)
DEFINE_UTF16_TO_UTF16(big2_)
-#undef SET2
#undef GET_LO
#undef GET_HI
#define LITTLE2_BYTE_TYPE(enc, p) \
- ((p)[1] == 0 ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
- : unicode_byte_type((p)[1], (p)[0]))
+ ((p)[1] == 0 ? SB_BYTE_TYPE(enc, p) : unicode_byte_type((p)[1], (p)[0]))
#define LITTLE2_BYTE_TO_ASCII(p) ((p)[1] == 0 ? (p)[0] : -1)
-#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == c)
+#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == (c))
#define LITTLE2_IS_NAME_CHAR_MINBPC(p) \
UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \
@@ -867,11 +869,9 @@ static const struct normal_encoding internal_little2_encoding
#endif
#define BIG2_BYTE_TYPE(enc, p) \
- ((p)[0] == 0 \
- ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
- : unicode_byte_type((p)[0], (p)[1]))
+ ((p)[0] == 0 ? SB_BYTE_TYPE(enc, p + 1) : unicode_byte_type((p)[0], (p)[1]))
#define BIG2_BYTE_TO_ASCII(p) ((p)[0] == 0 ? (p)[1] : -1)
-#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == c)
+#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == (c))
#define BIG2_IS_NAME_CHAR_MINBPC(p) \
UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
#define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \
diff --git a/contrib/expat/lib/xmltok.h b/contrib/expat/lib/xmltok.h
index 2adbf5307bef..c51fce1ec151 100644
--- a/contrib/expat/lib/xmltok.h
+++ b/contrib/expat/lib/xmltok.h
@@ -7,7 +7,11 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2002-2005 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -285,7 +289,8 @@ int XmlParseXmlDecl(int isGeneralTextEntity, const ENCODING *enc,
const char **encodingNamePtr,
const ENCODING **namedEncodingPtr, int *standalonePtr);
-int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
+int XmlInitEncoding(INIT_ENCODING *p, const ENCODING **encPtr,
+ const char *name);
const ENCODING *XmlGetUtf8InternalEncoding(void);
const ENCODING *XmlGetUtf16InternalEncoding(void);
int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
@@ -303,7 +308,8 @@ int XmlParseXmlDeclNS(int isGeneralTextEntity, const ENCODING *enc,
const char **encodingNamePtr,
const ENCODING **namedEncodingPtr, int *standalonePtr);
-int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
+int XmlInitEncodingNS(INIT_ENCODING *p, const ENCODING **encPtr,
+ const char *name);
const ENCODING *XmlGetUtf8InternalEncodingNS(void);
const ENCODING *XmlGetUtf16InternalEncodingNS(void);
ENCODING *XmlInitUnknownEncodingNS(void *mem, int *table, CONVERTER convert,
diff --git a/contrib/expat/lib/xmltok_impl.c b/contrib/expat/lib/xmltok_impl.c
index c209221cd79d..239a2d06c451 100644
--- a/contrib/expat/lib/xmltok_impl.c
+++ b/contrib/expat/lib/xmltok_impl.c
@@ -1,4 +1,4 @@
-/* This file is included!
+/* This file is included (from xmltok.c, 1-3 times depending on XML_MIN_SIZE)!
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -7,7 +7,16 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2018 Benjamin Peterson <benjamin@python.org>
+ Copyright (c) 2018 Anton Maklakov <antmak.pub@gmail.com>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Boris Kolpackov <boris@codesynthesis.com>
+ Copyright (c) 2022 Martin Ettl <ettl.martin78@googlemail.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,7 +41,7 @@
#ifdef XML_TOK_IMPL_C
-# ifndef IS_INVALID_CHAR
+# ifndef IS_INVALID_CHAR // i.e. for UTF-16 and XML_MIN_SIZE not defined
# define IS_INVALID_CHAR(enc, ptr, n) (0)
# endif
@@ -61,7 +70,7 @@
case BT_LEAD##n: \
if (end - ptr < n) \
return XML_TOK_PARTIAL_CHAR; \
- if (! IS_NAME_CHAR(enc, ptr, n)) { \
+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NAME_CHAR(enc, ptr, n)) { \
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
@@ -88,9 +97,9 @@
# define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
case BT_LEAD##n: \
- if (end - ptr < n) \
+ if ((end) - (ptr) < (n)) \
return XML_TOK_PARTIAL_CHAR; \
- if (! IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
@@ -116,7 +125,8 @@
# define PREFIX(ident) ident
# endif
-# define HAS_CHARS(enc, ptr, end, count) (end - ptr >= count * MINBPC(enc))
+# define HAS_CHARS(enc, ptr, end, count) \
+ ((end) - (ptr) >= ((count) * MINBPC(enc)))
# define HAS_CHAR(enc, ptr, end) HAS_CHARS(enc, ptr, end, 1)
@@ -1134,6 +1144,10 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
case BT_LEAD##n: \
if (end - ptr < n) \
return XML_TOK_PARTIAL_CHAR; \
+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
ptr += n; \
tok = XML_TOK_NAME; \
@@ -1262,7 +1276,7 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
break;
LEAD_CASE(2)
LEAD_CASE(3)
@@ -1331,7 +1345,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
break;
LEAD_CASE(2)
LEAD_CASE(3)
@@ -1510,7 +1524,7 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
state = inName; \
}
# define LEAD_CASE(n) \
- case BT_LEAD##n: \
+ case BT_LEAD##n: /* NOTE: The encoding has already been validated. */ \
START_NAME ptr += (n - MINBPC(enc)); \
break;
LEAD_CASE(2)
@@ -1722,7 +1736,7 @@ PREFIX(nameLength)(const ENCODING *enc, const char *ptr) {
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
break;
LEAD_CASE(2)
LEAD_CASE(3)
@@ -1767,14 +1781,15 @@ PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end,
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
+ pos->columnNumber++; \
break;
LEAD_CASE(2)
LEAD_CASE(3)
LEAD_CASE(4)
# undef LEAD_CASE
case BT_LF:
- pos->columnNumber = (XML_Size)-1;
+ pos->columnNumber = 0;
pos->lineNumber++;
ptr += MINBPC(enc);
break;
@@ -1783,13 +1798,13 @@ PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end,
ptr += MINBPC(enc);
if (HAS_CHAR(enc, ptr, end) && BYTE_TYPE(enc, ptr) == BT_LF)
ptr += MINBPC(enc);
- pos->columnNumber = (XML_Size)-1;
+ pos->columnNumber = 0;
break;
default:
ptr += MINBPC(enc);
+ pos->columnNumber++;
break;
}
- pos->columnNumber++;
}
}
diff --git a/contrib/expat/lib/xmltok_impl.h b/contrib/expat/lib/xmltok_impl.h
index e925dbc7e2c8..3469c4ae138c 100644
--- a/contrib/expat/lib/xmltok_impl.h
+++ b/contrib/expat/lib/xmltok_impl.h
@@ -7,7 +7,8 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2017-2019 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -44,7 +45,7 @@ enum {
BT_LF, /* line feed = "\n" */
BT_GT, /* greater than = ">" */
BT_QUOT, /* quotation character = "\"" */
- BT_APOS, /* aposthrophe = "'" */
+ BT_APOS, /* apostrophe = "'" */
BT_EQUALS, /* equal sign = "=" */
BT_QUEST, /* question mark = "?" */
BT_EXCL, /* exclamation mark = "!" */
diff --git a/contrib/expat/lib/xmltok_ns.c b/contrib/expat/lib/xmltok_ns.c
index 919c74e9f97f..fbdd3e3c7b79 100644
--- a/contrib/expat/lib/xmltok_ns.c
+++ b/contrib/expat/lib/xmltok_ns.c
@@ -7,7 +7,11 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2017-2021 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -89,7 +93,7 @@ NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
static const ENCODING *
NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) {
# define ENCODING_MAX 128
- char buf[ENCODING_MAX];
+ char buf[ENCODING_MAX] = "";
char *p = buf;
int i;
XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
diff --git a/contrib/expat/run.sh.in b/contrib/expat/run.sh.in
index ff3fb36447ca..72f86b6dcc48 100644
--- a/contrib/expat/run.sh.in
+++ b/contrib/expat/run.sh.in
@@ -1,10 +1,45 @@
#! /usr/bin/env bash
-# Copyright (C) 2017 Expat development team
-# Licensed under the MIT license
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
case "@host@" in
*-mingw*)
- exec wine "$@"
+ case "$(uname -o)" in
+ Cygwin|Msys)
+ # Windows binary on Windows host
+ exec "$@"
+ ;;
+ *)
+ # Windows binary on non-Windows host
+ exec wine "$@"
+ ;;
+ esac
;;
*)
exec "$@"
diff --git a/contrib/expat/test-driver-wrapper.sh b/contrib/expat/test-driver-wrapper.sh
index 36a185266c68..305c6f5f606b 100755
--- a/contrib/expat/test-driver-wrapper.sh
+++ b/contrib/expat/test-driver-wrapper.sh
@@ -6,7 +6,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2019 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/tests/Makefile.am b/contrib/expat/tests/Makefile.am
index 742ed437dbde..f949fe7f1ab0 100644
--- a/contrib/expat/tests/Makefile.am
+++ b/contrib/expat/tests/Makefile.am
@@ -6,7 +6,9 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -30,33 +32,63 @@
SUBDIRS = . benchmark
-AM_CPPFLAGS = -I$(srcdir)/../lib
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
-noinst_LIBRARIES = libruntests.a
-
-check_PROGRAMS = runtests runtestspp
-TESTS = runtests runtestspp
+check_PROGRAMS = runtests runtests_cxx
+TESTS = runtests runtests_cxx
# To support MinGW and Non-MinGW at the same time:
LOG_DRIVER = $(srcdir)/../test-driver-wrapper.sh
-libruntests_a_SOURCES = \
+runtests_SOURCES = \
+ acc_tests.c \
+ alloc_tests.c \
+ basic_tests.c \
chardata.c \
- structdata.c \
+ common.c \
+ dummy.c \
+ handlers.c \
memcheck.c \
- minicheck.c
+ minicheck.c \
+ misc_tests.c \
+ ns_tests.c \
+ nsalloc_tests.c \
+ runtests.c \
+ structdata.c
-runtests_SOURCES = \
- runtests.c
+runtests_cxx_SOURCES = \
+ acc_tests_cxx.cpp \
+ alloc_tests_cxx.cpp \
+ basic_tests_cxx.cpp \
+ chardata_cxx.cpp \
+ common_cxx.cpp \
+ dummy_cxx.cpp \
+ handlers_cxx.cpp \
+ memcheck_cxx.cpp \
+ minicheck_cxx.cpp \
+ misc_tests_cxx.cpp \
+ nsalloc_tests_cxx.cpp \
+ ns_tests_cxx.cpp \
+ runtests_cxx.cpp \
+ structdata_cxx.cpp
-runtestspp_SOURCES = \
- runtestspp.cpp
+runtests_LDADD = ../lib/libexpatinternal.la
+runtests_cxx_LDADD = ../lib/libexpatinternal.la
-runtests_LDADD = libruntests.a ../lib/libexpat.la
-runtestspp_LDADD = libruntests.a ../lib/libexpat.la
+runtests_LDFLAGS = @AM_LDFLAGS@ @LIBM@
+runtests_cxx_LDFLAGS = @AM_LDFLAGS@ @LIBM@
EXTRA_DIST = \
+ acc_tests.h \
+ alloc_tests.h \
+ basic_tests.h \
chardata.h \
+ common.h \
+ dummy.h \
+ handlers.h \
+ misc_tests.h \
+ ns_tests.h \
+ nsalloc_tests.h \
structdata.h \
minicheck.h \
memcheck.h \
diff --git a/contrib/expat/tests/Makefile.in b/contrib/expat/tests/Makefile.in
index b64e43b80b9c..4c4fd928e3c7 100644
--- a/contrib/expat/tests/Makefile.in
+++ b/contrib/expat/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,9 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -43,7 +45,6 @@
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
# USE OR OTHER DEALINGS IN THE SOFTWARE.
-
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
@@ -118,8 +119,8 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-check_PROGRAMS = runtests$(EXEEXT) runtestspp$(EXEEXT)
-TESTS = runtests$(EXEEXT) runtestspp$(EXEEXT)
+check_PROGRAMS = runtests$(EXEEXT) runtests_cxx$(EXEEXT)
+TESTS = runtests$(EXEEXT) runtests_cxx$(EXEEXT)
subdir = tests
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
@@ -133,6 +134,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/conftools/ax-append-compile-flags.m4 \
$(top_srcdir)/conftools/ax-append-link-flags.m4 \
$(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx-11.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -141,27 +144,34 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/expat_config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-LIBRARIES = $(noinst_LIBRARIES)
-ARFLAGS = cru
-AM_V_AR = $(am__v_AR_@AM_V@)
-am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
-am__v_AR_0 = @echo " AR " $@;
-am__v_AR_1 =
-libruntests_a_AR = $(AR) $(ARFLAGS)
-libruntests_a_LIBADD =
-am_libruntests_a_OBJECTS = chardata.$(OBJEXT) structdata.$(OBJEXT) \
- memcheck.$(OBJEXT) minicheck.$(OBJEXT)
-libruntests_a_OBJECTS = $(am_libruntests_a_OBJECTS)
-am_runtests_OBJECTS = runtests.$(OBJEXT)
+am_runtests_OBJECTS = acc_tests.$(OBJEXT) alloc_tests.$(OBJEXT) \
+ basic_tests.$(OBJEXT) chardata.$(OBJEXT) common.$(OBJEXT) \
+ dummy.$(OBJEXT) handlers.$(OBJEXT) memcheck.$(OBJEXT) \
+ minicheck.$(OBJEXT) misc_tests.$(OBJEXT) ns_tests.$(OBJEXT) \
+ nsalloc_tests.$(OBJEXT) runtests.$(OBJEXT) \
+ structdata.$(OBJEXT)
runtests_OBJECTS = $(am_runtests_OBJECTS)
-runtests_DEPENDENCIES = libruntests.a ../lib/libexpat.la
+runtests_DEPENDENCIES = ../lib/libexpatinternal.la
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
-am_runtestspp_OBJECTS = runtestspp.$(OBJEXT)
-runtestspp_OBJECTS = $(am_runtestspp_OBJECTS)
-runtestspp_DEPENDENCIES = libruntests.a ../lib/libexpat.la
+runtests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(runtests_LDFLAGS) $(LDFLAGS) -o $@
+am_runtests_cxx_OBJECTS = acc_tests_cxx.$(OBJEXT) \
+ alloc_tests_cxx.$(OBJEXT) basic_tests_cxx.$(OBJEXT) \
+ chardata_cxx.$(OBJEXT) common_cxx.$(OBJEXT) \
+ dummy_cxx.$(OBJEXT) handlers_cxx.$(OBJEXT) \
+ memcheck_cxx.$(OBJEXT) minicheck_cxx.$(OBJEXT) \
+ misc_tests_cxx.$(OBJEXT) nsalloc_tests_cxx.$(OBJEXT) \
+ ns_tests_cxx.$(OBJEXT) runtests_cxx.$(OBJEXT) \
+ structdata_cxx.$(OBJEXT)
+runtests_cxx_OBJECTS = $(am_runtests_cxx_OBJECTS)
+runtests_cxx_DEPENDENCIES = ../lib/libexpatinternal.la
+runtests_cxx_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(runtests_cxx_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -177,9 +187,21 @@ am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
am__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/chardata.Po ./$(DEPDIR)/memcheck.Po \
- ./$(DEPDIR)/minicheck.Po ./$(DEPDIR)/runtests.Po \
- ./$(DEPDIR)/runtestspp.Po ./$(DEPDIR)/structdata.Po
+am__depfiles_remade = ./$(DEPDIR)/acc_tests.Po \
+ ./$(DEPDIR)/acc_tests_cxx.Po ./$(DEPDIR)/alloc_tests.Po \
+ ./$(DEPDIR)/alloc_tests_cxx.Po ./$(DEPDIR)/basic_tests.Po \
+ ./$(DEPDIR)/basic_tests_cxx.Po ./$(DEPDIR)/chardata.Po \
+ ./$(DEPDIR)/chardata_cxx.Po ./$(DEPDIR)/common.Po \
+ ./$(DEPDIR)/common_cxx.Po ./$(DEPDIR)/dummy.Po \
+ ./$(DEPDIR)/dummy_cxx.Po ./$(DEPDIR)/handlers.Po \
+ ./$(DEPDIR)/handlers_cxx.Po ./$(DEPDIR)/memcheck.Po \
+ ./$(DEPDIR)/memcheck_cxx.Po ./$(DEPDIR)/minicheck.Po \
+ ./$(DEPDIR)/minicheck_cxx.Po ./$(DEPDIR)/misc_tests.Po \
+ ./$(DEPDIR)/misc_tests_cxx.Po ./$(DEPDIR)/ns_tests.Po \
+ ./$(DEPDIR)/ns_tests_cxx.Po ./$(DEPDIR)/nsalloc_tests.Po \
+ ./$(DEPDIR)/nsalloc_tests_cxx.Po ./$(DEPDIR)/runtests.Po \
+ ./$(DEPDIR)/runtests_cxx.Po ./$(DEPDIR)/structdata.Po \
+ ./$(DEPDIR)/structdata_cxx.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -217,10 +239,8 @@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
am__v_CXXLD_1 =
-SOURCES = $(libruntests_a_SOURCES) $(runtests_SOURCES) \
- $(runtestspp_SOURCES)
-DIST_SOURCES = $(libruntests_a_SOURCES) $(runtests_SOURCES) \
- $(runtestspp_SOURCES)
+SOURCES = $(runtests_SOURCES) $(runtests_cxx_SOURCES)
+DIST_SOURCES = $(runtests_SOURCES) $(runtests_cxx_SOURCES)
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-recursive \
install-data-recursive install-dvi-recursive \
@@ -259,8 +279,6 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__tty_colors_dummy = \
mgn= red= grn= lgn= blu= brg= std=; \
am__color_tests=no
@@ -443,6 +461,7 @@ am__set_TESTS_bases = \
bases='$(TEST_LOGS)'; \
bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
RECHECK_LOGS = $(TEST_LOGS)
TEST_SUITE_LOG = test-suite.log
TEST_EXTENSIONS = @EXEEXT@ .test
@@ -495,7 +514,11 @@ am__relativize = \
reldir="$$dir2"
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
@@ -505,8 +528,10 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CPP = @CPP@
+CMAKE_SHARED_LIBRARY_PREFIX = @CMAKE_SHARED_LIBRARY_PREFIX@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -522,10 +547,20 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
+EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
+EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
+EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
+EXPAT_DTD = @EXPAT_DTD@
+EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
+EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
+EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FILEMAP = @FILEMAP@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -535,6 +570,8 @@ LD = @LD@
LDFLAGS = @LDFLAGS@
LIBAGE = @LIBAGE@
LIBCURRENT = @LIBCURRENT@
+LIBDIR_BASENAME = @LIBDIR_BASENAME@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBREVISION = @LIBREVISION@
LIBS = @LIBS@
@@ -543,6 +580,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -564,6 +602,9 @@ RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SO_MAJOR = @SO_MAJOR@
+SO_MINOR = @SO_MINOR@
+SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
@@ -574,6 +615,7 @@ ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_void_p = @ac_cv_sizeof_void_p@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -611,6 +653,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -620,27 +663,56 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
SUBDIRS = . benchmark
-AM_CPPFLAGS = -I$(srcdir)/../lib
-noinst_LIBRARIES = libruntests.a
# To support MinGW and Non-MinGW at the same time:
LOG_DRIVER = $(srcdir)/../test-driver-wrapper.sh
-libruntests_a_SOURCES = \
+runtests_SOURCES = \
+ acc_tests.c \
+ alloc_tests.c \
+ basic_tests.c \
chardata.c \
- structdata.c \
+ common.c \
+ dummy.c \
+ handlers.c \
memcheck.c \
- minicheck.c
-
-runtests_SOURCES = \
- runtests.c
-
-runtestspp_SOURCES = \
- runtestspp.cpp
-
-runtests_LDADD = libruntests.a ../lib/libexpat.la
-runtestspp_LDADD = libruntests.a ../lib/libexpat.la
+ minicheck.c \
+ misc_tests.c \
+ ns_tests.c \
+ nsalloc_tests.c \
+ runtests.c \
+ structdata.c
+
+runtests_cxx_SOURCES = \
+ acc_tests_cxx.cpp \
+ alloc_tests_cxx.cpp \
+ basic_tests_cxx.cpp \
+ chardata_cxx.cpp \
+ common_cxx.cpp \
+ dummy_cxx.cpp \
+ handlers_cxx.cpp \
+ memcheck_cxx.cpp \
+ minicheck_cxx.cpp \
+ misc_tests_cxx.cpp \
+ nsalloc_tests_cxx.cpp \
+ ns_tests_cxx.cpp \
+ runtests_cxx.cpp \
+ structdata_cxx.cpp
+
+runtests_LDADD = ../lib/libexpatinternal.la
+runtests_cxx_LDADD = ../lib/libexpatinternal.la
+runtests_LDFLAGS = @AM_LDFLAGS@ @LIBM@
+runtests_cxx_LDFLAGS = @AM_LDFLAGS@ @LIBM@
EXTRA_DIST = \
+ acc_tests.h \
+ alloc_tests.h \
+ basic_tests.h \
chardata.h \
+ common.h \
+ dummy.h \
+ handlers.h \
+ misc_tests.h \
+ ns_tests.h \
+ nsalloc_tests.h \
structdata.h \
minicheck.h \
memcheck.h \
@@ -653,7 +725,7 @@ all: all-recursive
.SUFFIXES:
.SUFFIXES: .c .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -677,9 +749,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: $(am__configure_deps)
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
@@ -692,21 +764,13 @@ clean-checkPROGRAMS:
echo " rm -f" $$list; \
rm -f $$list
-clean-noinstLIBRARIES:
- -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
-
-libruntests.a: $(libruntests_a_OBJECTS) $(libruntests_a_DEPENDENCIES) $(EXTRA_libruntests_a_DEPENDENCIES)
- $(AM_V_at)-rm -f libruntests.a
- $(AM_V_AR)$(libruntests_a_AR) libruntests.a $(libruntests_a_OBJECTS) $(libruntests_a_LIBADD)
- $(AM_V_at)$(RANLIB) libruntests.a
-
runtests$(EXEEXT): $(runtests_OBJECTS) $(runtests_DEPENDENCIES) $(EXTRA_runtests_DEPENDENCIES)
@rm -f runtests$(EXEEXT)
- $(AM_V_CCLD)$(LINK) $(runtests_OBJECTS) $(runtests_LDADD) $(LIBS)
+ $(AM_V_CCLD)$(runtests_LINK) $(runtests_OBJECTS) $(runtests_LDADD) $(LIBS)
-runtestspp$(EXEEXT): $(runtestspp_OBJECTS) $(runtestspp_DEPENDENCIES) $(EXTRA_runtestspp_DEPENDENCIES)
- @rm -f runtestspp$(EXEEXT)
- $(AM_V_CXXLD)$(CXXLINK) $(runtestspp_OBJECTS) $(runtestspp_LDADD) $(LIBS)
+runtests_cxx$(EXEEXT): $(runtests_cxx_OBJECTS) $(runtests_cxx_DEPENDENCIES) $(EXTRA_runtests_cxx_DEPENDENCIES)
+ @rm -f runtests_cxx$(EXEEXT)
+ $(AM_V_CXXLD)$(runtests_cxx_LINK) $(runtests_cxx_OBJECTS) $(runtests_cxx_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -714,12 +778,34 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acc_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acc_tests_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc_tests_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_tests_cxx.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chardata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chardata_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handlers.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handlers_cxx.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memcheck.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memcheck_cxx.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minicheck.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minicheck_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc_tests_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ns_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ns_tests_cxx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsalloc_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsalloc_tests_cxx.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtests.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtestspp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtests_cxx.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/structdata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/structdata_cxx.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@@ -981,7 +1067,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
fi; \
echo "$${col}$$br$${std}"; \
- echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
echo "$${col}$$br$${std}"; \
create_testsuite_report --maybe-color; \
echo "$$col$$br$$std"; \
@@ -1022,9 +1108,9 @@ runtests.log: runtests$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
-runtestspp.log: runtestspp$(EXEEXT)
- @p='runtestspp$(EXEEXT)'; \
- b='runtestspp'; \
+runtests_cxx.log: runtests_cxx$(EXEEXT)
+ @p='runtests_cxx$(EXEEXT)'; \
+ b='runtests_cxx'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
@@ -1043,7 +1129,6 @@ runtestspp.log: runtestspp$(EXEEXT)
@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -1106,7 +1191,7 @@ check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
check: check-recursive
-all-am: Makefile $(LIBRARIES)
+all-am: Makefile
installdirs: installdirs-recursive
installdirs-am:
install: install-recursive
@@ -1145,15 +1230,37 @@ maintainer-clean-generic:
clean: clean-recursive
clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
- clean-noinstLIBRARIES mostlyclean-am
+ mostlyclean-am
distclean: distclean-recursive
- -rm -f ./$(DEPDIR)/chardata.Po
+ -rm -f ./$(DEPDIR)/acc_tests.Po
+ -rm -f ./$(DEPDIR)/acc_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/alloc_tests.Po
+ -rm -f ./$(DEPDIR)/alloc_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/basic_tests.Po
+ -rm -f ./$(DEPDIR)/basic_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/chardata.Po
+ -rm -f ./$(DEPDIR)/chardata_cxx.Po
+ -rm -f ./$(DEPDIR)/common.Po
+ -rm -f ./$(DEPDIR)/common_cxx.Po
+ -rm -f ./$(DEPDIR)/dummy.Po
+ -rm -f ./$(DEPDIR)/dummy_cxx.Po
+ -rm -f ./$(DEPDIR)/handlers.Po
+ -rm -f ./$(DEPDIR)/handlers_cxx.Po
-rm -f ./$(DEPDIR)/memcheck.Po
+ -rm -f ./$(DEPDIR)/memcheck_cxx.Po
-rm -f ./$(DEPDIR)/minicheck.Po
+ -rm -f ./$(DEPDIR)/minicheck_cxx.Po
+ -rm -f ./$(DEPDIR)/misc_tests.Po
+ -rm -f ./$(DEPDIR)/misc_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/ns_tests.Po
+ -rm -f ./$(DEPDIR)/ns_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/nsalloc_tests.Po
+ -rm -f ./$(DEPDIR)/nsalloc_tests_cxx.Po
-rm -f ./$(DEPDIR)/runtests.Po
- -rm -f ./$(DEPDIR)/runtestspp.Po
+ -rm -f ./$(DEPDIR)/runtests_cxx.Po
-rm -f ./$(DEPDIR)/structdata.Po
+ -rm -f ./$(DEPDIR)/structdata_cxx.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -1199,12 +1306,34 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-recursive
- -rm -f ./$(DEPDIR)/chardata.Po
+ -rm -f ./$(DEPDIR)/acc_tests.Po
+ -rm -f ./$(DEPDIR)/acc_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/alloc_tests.Po
+ -rm -f ./$(DEPDIR)/alloc_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/basic_tests.Po
+ -rm -f ./$(DEPDIR)/basic_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/chardata.Po
+ -rm -f ./$(DEPDIR)/chardata_cxx.Po
+ -rm -f ./$(DEPDIR)/common.Po
+ -rm -f ./$(DEPDIR)/common_cxx.Po
+ -rm -f ./$(DEPDIR)/dummy.Po
+ -rm -f ./$(DEPDIR)/dummy_cxx.Po
+ -rm -f ./$(DEPDIR)/handlers.Po
+ -rm -f ./$(DEPDIR)/handlers_cxx.Po
-rm -f ./$(DEPDIR)/memcheck.Po
+ -rm -f ./$(DEPDIR)/memcheck_cxx.Po
-rm -f ./$(DEPDIR)/minicheck.Po
+ -rm -f ./$(DEPDIR)/minicheck_cxx.Po
+ -rm -f ./$(DEPDIR)/misc_tests.Po
+ -rm -f ./$(DEPDIR)/misc_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/ns_tests.Po
+ -rm -f ./$(DEPDIR)/ns_tests_cxx.Po
+ -rm -f ./$(DEPDIR)/nsalloc_tests.Po
+ -rm -f ./$(DEPDIR)/nsalloc_tests_cxx.Po
-rm -f ./$(DEPDIR)/runtests.Po
- -rm -f ./$(DEPDIR)/runtestspp.Po
+ -rm -f ./$(DEPDIR)/runtests_cxx.Po
-rm -f ./$(DEPDIR)/structdata.Po
+ -rm -f ./$(DEPDIR)/structdata_cxx.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@@ -1227,19 +1356,18 @@ uninstall-am:
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
am--depfiles check check-TESTS check-am clean \
- clean-checkPROGRAMS clean-generic clean-libtool \
- clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \
- distclean-compile distclean-generic distclean-libtool \
- distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-data install-data-am install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-ps install-ps-am \
- install-strip installcheck installcheck-am installdirs \
- installdirs-am maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-compile mostlyclean-generic \
- mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
- uninstall uninstall-am
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ recheck tags tags-am uninstall uninstall-am
.PRECIOUS: Makefile
diff --git a/contrib/expat/tests/acc_tests.c b/contrib/expat/tests/acc_tests.c
new file mode 100644
index 000000000000..e1c4b7f7eb51
--- /dev/null
+++ b/contrib/expat/tests/acc_tests.c
@@ -0,0 +1,396 @@
+/* Tests in the "accounting" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <math.h> /* NAN, INFINITY */
+#include <stdio.h>
+#include <string.h>
+
+#include "expat_config.h"
+
+#include "expat.h"
+#include "internal.h"
+#include "common.h"
+#include "minicheck.h"
+#include "chardata.h"
+#include "handlers.h"
+#include "acc_tests.h"
+
+#if XML_GE == 1
+START_TEST(test_accounting_precision) {
+ struct AccountingTestCase cases[] = {
+ {"<e/>", NULL, NULL, 0},
+ {"<e></e>", NULL, NULL, 0},
+
+ /* Attributes */
+ {"<e k1=\"v2\" k2=\"v2\"/>", NULL, NULL, 0},
+ {"<e k1=\"v2\" k2=\"v2\"></e>", NULL, NULL, 0},
+ {"<p:e xmlns:p=\"https://domain.invalid/\" />", NULL, NULL, 0},
+ {"<e k=\"&amp;&apos;&gt;&lt;&quot;\" />", NULL, NULL,
+ sizeof(XML_Char) * 5 /* number of predefined entities */},
+ {"<e1 xmlns='https://example.org/'>\n"
+ " <e2 xmlns=''/>\n"
+ "</e1>",
+ NULL, NULL, 0},
+
+ /* Text */
+ {"<e>text</e>", NULL, NULL, 0},
+ {"<e1><e2>text1<e3/>text2</e2></e1>", NULL, NULL, 0},
+ {"<e>&amp;&apos;&gt;&lt;&quot;</e>", NULL, NULL,
+ sizeof(XML_Char) * 5 /* number of predefined entities */},
+ {"<e>&#65;&#41;</e>", NULL, NULL, 0},
+
+ /* Prolog */
+ {"<?xml version=\"1.0\"?><root/>", NULL, NULL, 0},
+
+ /* Whitespace */
+ {" <e1> <e2> </e2> </e1> ", NULL, NULL, 0},
+ {"<e1 ><e2 /></e1 >", NULL, NULL, 0},
+ {"<e1><e2 k = \"v\"/><e3 k = 'v'/></e1>", NULL, NULL, 0},
+
+ /* Comments */
+ {"<!-- Comment --><e><!-- Comment --></e>", NULL, NULL, 0},
+
+ /* Processing instructions */
+ {"<?xml-stylesheet type=\"text/xsl\" href=\"https://domain.invalid/\" media=\"all\"?><e/>",
+ NULL, NULL, 0},
+ {"<?pi0?><?pi1 ?><?pi2 ?><r/><?pi4?>", NULL, NULL, 0},
+# ifdef XML_DTD
+ {"<?pi0?><?pi1 ?><?pi2 ?><!DOCTYPE r SYSTEM 'first.ent'><r/>",
+ "<?pi3?><!ENTITY % e1 SYSTEM 'second.ent'><?pi4?>%e1;<?pi5?>", "<?pi6?>",
+ 0},
+# endif /* XML_DTD */
+
+ /* CDATA */
+ {"<e><![CDATA[one two three]]></e>", NULL, NULL, 0},
+ /* The following is the essence of this OSS-Fuzz finding:
+ https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34302
+ https://oss-fuzz.com/testcase-detail/4860575394955264
+ */
+ {"<!DOCTYPE r [\n"
+ "<!ENTITY e \"111<![CDATA[2 <= 2]]>333\">\n"
+ "]>\n"
+ "<r>&e;</r>\n",
+ NULL, NULL, sizeof(XML_Char) * strlen("111<![CDATA[2 <= 2]]>333")},
+
+# ifdef XML_DTD
+ /* Conditional sections */
+ {"<!DOCTYPE r [\n"
+ "<!ENTITY % draft 'INCLUDE'>\n"
+ "<!ENTITY % final 'IGNORE'>\n"
+ "<!ENTITY % import SYSTEM \"first.ent\">\n"
+ "%import;\n"
+ "]>\n"
+ "<r/>\n",
+ "<![%draft;[<!--1-->]]>\n"
+ "<![%final;[<!--22-->]]>",
+ NULL, sizeof(XML_Char) * (strlen("INCLUDE") + strlen("IGNORE"))},
+# endif /* XML_DTD */
+
+ /* General entities */
+ {"<!DOCTYPE root [\n"
+ "<!ENTITY nine \"123456789\">\n"
+ "]>\n"
+ "<root>&nine;</root>",
+ NULL, NULL, sizeof(XML_Char) * strlen("123456789")},
+ {"<!DOCTYPE root [\n"
+ "<!ENTITY nine \"123456789\">\n"
+ "]>\n"
+ "<root k1=\"&nine;\"/>",
+ NULL, NULL, sizeof(XML_Char) * strlen("123456789")},
+ {"<!DOCTYPE root [\n"
+ "<!ENTITY nine \"123456789\">\n"
+ "<!ENTITY nine2 \"&nine;&nine;\">\n"
+ "]>\n"
+ "<root>&nine2;&nine2;&nine2;</root>",
+ NULL, NULL,
+ sizeof(XML_Char) * 3 /* calls to &nine2; */ * 2 /* calls to &nine; */
+ * (strlen("&nine;") + strlen("123456789"))},
+ {"<!DOCTYPE r [\n"
+ " <!ENTITY five SYSTEM 'first.ent'>\n"
+ "]>\n"
+ "<r>&five;</r>",
+ "12345", NULL, 0},
+ {"<!DOCTYPE r [\n"
+ " <!ENTITY five SYSTEM 'first.ent'>\n"
+ "]>\n"
+ "<r>&five;</r>",
+ "\xEF\xBB\xBF" /* UTF-8 BOM */, NULL, 0},
+
+# ifdef XML_DTD
+ /* Parameter entities */
+ {"<!DOCTYPE r [\n"
+ "<!ENTITY % comment \"<!---->\">\n"
+ "%comment;\n"
+ "]>\n"
+ "<r/>",
+ NULL, NULL, sizeof(XML_Char) * strlen("<!---->")},
+ {"<!DOCTYPE r [\n"
+ "<!ENTITY % ninedef \"&#60;!ENTITY nine &#34;123456789&#34;&#62;\">\n"
+ "%ninedef;\n"
+ "]>\n"
+ "<r>&nine;</r>",
+ NULL, NULL,
+ sizeof(XML_Char)
+ * (strlen("<!ENTITY nine \"123456789\">") + strlen("123456789"))},
+ {"<!DOCTYPE r [\n"
+ "<!ENTITY % comment \"<!--1-->\">\n"
+ "<!ENTITY % comment2 \"&#37;comment;<!--22-->&#37;comment;\">\n"
+ "%comment2;\n"
+ "]>\n"
+ "<r/>\n",
+ NULL, NULL,
+ sizeof(XML_Char)
+ * (strlen("%comment;<!--22-->%comment;") + 2 * strlen("<!--1-->"))},
+ {"<!DOCTYPE r [\n"
+ " <!ENTITY % five \"12345\">\n"
+ " <!ENTITY % five2def \"&#60;!ENTITY five2 &#34;[&#37;five;][&#37;five;]]]]&#34;&#62;\">\n"
+ " %five2def;\n"
+ "]>\n"
+ "<r>&five2;</r>",
+ NULL, NULL, /* from "%five2def;": */
+ sizeof(XML_Char)
+ * (strlen("<!ENTITY five2 \"[%five;][%five;]]]]\">")
+ + 2 /* calls to "%five;" */ * strlen("12345")
+ + /* from "&five2;": */ strlen("[12345][12345]]]]"))},
+ {"<!DOCTYPE r SYSTEM \"first.ent\">\n"
+ "<r/>",
+ "<!ENTITY % comment '<!--1-->'>\n"
+ "<!ENTITY % comment2 '<!--22-->%comment;<!--22-->%comment;<!--22-->'>\n"
+ "%comment2;",
+ NULL,
+ sizeof(XML_Char)
+ * (strlen("<!--22-->%comment;<!--22-->%comment;<!--22-->")
+ + 2 /* calls to "%comment;" */ * strlen("<!---->"))},
+ {"<!DOCTYPE r SYSTEM 'first.ent'>\n"
+ "<r/>",
+ "<!ENTITY % e1 PUBLIC 'foo' 'second.ent'>\n"
+ "<!ENTITY % e2 '<!--22-->%e1;<!--22-->'>\n"
+ "%e2;\n",
+ "<!--1-->", sizeof(XML_Char) * strlen("<!--22--><!--1--><!--22-->")},
+ {
+ "<!DOCTYPE r SYSTEM 'first.ent'>\n"
+ "<r/>",
+ "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>",
+ "<?xml version='1.0' encoding='utf-8'?>\n"
+ "hello\n"
+ "xml" /* without trailing newline! */,
+ 0,
+ },
+ {
+ "<!DOCTYPE r SYSTEM 'first.ent'>\n"
+ "<r/>",
+ "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>",
+ "<?xml version='1.0' encoding='utf-8'?>\n"
+ "hello\n"
+ "xml\n" /* with trailing newline! */,
+ 0,
+ },
+ {"<!DOCTYPE doc SYSTEM 'first.ent'>\n"
+ "<doc></doc>\n",
+ "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n"
+ "%e1;\n",
+ "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>" /* UTF-8 BOM */,
+ strlen("\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>")},
+# endif /* XML_DTD */
+ };
+
+ const size_t countCases = sizeof(cases) / sizeof(cases[0]);
+ size_t u = 0;
+ for (; u < countCases; u++) {
+ const unsigned long long expectedCountBytesDirect
+ = strlen(cases[u].primaryText);
+ const unsigned long long expectedCountBytesIndirect
+ = (cases[u].firstExternalText ? strlen(cases[u].firstExternalText) : 0)
+ + (cases[u].secondExternalText ? strlen(cases[u].secondExternalText)
+ : 0)
+ + cases[u].expectedCountBytesIndirectExtra;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ if (cases[u].firstExternalText) {
+ XML_SetExternalEntityRefHandler(parser,
+ accounting_external_entity_ref_handler);
+ XML_SetUserData(parser, (void *)&cases[u]);
+ }
+
+ enum XML_Status status
+ = _XML_Parse_SINGLE_BYTES(parser, cases[u].primaryText,
+ (int)strlen(cases[u].primaryText), XML_TRUE);
+ if (status != XML_STATUS_OK) {
+ _xml_failure(parser, __FILE__, __LINE__);
+ }
+
+ const unsigned long long actualCountBytesDirect
+ = testingAccountingGetCountBytesDirect(parser);
+ const unsigned long long actualCountBytesIndirect
+ = testingAccountingGetCountBytesIndirect(parser);
+
+ XML_ParserFree(parser);
+
+ if (actualCountBytesDirect != expectedCountBytesDirect) {
+ fprintf(
+ stderr,
+ "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ": Expected " EXPAT_FMT_ULL(
+ "") " count direct bytes, got " EXPAT_FMT_ULL("") " instead.\n",
+ u + 1, countCases, expectedCountBytesDirect, actualCountBytesDirect);
+ fail("Count of direct bytes is off");
+ }
+
+ if (actualCountBytesIndirect != expectedCountBytesIndirect) {
+ fprintf(
+ stderr,
+ "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ": Expected " EXPAT_FMT_ULL(
+ "") " count indirect bytes, got " EXPAT_FMT_ULL("") " instead.\n",
+ u + 1, countCases, expectedCountBytesIndirect,
+ actualCountBytesIndirect);
+ fail("Count of indirect bytes is off");
+ }
+ }
+}
+END_TEST
+
+START_TEST(test_billion_laughs_attack_protection_api) {
+ XML_Parser parserWithoutParent = XML_ParserCreate(NULL);
+ XML_Parser parserWithParent = XML_ExternalEntityParserCreate(
+ parserWithoutParent, XCS("entity123"), NULL);
+ if (parserWithoutParent == NULL)
+ fail("parserWithoutParent is NULL");
+ if (parserWithParent == NULL)
+ fail("parserWithParent is NULL");
+
+ // XML_SetBillionLaughsAttackProtectionMaximumAmplification, error cases
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(NULL, 123.0f)
+ == XML_TRUE)
+ fail("Call with NULL parser is NOT supposed to succeed");
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(parserWithParent,
+ 123.0f)
+ == XML_TRUE)
+ fail("Call with non-root parser is NOT supposed to succeed");
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parserWithoutParent, NAN)
+ == XML_TRUE)
+ fail("Call with NaN limit is NOT supposed to succeed");
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parserWithoutParent, -1.0f)
+ == XML_TRUE)
+ fail("Call with negative limit is NOT supposed to succeed");
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parserWithoutParent, 0.9f)
+ == XML_TRUE)
+ fail("Call with positive limit <1.0 is NOT supposed to succeed");
+
+ // XML_SetBillionLaughsAttackProtectionMaximumAmplification, success cases
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parserWithoutParent, 1.0f)
+ == XML_FALSE)
+ fail("Call with positive limit >=1.0 is supposed to succeed");
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parserWithoutParent, 123456.789f)
+ == XML_FALSE)
+ fail("Call with positive limit >=1.0 is supposed to succeed");
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parserWithoutParent, INFINITY)
+ == XML_FALSE)
+ fail("Call with positive limit >=1.0 is supposed to succeed");
+
+ // XML_SetBillionLaughsAttackProtectionActivationThreshold, error cases
+ if (XML_SetBillionLaughsAttackProtectionActivationThreshold(NULL, 123)
+ == XML_TRUE)
+ fail("Call with NULL parser is NOT supposed to succeed");
+ if (XML_SetBillionLaughsAttackProtectionActivationThreshold(parserWithParent,
+ 123)
+ == XML_TRUE)
+ fail("Call with non-root parser is NOT supposed to succeed");
+
+ // XML_SetBillionLaughsAttackProtectionActivationThreshold, success cases
+ if (XML_SetBillionLaughsAttackProtectionActivationThreshold(
+ parserWithoutParent, 123)
+ == XML_FALSE)
+ fail("Call with non-NULL parentless parser is supposed to succeed");
+
+ XML_ParserFree(parserWithParent);
+ XML_ParserFree(parserWithoutParent);
+}
+END_TEST
+
+START_TEST(test_helper_unsigned_char_to_printable) {
+ // Smoke test
+ unsigned char uc = 0;
+ for (; uc < (unsigned char)-1; uc++) {
+ set_subtest("char %u", (unsigned)uc);
+ const char *const printable = unsignedCharToPrintable(uc);
+ if (printable == NULL)
+ fail("unsignedCharToPrintable returned NULL");
+ else if (strlen(printable) < (size_t)1)
+ fail("unsignedCharToPrintable returned empty string");
+ }
+
+ // Two concrete samples
+ set_subtest("char 'A'");
+ if (strcmp(unsignedCharToPrintable('A'), "A") != 0)
+ fail("unsignedCharToPrintable result mistaken");
+ set_subtest("char '\\'");
+ if (strcmp(unsignedCharToPrintable('\\'), "\\\\") != 0)
+ fail("unsignedCharToPrintable result mistaken");
+}
+END_TEST
+#endif // XML_GE == 1
+
+void
+make_accounting_test_case(Suite *s) {
+#if XML_GE == 1
+ TCase *tc_accounting = tcase_create("accounting tests");
+
+ suite_add_tcase(s, tc_accounting);
+
+ tcase_add_test(tc_accounting, test_accounting_precision);
+ tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
+ tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
+#else
+ UNUSED_P(s);
+#endif /* XML_GE == 1 */
+}
diff --git a/contrib/expat/tests/acc_tests.h b/contrib/expat/tests/acc_tests.h
new file mode 100644
index 000000000000..bbb93f37ed20
--- /dev/null
+++ b/contrib/expat/tests/acc_tests.h
@@ -0,0 +1,56 @@
+/* Tests in the "accounting" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_ACC_TESTS_H
+# define XML_ACC_TESTS_H
+
+extern void make_accounting_test_case(Suite *s);
+
+#endif /* XML_ACC_TESTS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/xmlwf/xmlurl.h b/contrib/expat/tests/acc_tests_cxx.cpp
index f2cff093e2ea..01644991ae51 100644
--- a/contrib/expat/xmlwf/xmlurl.h
+++ b/contrib/expat/tests/acc_tests_cxx.cpp
@@ -1,4 +1,4 @@
-/*
+/* C++ compilation harness for the test suite.
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -6,8 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,16 +29,4 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int XML_URLInit();
-void XML_URLUninit();
-int XML_ProcessURL(XML_Parser parser,
- const XML_Char *url,
- unsigned flags);
-
-#ifdef __cplusplus
-}
-#endif
+#include "acc_tests.c"
diff --git a/contrib/expat/tests/alloc_tests.c b/contrib/expat/tests/alloc_tests.c
new file mode 100644
index 000000000000..e5d46ebea821
--- /dev/null
+++ b/contrib/expat/tests/alloc_tests.c
@@ -0,0 +1,2127 @@
+/* Tests in the "allocation" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
+#endif
+
+#include <string.h>
+#include <assert.h>
+
+#include "expat.h"
+#include "common.h"
+#include "minicheck.h"
+#include "dummy.h"
+#include "handlers.h"
+#include "alloc_tests.h"
+
+static void
+alloc_setup(void) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
+
+ /* Ensure the parser creation will go through */
+ g_allocation_count = ALLOC_ALWAYS_SUCCEED;
+ g_reallocation_count = REALLOC_ALWAYS_SUCCEED;
+ g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
+ if (g_parser == NULL)
+ fail("Parser not created");
+}
+
+static void
+alloc_teardown(void) {
+ basic_teardown();
+}
+
+/* Test the effects of allocation failures on xml declaration processing */
+START_TEST(test_alloc_parse_xdecl) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>Hello, world</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* Resetting the parser is insufficient, because some memory
+ * allocations are cached within the parser. Instead we use
+ * the teardown and setup routines to ensure that we have the
+ * right sort of parser back in our hands.
+ */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+/* As above, but with an encoding big enough to cause storing the
+ * version information to expand the string pool being used.
+ */
+START_TEST(test_alloc_parse_xdecl_2) {
+ const char *text
+ = "<?xml version='1.0' encoding='"
+ /* Each line is 64 characters */
+ "ThisIsAStupidlyLongEncodingNameIntendedToTriggerPoolGrowth123456"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN"
+ "'?>"
+ "<doc>Hello, world</doc>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
+ XML_SetUnknownEncodingHandler(g_parser, long_encoding_handler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+/* Test the effects of allocation failures on a straightforward parse */
+START_TEST(test_alloc_parse_pi) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<?pi unknown?>\n"
+ "<doc>"
+ "Hello, world"
+ "</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_pi_2) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>"
+ "Hello, world"
+ "<?pi unknown?>\n"
+ "</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_pi_3) {
+ const char *text
+ = "<?"
+ /* 64 characters per line */
+ "This processing instruction should be long enough to ensure that"
+ "it triggers the growth of an internal string pool when the "
+ "allocator fails at a cruicial moment FGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "Q?><doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_comment) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!-- Test parsing this comment -->"
+ "<doc>Hi</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_comment_2) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>"
+ "Hello, world"
+ "<!-- Parse this comment too -->"
+ "</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+/* Test that external parser creation running out of memory is
+ * correctly reported. Based on the external entity test cases.
+ */
+START_TEST(test_alloc_create_external_parser) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, foo_text);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_duff_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR) {
+ fail("External parser allocator returned success incorrectly");
+ }
+}
+END_TEST
+
+/* More external parser memory allocation testing */
+START_TEST(test_alloc_run_external_parser) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
+ unsigned int i;
+ const unsigned int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, foo_text);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Parsing failed with allocation count 10");
+}
+END_TEST
+
+/* Test that running out of memory in dtdCopy is correctly reported.
+ * Based on test_default_ns_from_ext_subset_and_ext_ge()
+ */
+START_TEST(test_alloc_dtd_copy_default_atts) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/ns1'>\n"
+ "&en;\n"
+ "</doc>";
+ int callno = 0;
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler);
+ XML_SetUserData(g_parser, &callno);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test more external entity allocation failure paths */
+START_TEST(test_alloc_external_entity) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/ns1'>\n"
+ "&en;\n"
+ "</doc>";
+ int i;
+ const int alloc_test_max_repeats = 50;
+ int callno = 0;
+
+ for (i = 0; i < alloc_test_max_repeats; i++) {
+ g_allocation_count = -1;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler_2);
+ callno = 0;
+ XML_SetUserData(g_parser, &callno);
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ g_allocation_count = -1;
+ if (i == 0)
+ fail("External entity parsed despite duff allocator");
+ if (i == alloc_test_max_repeats)
+ fail("External entity not parsed at max allocation count");
+}
+END_TEST
+
+/* Test more allocation failure paths */
+START_TEST(test_alloc_ext_entity_set_encoding) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int i;
+ const int max_allocation_count = 30;
+
+ for (i = 0; i < max_allocation_count; i++) {
+ XML_SetExternalEntityRefHandler(g_parser,
+ external_entity_alloc_set_encoding);
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ break;
+ g_allocation_count = -1;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Encoding check succeeded despite failing allocator");
+ if (i == max_allocation_count)
+ fail("Encoding failed at max allocation count");
+}
+END_TEST
+
+/* Test the effects of allocation failure in internal entities.
+ * Based on test_unknown_encoding_internal_entity
+ */
+START_TEST(test_alloc_internal_entity) {
+ const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
+ "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
+ "<test a='&foo;'/>";
+ unsigned int i;
+ const unsigned int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUnknownEncodingHandler(g_parser, unknown_released_encoding_handler,
+ NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Internal entity worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Internal entity failed at max allocation count");
+}
+END_TEST
+
+/* Test the robustness against allocation failure of element handling
+ * Based on test_dtd_default_handling().
+ */
+START_TEST(test_alloc_dtd_default_handling) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
+ "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
+ "<!ENTITY e1 SYSTEM 'http://example.org/e' NDATA n>\n"
+ "<!ELEMENT doc (#PCDATA)>\n"
+ "<!ATTLIST doc a CDATA #IMPLIED>\n"
+ "<?pi in dtd?>\n"
+ "<!--comment in dtd-->\n"
+ "]>\n"
+ "<doc><![CDATA[text in doc]]></doc>";
+ const XML_Char *expected = XCS("\n\n\n\n\n\n\n\n\n<doc>text in doc</doc>");
+ CharData storage;
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ init_dummy_handlers();
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
+ dummy_end_doctype_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ XML_SetCdataSectionHandler(g_parser, dummy_start_cdata_handler,
+ dummy_end_cdata_handler);
+ XML_SetUnparsedEntityDeclHandler(g_parser,
+ dummy_unparsed_entity_decl_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Default DTD parsed despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Default DTD not parsed with maximum alloc count");
+ CharData_CheckXMLChars(&storage, expected);
+ if (get_dummy_handler_flags()
+ != (DUMMY_START_DOCTYPE_HANDLER_FLAG | DUMMY_END_DOCTYPE_HANDLER_FLAG
+ | DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG
+ | DUMMY_ELEMENT_DECL_HANDLER_FLAG | DUMMY_ATTLIST_DECL_HANDLER_FLAG
+ | DUMMY_COMMENT_HANDLER_FLAG | DUMMY_PI_HANDLER_FLAG
+ | DUMMY_START_CDATA_HANDLER_FLAG | DUMMY_END_CDATA_HANDLER_FLAG
+ | DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG))
+ fail("Not all handlers were called");
+}
+END_TEST
+
+/* Test robustness of XML_SetEncoding() with a failing allocator */
+START_TEST(test_alloc_explicit_encoding) {
+ int i;
+ const int max_alloc_count = 5;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (XML_SetEncoding(g_parser, XCS("us-ascii")) == XML_STATUS_OK)
+ break;
+ }
+ if (i == 0)
+ fail("Encoding set despite failing allocator");
+ else if (i == max_alloc_count)
+ fail("Encoding not set at max allocation count");
+}
+END_TEST
+
+/* Test robustness of XML_SetBase against a failing allocator */
+START_TEST(test_alloc_set_base) {
+ const XML_Char *new_base = XCS("/local/file/name.xml");
+ int i;
+ const int max_alloc_count = 5;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (XML_SetBase(g_parser, new_base) == XML_STATUS_OK)
+ break;
+ }
+ if (i == 0)
+ fail("Base set despite failing allocator");
+ else if (i == max_alloc_count)
+ fail("Base not set with max allocation count");
+}
+END_TEST
+
+/* Test buffer extension in the face of a duff reallocator */
+START_TEST(test_alloc_realloc_buffer) {
+ const char *text = get_buffer_test_text;
+ void *buffer;
+ int i;
+ const int max_realloc_count = 10;
+
+ /* Get a smallish buffer */
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ buffer = XML_GetBuffer(g_parser, 1536);
+ if (buffer == NULL)
+ fail("1.5K buffer reallocation failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_OK)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ g_reallocation_count = -1;
+ if (i == 0)
+ fail("Parse succeeded with no reallocation");
+ else if (i == max_realloc_count)
+ fail("Parse failed with max reallocation count");
+}
+END_TEST
+
+/* Same test for external entity parsers */
+START_TEST(test_alloc_ext_entity_realloc_buffer) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_reallocator);
+ XML_SetUserData(g_parser, &i);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Succeeded with no reallocations");
+ if (i == max_realloc_count)
+ fail("Failed with max reallocations");
+}
+END_TEST
+
+/* Test elements with many attributes are handled correctly */
+START_TEST(test_alloc_realloc_many_attributes) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ATTLIST doc za CDATA 'default'>\n"
+ "<!ATTLIST doc zb CDATA 'def2'>\n"
+ "<!ATTLIST doc zc CDATA 'def3'>\n"
+ "]>\n"
+ "<doc a='1'"
+ " b='2'"
+ " c='3'"
+ " d='4'"
+ " e='5'"
+ " f='6'"
+ " g='7'"
+ " h='8'"
+ " i='9'"
+ " j='10'"
+ " k='11'"
+ " l='12'"
+ " m='13'"
+ " n='14'"
+ " p='15'"
+ " q='16'"
+ " r='17'"
+ " s='18'>"
+ "</doc>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite no reallocations");
+ if (i == max_realloc_count)
+ fail("Parse failed at max reallocations");
+}
+END_TEST
+
+/* Test handling of a public entity with failing allocator */
+START_TEST(test_alloc_public_entity_value) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc></doc>\n";
+ char dtd_text[]
+ = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 PUBLIC 'foo' 'bar.ent'>\n"
+ "<!ENTITY % "
+ /* Each line is 64 characters */
+ "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " '%e1;'>\n"
+ "%e1;\n";
+ int i;
+ const int max_alloc_count = 50;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ init_dummy_handlers();
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
+ /* Provoke a particular code path */
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocation");
+ if (i == max_alloc_count)
+ fail("Parsing failed at max allocation count");
+ if (get_dummy_handler_flags() != DUMMY_ENTITY_DECL_HANDLER_FLAG)
+ fail("Entity declaration handler not called");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_subst_public_entity_value) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc></doc>\n";
+ char dtd_text[]
+ = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % "
+ /* Each line is 64 characters */
+ "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " PUBLIC 'foo' 'bar.ent'>\n"
+ "%ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP;";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocation");
+ if (i == max_realloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_public_doctype) {
+ const char *text
+ = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!DOCTYPE doc PUBLIC '"
+ /* 64 characters per line */
+ "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "' 'test'>\n"
+ "<doc></doc>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ init_dummy_handlers();
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
+ dummy_end_doctype_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (get_dummy_handler_flags()
+ != (DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG
+ | DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG))
+ fail("Doctype handler functions not called");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_public_doctype_long_name) {
+ const char *text
+ = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!DOCTYPE doc PUBLIC 'http://example.com/foo' '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "'>\n"
+ "<doc></doc>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
+ dummy_end_doctype_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test foreign DTD handling */
+START_TEST(test_alloc_set_foreign_dtd) {
+ const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+ char text2[] = "<!ELEMENT doc (#PCDATA)*>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &text2);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test based on ibm/valid/P32/ibm32v04.xml */
+START_TEST(test_alloc_attribute_enum_value) {
+ const char *text = "<?xml version='1.0' standalone='no'?>\n"
+ "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
+ "<animal>This is a \n <a/> \n\nyellow tiger</animal>";
+ char dtd_text[] = "<!ELEMENT animal (#PCDATA|a)*>\n"
+ "<!ELEMENT a EMPTY>\n"
+ "<!ATTLIST animal xml:space (default|preserve) 'preserve'>";
+ int i;
+ const int max_alloc_count = 30;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ /* An attribute list handler provokes a different code path */
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test attribute enums sufficient to overflow the string pool */
+START_TEST(test_alloc_realloc_attribute_enum_value) {
+ const char *text = "<?xml version='1.0' standalone='no'?>\n"
+ "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
+ "<animal>This is a yellow tiger</animal>";
+ /* We wish to define a collection of attribute enums that will
+ * cause the string pool storing them to have to expand. This
+ * means more than 1024 bytes, including the parentheses and
+ * separator bars.
+ */
+ char dtd_text[]
+ = "<!ELEMENT animal (#PCDATA)*>\n"
+ "<!ATTLIST animal thing "
+ "(default"
+ /* Each line is 64 characters */
+ "|ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO)"
+ " 'default'>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ /* An attribute list handler provokes a different code path */
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+/* Test attribute enums in a #IMPLIED attribute forcing pool growth */
+START_TEST(test_alloc_realloc_implied_attribute) {
+ /* Forcing this particular code path is a balancing act. The
+ * addition of the closing parenthesis and terminal NUL must be
+ * what pushes the string of enums over the 1024-byte limit,
+ * otherwise a different code path will pick up the realloc.
+ */
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "<!ATTLIST doc a "
+ /* Each line is 64 characters */
+ "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
+ " #IMPLIED>\n"
+ "]><doc/>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+/* Test attribute enums in a defaulted attribute forcing pool growth */
+START_TEST(test_alloc_realloc_default_attribute) {
+ /* Forcing this particular code path is a balancing act. The
+ * addition of the closing parenthesis and terminal NUL must be
+ * what pushes the string of enums over the 1024-byte limit,
+ * otherwise a different code path will pick up the realloc.
+ */
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "<!ATTLIST doc a "
+ /* Each line is 64 characters */
+ "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
+ " 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO'"
+ ">\n]><doc/>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+/* Test long notation name with dodgy allocator */
+START_TEST(test_alloc_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!NOTATION "
+ /* Each line is 64 characters */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " SYSTEM 'http://example.org/n'>\n"
+ "<!ENTITY e SYSTEM 'http://example.org/e' NDATA "
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ">\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ init_dummy_handlers();
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (get_dummy_handler_flags()
+ != (DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG))
+ fail("Entity declaration handler not called");
+}
+END_TEST
+
+/* Test public notation with dodgy allocator */
+START_TEST(test_alloc_public_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!NOTATION note PUBLIC '"
+ /* 64 characters per line */
+ "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "' 'foo'>\n"
+ "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ init_dummy_handlers();
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (get_dummy_handler_flags() != DUMMY_NOTATION_DECL_HANDLER_FLAG)
+ fail("Notation handler not called");
+}
+END_TEST
+
+/* Test public notation with dodgy allocator */
+START_TEST(test_alloc_system_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!NOTATION note SYSTEM '"
+ /* 64 characters per line */
+ "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "'>\n"
+ "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ init_dummy_handlers();
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (get_dummy_handler_flags() != DUMMY_NOTATION_DECL_HANDLER_FLAG)
+ fail("Notation handler not called");
+}
+END_TEST
+
+START_TEST(test_alloc_nested_groups) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc "
+ /* Sixteen elements per line */
+ "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
+ "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
+ "))))))))))))))))))))))))))))))))>\n"
+ "<!ELEMENT e EMPTY>"
+ "]>\n"
+ "<doc><e/></doc>";
+ CharData storage;
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ CharData_Init(&storage);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum reallocation count");
+ CharData_CheckXMLChars(&storage, XCS("doce"));
+ if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler not fired");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_nested_groups) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc "
+ /* Sixteen elements per line */
+ "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
+ "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
+ "))))))))))))))))))))))))))))))))>\n"
+ "<!ELEMENT e EMPTY>"
+ "]>\n"
+ "<doc><e/></doc>";
+ CharData storage;
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ CharData_Init(&storage);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+ CharData_CheckXMLChars(&storage, XCS("doce"));
+ if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler not fired");
+}
+END_TEST
+
+START_TEST(test_alloc_large_group) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc ("
+ "a1|a2|a3|a4|a5|a6|a7|a8|"
+ "b1|b2|b3|b4|b5|b6|b7|b8|"
+ "c1|c2|c3|c4|c5|c6|c7|c8|"
+ "d1|d2|d3|d4|d5|d6|d7|d8|"
+ "e1"
+ ")+>\n"
+ "]>\n"
+ "<doc>\n"
+ "<a1/>\n"
+ "</doc>\n";
+ int i;
+ const int max_alloc_count = 50;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler flag not raised");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_group_choice) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc ("
+ "a1|a2|a3|a4|a5|a6|a7|a8|"
+ "b1|b2|b3|b4|b5|b6|b7|b8|"
+ "c1|c2|c3|c4|c5|c6|c7|c8|"
+ "d1|d2|d3|d4|d5|d6|d7|d8|"
+ "e1"
+ ")+>\n"
+ "]>\n"
+ "<doc>\n"
+ "<a1/>\n"
+ "<b2 attr='foo'>This is a foo</b2>\n"
+ "<c3></c3>\n"
+ "</doc>\n";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+ if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler flag not raised");
+}
+END_TEST
+
+START_TEST(test_alloc_pi_in_epilog) {
+ const char *text = "<doc></doc>\n"
+ "<?pi in epilog?>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse completed despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (get_dummy_handler_flags() != DUMMY_PI_HANDLER_FLAG)
+ fail("Processing instruction handler not invoked");
+}
+END_TEST
+
+START_TEST(test_alloc_comment_in_epilog) {
+ const char *text = "<doc></doc>\n"
+ "<!-- comment in epilog -->";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse completed despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (get_dummy_handler_flags() != DUMMY_COMMENT_HANDLER_FLAG)
+ fail("Processing instruction handler not invoked");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_long_attribute_value) {
+ const char *text
+ = "<!DOCTYPE doc [<!ENTITY foo '"
+ /* Each line is 64 characters */
+ "This entity will be substituted as an attribute value, and is "
+ "calculated to be exactly long enough that the terminating NUL "
+ "that the library adds internally will trigger the string pool to"
+ "grow. GHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>]>\n"
+ "<doc a='&foo;'></doc>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_attribute_whitespace) {
+ const char *text = "<doc a=' '></doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_attribute_predefined_entity) {
+ const char *text = "<doc a='&amp;'></doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test that a character reference at the end of a suitably long
+ * default value for an attribute can trigger pool growth, and recovers
+ * if the allocator fails on it.
+ */
+START_TEST(test_alloc_long_attr_default_with_char_ref) {
+ const char *text
+ = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHI"
+ "&#x31;'>]>\n"
+ "<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test that a long character reference substitution triggers a pool
+ * expansion correctly for an attribute value.
+ */
+START_TEST(test_alloc_long_attr_value) {
+ const char *text
+ = "<!DOCTYPE test [<!ENTITY foo '\n"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>]>\n"
+ "<test a='&foo;'/>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test that an error in a nested parameter entity substitution is
+ * handled correctly. It seems unlikely that the code path being
+ * exercised can be reached purely by carefully crafted XML, but an
+ * allocation error in the right place will definitely do it.
+ */
+START_TEST(test_alloc_nested_entities) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
+ "<doc />";
+ ExtFaults test_data
+ = {"<!ENTITY % pe1 '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>\n"
+ "<!ENTITY % pe2 '%pe1;'>\n"
+ "<!ENTITY % pe3 '%pe2;'>",
+ "Memory Fail not faulted", NULL, XML_ERROR_NO_MEMORY};
+
+ /* Causes an allocation error in a nested storeEntityValue() */
+ g_allocation_count = 12;
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Entity allocation failure not noted");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_param_entity_newline) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc/>";
+ char dtd_text[]
+ = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
+ /* 64 characters per line */
+ "This default value is carefully crafted so that the carriage "
+ "return right at the end of the entity string causes an internal "
+ "string pool to have to grow. This allows us to test the alloc "
+ "failure path from that point. OPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDE"
+ "\">\n'>"
+ "%pe;\n";
+ int i;
+ const int max_realloc_count = 5;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_ce_extends_pe) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc/>";
+ char dtd_text[]
+ = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
+ /* 64 characters per line */
+ "This default value is carefully crafted so that the character "
+ "entity at the end causes an internal string pool to have to "
+ "grow. This allows us to test the allocation failure path from "
+ "that point onwards. EFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFG&#x51;"
+ "\">\n'>"
+ "%pe;\n";
+ int i;
+ const int max_realloc_count = 5;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_attributes) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc\n"
+ " a1 (a|b|c) 'a'\n"
+ " a2 (foo|bar) #IMPLIED\n"
+ " a3 NMTOKEN #IMPLIED\n"
+ " a4 NMTOKENS #IMPLIED\n"
+ " a5 ID #IMPLIED\n"
+ " a6 IDREF #IMPLIED\n"
+ " a7 IDREFS #IMPLIED\n"
+ " a8 ENTITY #IMPLIED\n"
+ " a9 ENTITIES #IMPLIED\n"
+ " a10 CDATA #IMPLIED\n"
+ " >]>\n"
+ "<doc>wombat</doc>\n";
+ int i;
+ const int max_realloc_count = 5;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_doc_name) {
+ const char *text =
+ /* 64 characters per line */
+ "<LongRootElementNameThatWillCauseTheNextAllocationToExpandTheStr"
+ "ingPoolForTheDTDQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ " a='1'/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_base) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY e SYSTEM 'foo'>\n"
+ "]>\n"
+ "<doc>&e;</doc>";
+ char entity_text[] = "Hello world";
+ const XML_Char *base =
+ /* 64 characters per line */
+ /* clang-format off */
+ XCS("LongBaseURI/that/will/overflow/an/internal/buffer/and/cause/it/t")
+ XCS("o/have/to/grow/PQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/");
+ /* clang-format on */
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, entity_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (XML_SetBase(g_parser, base) == XML_STATUS_ERROR) {
+ XML_ParserReset(g_parser, NULL);
+ continue;
+ }
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_public_id) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY e PUBLIC '"
+ /* 64 characters per line */
+ "LongPublicIDThatShouldResultInAnInternalStringPoolGrowingAtASpec"
+ "ificMomentKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "' 'bar'>\n"
+ "]>\n"
+ "<doc>&e;</doc>";
+ char entity_text[] = "Hello world";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, entity_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_entity_value) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY e1 '"
+ /* 64 characters per line */
+ "Long entity value that should provoke a string pool to grow whil"
+ "e setting up to parse the external entity below. xyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "'>\n"
+ " <!ENTITY e2 SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc>&e2;</doc>";
+ char entity_text[] = "Hello world";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, entity_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!NOTATION note SYSTEM '"
+ /* 64 characters per line */
+ "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
+ "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "'>\n"
+ " <!ENTITY e1 SYSTEM 'foo' NDATA "
+ /* 64 characters per line */
+ "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
+ "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ ">\n"
+ " <!ENTITY e2 SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc>&e2;</doc>";
+ ExtOption options[]
+ = {{XCS("foo"), "Entity Foo"}, {XCS("bar"), "Entity Bar"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) {
+ const char *const text = "<!DOCTYPE doc SYSTEM 'foo'><doc/>";
+
+ XML_SetExternalEntityRefHandler(
+ g_parser, external_entity_parser_create_alloc_fail_handler);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Call to parse was expected to fail");
+
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
+ fail("Call to parse was expected to fail from the external entity handler");
+
+ XML_ParserReset(g_parser, NULL);
+}
+END_TEST
+
+void
+make_alloc_test_case(Suite *s) {
+ TCase *tc_alloc = tcase_create("allocation tests");
+
+ suite_add_tcase(s, tc_alloc);
+ tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
+
+ tcase_add_test(tc_alloc, test_alloc_parse_xdecl);
+ tcase_add_test(tc_alloc, test_alloc_parse_xdecl_2);
+ tcase_add_test(tc_alloc, test_alloc_parse_pi);
+ tcase_add_test(tc_alloc, test_alloc_parse_pi_2);
+ tcase_add_test(tc_alloc, test_alloc_parse_pi_3);
+ tcase_add_test(tc_alloc, test_alloc_parse_comment);
+ tcase_add_test(tc_alloc, test_alloc_parse_comment_2);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_create_external_parser);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_run_external_parser);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_copy_default_atts);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_external_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_ext_entity_set_encoding);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_internal_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_default_handling);
+ tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
+ tcase_add_test(tc_alloc, test_alloc_set_base);
+ tcase_add_test(tc_alloc, test_alloc_realloc_buffer);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_ext_entity_realloc_buffer);
+ tcase_add_test(tc_alloc, test_alloc_realloc_many_attributes);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_public_entity_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_subst_public_entity_value);
+ tcase_add_test(tc_alloc, test_alloc_parse_public_doctype);
+ tcase_add_test(tc_alloc, test_alloc_parse_public_doctype_long_name);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_set_foreign_dtd);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_attribute_enum_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_attribute_enum_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_implied_attribute);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_default_attribute);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_notation);
+ tcase_add_test(tc_alloc, test_alloc_public_notation);
+ tcase_add_test(tc_alloc, test_alloc_system_notation);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_groups);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_nested_groups);
+ tcase_add_test(tc_alloc, test_alloc_large_group);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_group_choice);
+ tcase_add_test(tc_alloc, test_alloc_pi_in_epilog);
+ tcase_add_test(tc_alloc, test_alloc_comment_in_epilog);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_long_attribute_value);
+ tcase_add_test(tc_alloc, test_alloc_attribute_whitespace);
+ tcase_add_test(tc_alloc, test_alloc_attribute_predefined_entity);
+ tcase_add_test(tc_alloc, test_alloc_long_attr_default_with_char_ref);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_attr_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_entities);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_param_entity_newline);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_ce_extends_pe);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_attributes);
+ tcase_add_test(tc_alloc, test_alloc_long_doc_name);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_base);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_public_id);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_entity_value);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_notation);
+
+ tcase_add_test__ifdef_xml_dtd(
+ tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail);
+}
diff --git a/contrib/expat/tests/alloc_tests.h b/contrib/expat/tests/alloc_tests.h
new file mode 100644
index 000000000000..1eae130be78f
--- /dev/null
+++ b/contrib/expat/tests/alloc_tests.h
@@ -0,0 +1,56 @@
+/* Tests in the "allocation" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_ALLOC_TESTS_H
+# define XML_ALLOC_TESTS_H
+
+extern void make_alloc_test_case(Suite *s);
+
+#endif /* XML_ALLOC_TESTS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/alloc_tests_cxx.cpp b/contrib/expat/tests/alloc_tests_cxx.cpp
new file mode 100644
index 000000000000..3270b1a6c984
--- /dev/null
+++ b/contrib/expat/tests/alloc_tests_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "alloc_tests.c"
diff --git a/contrib/expat/tests/basic_tests.c b/contrib/expat/tests/basic_tests.c
new file mode 100644
index 000000000000..7112a4401879
--- /dev/null
+++ b/contrib/expat/tests/basic_tests.c
@@ -0,0 +1,6076 @@
+/* Tests in the "basic" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
+#endif
+
+#include <assert.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#if ! defined(__cplusplus)
+# include <stdbool.h>
+#endif
+
+#include "expat_config.h"
+
+#include "expat.h"
+#include "internal.h"
+#include "minicheck.h"
+#include "structdata.h"
+#include "common.h"
+#include "dummy.h"
+#include "handlers.h"
+#include "siphash.h"
+#include "basic_tests.h"
+
+static void
+basic_setup(void) {
+ g_parser = XML_ParserCreate(NULL);
+ if (g_parser == NULL)
+ fail("Parser not created.");
+}
+
+/*
+ * Character & encoding tests.
+ */
+
+START_TEST(test_nul_byte) {
+ char text[] = "<doc>\0</doc>";
+
+ /* test that a NUL byte (in US-ASCII data) is an error */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Parser did not report error on NUL-byte.");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_u0000_char) {
+ /* test that a NUL byte (in US-ASCII data) is an error */
+ expect_failure("<doc>&#0;</doc>", XML_ERROR_BAD_CHAR_REF,
+ "Parser did not report error on NUL-byte.");
+}
+END_TEST
+
+START_TEST(test_siphash_self) {
+ if (! sip24_valid())
+ fail("SipHash self-test failed");
+}
+END_TEST
+
+START_TEST(test_siphash_spec) {
+ /* https://131002.net/siphash/siphash.pdf (page 19, "Test values") */
+ const char message[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
+ "\x0a\x0b\x0c\x0d\x0e";
+ const size_t len = sizeof(message) - 1;
+ const uint64_t expected = SIP_ULL(0xa129ca61U, 0x49be45e5U);
+ struct siphash state;
+ struct sipkey key;
+
+ sip_tokey(&key, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
+ "\x0a\x0b\x0c\x0d\x0e\x0f");
+ sip24_init(&state, &key);
+
+ /* Cover spread across calls */
+ sip24_update(&state, message, 4);
+ sip24_update(&state, message + 4, len - 4);
+
+ /* Cover null length */
+ sip24_update(&state, message, 0);
+
+ if (sip24_final(&state) != expected)
+ fail("sip24_final failed spec test\n");
+
+ /* Cover wrapper */
+ if (siphash24(message, len, &key) != expected)
+ fail("siphash24 failed spec test\n");
+}
+END_TEST
+
+START_TEST(test_bom_utf8) {
+ /* This test is really just making sure we don't core on a UTF-8 BOM. */
+ const char *text = "\357\273\277<e/>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_bom_utf16_be) {
+ char text[] = "\376\377\0<\0e\0/\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_bom_utf16_le) {
+ char text[] = "\377\376<\0e\0/\0>\0";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_nobom_utf16_le) {
+ char text[] = " \0<\0e\0/\0>\0";
+
+ if (g_chunkSize == 1) {
+ // TODO: with just the first byte, we can't tell the difference between
+ // UTF-16-LE and UTF-8. Avoid the failure for now.
+ return;
+ }
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_hash_collision) {
+ /* For full coverage of the lookup routine, we need to ensure a
+ * hash collision even though we can only tell that we have one
+ * through breakpoint debugging or coverage statistics. The
+ * following will cause a hash collision on machines with a 64-bit
+ * long type; others will have to experiment. The full coverage
+ * tests invoked from qa.sh usually provide a hash collision, but
+ * not always. This is an attempt to provide insurance.
+ */
+#define COLLIDING_HASH_SALT (unsigned long)SIP_ULL(0xffffffffU, 0xff99fc90U)
+ const char *text
+ = "<doc>\n"
+ "<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n"
+ "<b1></b1><b2 attr='foo'>This is a foo</b2><b3></b3><b4></b4>\n"
+ "<b5></b5><b6></b6><b7></b7><b8></b8>\n"
+ "<c1/><c2/><c3/><c4/><c5/><c6/><c7/><c8/>\n"
+ "<d1/><d2/><d3/><d4/><d5/><d6/><d7/>\n"
+ "<d8>This triggers the table growth and collides with b2</d8>\n"
+ "</doc>\n";
+
+ XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+#undef COLLIDING_HASH_SALT
+
+/* Regression test for SF bug #491986. */
+START_TEST(test_danish_latin1) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
+#ifdef XML_UNICODE
+ const XML_Char *expected
+ = XCS("J\x00f8rgen \x00e6\x00f8\x00e5\x00c6\x00d8\x00c5");
+#else
+ const XML_Char *expected
+ = XCS("J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
+#endif
+ run_character_check(text, expected);
+}
+END_TEST
+
+/* Regression test for SF bug #514281. */
+START_TEST(test_french_charref_hexidecimal) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
+#else
+ const XML_Char *expected
+ = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+#endif
+ run_character_check(text, expected);
+}
+END_TEST
+
+START_TEST(test_french_charref_decimal) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
+#else
+ const XML_Char *expected
+ = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+#endif
+ run_character_check(text, expected);
+}
+END_TEST
+
+START_TEST(test_french_latin1) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
+#else
+ const XML_Char *expected
+ = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+#endif
+ run_character_check(text, expected);
+}
+END_TEST
+
+START_TEST(test_french_utf8) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>\xC3\xA9</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9");
+#else
+ const XML_Char *expected = XCS("\xC3\xA9");
+#endif
+ run_character_check(text, expected);
+}
+END_TEST
+
+/* Regression test for SF bug #600479.
+ XXX There should be a test that exercises all legal XML Unicode
+ characters as PCDATA and attribute value content, and XML Name
+ characters as part of element and attribute names.
+*/
+START_TEST(test_utf8_false_rejection) {
+ const char *text = "<doc>\xEF\xBA\xBF</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\xfebf");
+#else
+ const XML_Char *expected = XCS("\xEF\xBA\xBF");
+#endif
+ run_character_check(text, expected);
+}
+END_TEST
+
+/* Regression test for SF bug #477667.
+ This test assures that any 8-bit character followed by a 7-bit
+ character will not be mistakenly interpreted as a valid UTF-8
+ sequence.
+*/
+START_TEST(test_illegal_utf8) {
+ char text[100];
+ int i;
+
+ for (i = 128; i <= 255; ++i) {
+ snprintf(text, sizeof(text), "<e>%ccd</e>", i);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK) {
+ snprintf(text, sizeof(text),
+ "expected token error for '%c' (ordinal %d) in UTF-8 text", i,
+ i);
+ fail(text);
+ } else if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+ /* Reset the parser since we use the same parser repeatedly. */
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Examples, not masks: */
+#define UTF8_LEAD_1 "\x7f" /* 0b01111111 */
+#define UTF8_LEAD_2 "\xdf" /* 0b11011111 */
+#define UTF8_LEAD_3 "\xef" /* 0b11101111 */
+#define UTF8_LEAD_4 "\xf7" /* 0b11110111 */
+#define UTF8_FOLLOW "\xbf" /* 0b10111111 */
+
+START_TEST(test_utf8_auto_align) {
+ struct TestCase {
+ ptrdiff_t expectedMovementInChars;
+ const char *input;
+ };
+
+ struct TestCase cases[] = {
+ {00, ""},
+
+ {00, UTF8_LEAD_1},
+
+ {-1, UTF8_LEAD_2},
+ {00, UTF8_LEAD_2 UTF8_FOLLOW},
+
+ {-1, UTF8_LEAD_3},
+ {-2, UTF8_LEAD_3 UTF8_FOLLOW},
+ {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW},
+
+ {-1, UTF8_LEAD_4},
+ {-2, UTF8_LEAD_4 UTF8_FOLLOW},
+ {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW},
+ {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW},
+ };
+
+ size_t i = 0;
+ bool success = true;
+ for (; i < sizeof(cases) / sizeof(*cases); i++) {
+ const char *fromLim = cases[i].input + strlen(cases[i].input);
+ const char *const fromLimInitially = fromLim;
+ ptrdiff_t actualMovementInChars;
+
+ _INTERNAL_trim_to_complete_utf8_characters(cases[i].input, &fromLim);
+
+ actualMovementInChars = (fromLim - fromLimInitially);
+ if (actualMovementInChars != cases[i].expectedMovementInChars) {
+ size_t j = 0;
+ success = false;
+ printf("[-] UTF-8 case %2u: Expected movement by %2d chars"
+ ", actually moved by %2d chars: \"",
+ (unsigned)(i + 1), (int)cases[i].expectedMovementInChars,
+ (int)actualMovementInChars);
+ for (; j < strlen(cases[i].input); j++) {
+ printf("\\x%02x", (unsigned char)cases[i].input[j]);
+ }
+ printf("\"\n");
+ }
+ }
+
+ if (! success) {
+ fail("UTF-8 auto-alignment is not bullet-proof\n");
+ }
+}
+END_TEST
+
+START_TEST(test_utf16) {
+ /* <?xml version="1.0" encoding="UTF-16"?>
+ * <doc a='123'>some {A} text</doc>
+ *
+ * where {A} is U+FF21, FULLWIDTH LATIN CAPITAL LETTER A
+ */
+ char text[]
+ = "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
+ "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
+ "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
+ "\000'\000?\000>\000\n"
+ "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'\000>"
+ "\000s\000o\000m\000e\000 \xff\x21\000 \000t\000e\000x\000t\000"
+ "<\000/\000d\000o\000c\000>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("some \xff21 text");
+#else
+ const XML_Char *expected = XCS("some \357\274\241 text");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_le_epilog_newline) {
+ unsigned int first_chunk_bytes = 17;
+ char text[] = "\xFF\xFE" /* BOM */
+ "<\000e\000/\000>\000" /* document element */
+ "\r\000\n\000\r\000\n\000"; /* epilog */
+
+ if (first_chunk_bytes >= sizeof(text) - 1)
+ fail("bad value of first_chunk_bytes");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, first_chunk_bytes, XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ else {
+ enum XML_Status rc;
+ rc = _XML_Parse_SINGLE_BYTES(g_parser, text + first_chunk_bytes,
+ sizeof(text) - first_chunk_bytes - 1,
+ XML_TRUE);
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ }
+}
+END_TEST
+
+/* Test that an outright lie in the encoding is faulted */
+START_TEST(test_not_utf16) {
+ const char *text = "<?xml version='1.0' encoding='utf-16'?>"
+ "<doc>Hi</doc>";
+
+ /* Use a handler to provoke the appropriate code paths */
+ XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
+ expect_failure(text, XML_ERROR_INCORRECT_ENCODING,
+ "UTF-16 declared in UTF-8 not faulted");
+}
+END_TEST
+
+/* Test that an unknown encoding is rejected */
+START_TEST(test_bad_encoding) {
+ const char *text = "<doc>Hi</doc>";
+
+ if (! XML_SetEncoding(g_parser, XCS("unknown-encoding")))
+ fail("XML_SetEncoding failed");
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Unknown encoding not faulted");
+}
+END_TEST
+
+/* Regression test for SF bug #481609, #774028. */
+START_TEST(test_latin1_umlauts) {
+ const char *text
+ = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<e a='\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; >'\n"
+ " >\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; ></e>";
+#ifdef XML_UNICODE
+ /* Expected results in UTF-16 */
+ const XML_Char *expected = XCS("\x00e4 \x00f6 \x00fc ")
+ XCS("\x00e4 \x00f6 \x00fc ") XCS("\x00e4 \x00f6 \x00fc >");
+#else
+ /* Expected results in UTF-8 */
+ const XML_Char *expected = XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ")
+ XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC >");
+#endif
+
+ run_character_check(text, expected);
+ XML_ParserReset(g_parser, NULL);
+ run_attribute_check(text, expected);
+ /* Repeat with a default handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ run_character_check(text, expected);
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ run_attribute_check(text, expected);
+}
+END_TEST
+
+/* Test that an element name with a 4-byte UTF-8 character is rejected */
+START_TEST(test_long_utf8_character) {
+ const char *text
+ = "<?xml version='1.0' encoding='utf-8'?>\n"
+ /* 0xf0 0x90 0x80 0x80 = U+10000, the first Linear B character */
+ "<do\xf0\x90\x80\x80/>";
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "4-byte UTF-8 character in element name not faulted");
+}
+END_TEST
+
+/* Test that a long latin-1 attribute (too long to convert in one go)
+ * is correctly converted
+ */
+START_TEST(test_long_latin1_attribute) {
+ const char *text
+ = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc att='"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ /* Last character splits across a buffer boundary */
+ "\xe4'>\n</doc>";
+
+ const XML_Char *expected =
+ /* 64 characters per line */
+ /* clang-format off */
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO")
+ /* clang-format on */
+#ifdef XML_UNICODE
+ XCS("\x00e4");
+#else
+ XCS("\xc3\xa4");
+#endif
+
+ run_attribute_check(text, expected);
+}
+END_TEST
+
+/* Test that a long ASCII attribute (too long to convert in one go)
+ * is correctly converted
+ */
+START_TEST(test_long_ascii_attribute) {
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc att='"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "01234'>\n</doc>";
+ const XML_Char *expected =
+ /* 64 characters per line */
+ /* clang-format off */
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("01234");
+ /* clang-format on */
+
+ run_attribute_check(text, expected);
+}
+END_TEST
+
+/* Regression test #1 for SF bug #653180. */
+START_TEST(test_line_number_after_parse) {
+ const char *text = "<tag>\n"
+ "\n"
+ "\n</tag>";
+ XML_Size lineno;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ lineno = XML_GetCurrentLineNumber(g_parser);
+ if (lineno != 4) {
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer),
+ "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
+ fail(buffer);
+ }
+}
+END_TEST
+
+/* Regression test #2 for SF bug #653180. */
+START_TEST(test_column_number_after_parse) {
+ const char *text = "<tag></tag>";
+ XML_Size colno;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ colno = XML_GetCurrentColumnNumber(g_parser);
+ if (colno != 11) {
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer),
+ "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
+ fail(buffer);
+ }
+}
+END_TEST
+
+/* Regression test #3 for SF bug #653180. */
+START_TEST(test_line_and_column_numbers_inside_handlers) {
+ const char *text = "<a>\n" /* Unix end-of-line */
+ " <b>\r\n" /* Windows end-of-line */
+ " <c/>\r" /* Mac OS end-of-line */
+ " </b>\n"
+ " <d>\n"
+ " <f/>\n"
+ " </d>\n"
+ "</a>";
+ const StructDataEntry expected[]
+ = {{XCS("a"), 0, 1, STRUCT_START_TAG}, {XCS("b"), 2, 2, STRUCT_START_TAG},
+ {XCS("c"), 4, 3, STRUCT_START_TAG}, {XCS("c"), 8, 3, STRUCT_END_TAG},
+ {XCS("b"), 2, 4, STRUCT_END_TAG}, {XCS("d"), 2, 5, STRUCT_START_TAG},
+ {XCS("f"), 4, 6, STRUCT_START_TAG}, {XCS("f"), 8, 6, STRUCT_END_TAG},
+ {XCS("d"), 2, 7, STRUCT_END_TAG}, {XCS("a"), 0, 8, STRUCT_END_TAG}};
+ const int expected_count = sizeof(expected) / sizeof(StructDataEntry);
+ StructData storage;
+
+ StructData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, start_element_event_handler2);
+ XML_SetEndElementHandler(g_parser, end_element_event_handler2);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ StructData_CheckItems(&storage, expected, expected_count);
+ StructData_Dispose(&storage);
+}
+END_TEST
+
+/* Regression test #4 for SF bug #653180. */
+START_TEST(test_line_number_after_error) {
+ const char *text = "<a>\n"
+ " <b>\n"
+ " </a>"; /* missing </b> */
+ XML_Size lineno;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Expected a parse error");
+
+ lineno = XML_GetCurrentLineNumber(g_parser);
+ if (lineno != 3) {
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer),
+ "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
+ fail(buffer);
+ }
+}
+END_TEST
+
+/* Regression test #5 for SF bug #653180. */
+START_TEST(test_column_number_after_error) {
+ const char *text = "<a>\n"
+ " <b>\n"
+ " </a>"; /* missing </b> */
+ XML_Size colno;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Expected a parse error");
+
+ colno = XML_GetCurrentColumnNumber(g_parser);
+ if (colno != 4) {
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer),
+ "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
+ fail(buffer);
+ }
+}
+END_TEST
+
+/* Regression test for SF bug #478332. */
+START_TEST(test_really_long_lines) {
+ /* This parses an input line longer than INIT_DATA_BUF_SIZE
+ characters long (defined to be 1024 in xmlparse.c). We take a
+ really cheesy approach to building the input buffer, because
+ this avoids writing bugs in buffer-filling code.
+ */
+ const char *text
+ = "<e>"
+ /* 64 chars */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ /* until we have at least 1024 characters on the line: */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "</e>";
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test cdata processing across a buffer boundary */
+START_TEST(test_really_long_encoded_lines) {
+ /* As above, except that we want to provoke an output buffer
+ * overflow with a non-trivial encoding. For this we need to pass
+ * the whole cdata in one go, not byte-by-byte.
+ */
+ void *buffer;
+ const char *text
+ = "<?xml version='1.0' encoding='iso-8859-1'?>"
+ "<e>"
+ /* 64 chars */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ /* until we have at least 1024 characters on the line: */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "</e>";
+ int parse_len = (int)strlen(text);
+
+ /* Need a cdata handler to provoke the code path we want to test */
+ XML_SetCharacterDataHandler(g_parser, dummy_cdata_handler);
+ buffer = XML_GetBuffer(g_parser, parse_len);
+ if (buffer == NULL)
+ fail("Could not allocate parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, text, parse_len);
+ if (XML_ParseBuffer(g_parser, parse_len, XML_TRUE) == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/*
+ * Element event tests.
+ */
+
+START_TEST(test_end_element_events) {
+ const char *text = "<a><b><c/></b><d><f/></d></a>";
+ const XML_Char *expected = XCS("/c/b/f/d/a");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetEndElementHandler(g_parser, end_element_event_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/*
+ * Attribute tests.
+ */
+
+/* Helper used by the following tests; this checks any "attr" and "refs"
+ attributes to make sure whitespace has been normalized.
+
+ Return true if whitespace has been normalized in a string, using
+ the rules for attribute value normalization. The 'is_cdata' flag
+ is needed since CDATA attributes don't need to have multiple
+ whitespace characters collapsed to a single space, while other
+ attribute data types do. (Section 3.3.3 of the recommendation.)
+*/
+static int
+is_whitespace_normalized(const XML_Char *s, int is_cdata) {
+ int blanks = 0;
+ int at_start = 1;
+ while (*s) {
+ if (*s == XCS(' '))
+ ++blanks;
+ else if (*s == XCS('\t') || *s == XCS('\n') || *s == XCS('\r'))
+ return 0;
+ else {
+ if (at_start) {
+ at_start = 0;
+ if (blanks && ! is_cdata)
+ /* illegal leading blanks */
+ return 0;
+ } else if (blanks > 1 && ! is_cdata)
+ return 0;
+ blanks = 0;
+ }
+ ++s;
+ }
+ if (blanks && ! is_cdata)
+ return 0;
+ return 1;
+}
+
+/* Check the attribute whitespace checker: */
+START_TEST(test_helper_is_whitespace_normalized) {
+ assert(is_whitespace_normalized(XCS("abc"), 0));
+ assert(is_whitespace_normalized(XCS("abc"), 1));
+ assert(is_whitespace_normalized(XCS("abc def ghi"), 0));
+ assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
+ assert(! is_whitespace_normalized(XCS(" abc def ghi"), 0));
+ assert(is_whitespace_normalized(XCS(" abc def ghi"), 1));
+ assert(! is_whitespace_normalized(XCS("abc def ghi"), 0));
+ assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
+ assert(! is_whitespace_normalized(XCS("abc def ghi "), 0));
+ assert(is_whitespace_normalized(XCS("abc def ghi "), 1));
+ assert(! is_whitespace_normalized(XCS(" "), 0));
+ assert(is_whitespace_normalized(XCS(" "), 1));
+ assert(! is_whitespace_normalized(XCS("\t"), 0));
+ assert(! is_whitespace_normalized(XCS("\t"), 1));
+ assert(! is_whitespace_normalized(XCS("\n"), 0));
+ assert(! is_whitespace_normalized(XCS("\n"), 1));
+ assert(! is_whitespace_normalized(XCS("\r"), 0));
+ assert(! is_whitespace_normalized(XCS("\r"), 1));
+ assert(! is_whitespace_normalized(XCS("abc\t def"), 1));
+}
+END_TEST
+
+static void XMLCALL
+check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ int i;
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ for (i = 0; atts[i] != NULL; i += 2) {
+ const XML_Char *attrname = atts[i];
+ const XML_Char *value = atts[i + 1];
+ if (xcstrcmp(XCS("attr"), attrname) == 0
+ || xcstrcmp(XCS("ents"), attrname) == 0
+ || xcstrcmp(XCS("refs"), attrname) == 0) {
+ if (! is_whitespace_normalized(value, 0)) {
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer),
+ "attribute value not normalized: %" XML_FMT_STR
+ "='%" XML_FMT_STR "'",
+ attrname, value);
+ fail(buffer);
+ }
+ }
+ }
+}
+
+START_TEST(test_attr_whitespace_normalization) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc\n"
+ " attr NMTOKENS #REQUIRED\n"
+ " ents ENTITIES #REQUIRED\n"
+ " refs IDREFS #REQUIRED>\n"
+ "]>\n"
+ "<doc attr=' a b c\t\td\te\t' refs=' id-1 \t id-2\t\t' \n"
+ " ents=' ent-1 \t\r\n"
+ " ent-2 ' >\n"
+ " <e id='id-1'/>\n"
+ " <e id='id-2'/>\n"
+ "</doc>";
+
+ XML_SetStartElementHandler(g_parser,
+ check_attr_contains_normalized_whitespace);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/*
+ * XML declaration tests.
+ */
+
+START_TEST(test_xmldecl_misplaced) {
+ expect_failure("\n"
+ "<?xml version='1.0'?>\n"
+ "<a/>",
+ XML_ERROR_MISPLACED_XML_PI,
+ "failed to report misplaced XML declaration");
+}
+END_TEST
+
+START_TEST(test_xmldecl_invalid) {
+ expect_failure("<?xml version='1.0' \xc3\xa7?>\n<doc/>", XML_ERROR_XML_DECL,
+ "Failed to report invalid XML declaration");
+}
+END_TEST
+
+START_TEST(test_xmldecl_missing_attr) {
+ expect_failure("<?xml ='1.0'?>\n<doc/>\n", XML_ERROR_XML_DECL,
+ "Failed to report missing XML declaration attribute");
+}
+END_TEST
+
+START_TEST(test_xmldecl_missing_value) {
+ expect_failure("<?xml version='1.0' encoding='us-ascii' standalone?>\n"
+ "<doc/>",
+ XML_ERROR_XML_DECL,
+ "Failed to report missing attribute value");
+}
+END_TEST
+
+/* Regression test for SF bug #584832. */
+START_TEST(test_unknown_encoding_internal_entity) {
+ const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
+ "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
+ "<test a='&foo;'/>";
+
+ XML_SetUnknownEncodingHandler(g_parser, UnknownEncodingHandler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test unrecognised encoding handler */
+START_TEST(test_unrecognised_encoding_internal_entity) {
+ const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
+ "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
+ "<test a='&foo;'/>";
+
+ XML_SetUnknownEncodingHandler(g_parser, UnrecognisedEncodingHandler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Unrecognised encoding not rejected");
+}
+END_TEST
+
+/* Regression test for SF bug #620106. */
+START_TEST(test_ext_entity_set_encoding) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest test_data
+ = {/* This text says it's an unsupported encoding, but it's really
+ UTF-8, which we tell Expat using XML_SetEncoding().
+ */
+ "<?xml encoding='iso-8859-3'?>\xC3\xA9", XCS("utf-8"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9");
+#else
+ const XML_Char *expected = XCS("\xc3\xa9");
+#endif
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ run_ext_character_check(text, &test_data, expected);
+}
+END_TEST
+
+/* Test external entities with no handler */
+START_TEST(test_ext_entity_no_handler) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ run_character_check(text, XCS(""));
+}
+END_TEST
+
+/* Test UTF-8 BOM is accepted */
+START_TEST(test_ext_entity_set_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest test_data = {"\xEF\xBB\xBF" /* BOM */
+ "<?xml encoding='iso-8859-3'?>"
+ "\xC3\xA9",
+ XCS("utf-8"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9");
+#else
+ const XML_Char *expected = XCS("\xc3\xa9");
+#endif
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ run_ext_character_check(text, &test_data, expected);
+}
+END_TEST
+
+/* Test that bad encodings are faulted */
+START_TEST(test_ext_entity_bad_encoding) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtFaults fault
+ = {"<?xml encoding='iso-8859-3'?>u", "Unsupported encoding not faulted",
+ XCS("unknown"), XML_ERROR_UNKNOWN_ENCODING};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad encoding should not have been accepted");
+}
+END_TEST
+
+/* Try handing an invalid encoding to an external entity parser */
+START_TEST(test_ext_entity_bad_encoding_2) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtFaults fault
+ = {"<!ELEMENT doc (#PCDATA)*>", "Unknown encoding not faulted",
+ XCS("unknown-encoding"), XML_ERROR_UNKNOWN_ENCODING};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad encoding not faulted in external entity handler");
+}
+END_TEST
+
+/* Test that no error is reported for unknown entities if we don't
+ read an external subset. This was fixed in Expat 1.95.5.
+*/
+START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that an error is reported for unknown entities if we don't
+ have an external subset.
+*/
+START_TEST(test_wfc_undeclared_entity_no_external_subset) {
+ expect_failure("<doc>&entity;</doc>", XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity w/out a DTD.");
+}
+END_TEST
+
+/* Test that an error is reported for unknown entities if we don't
+ read an external subset, but have been declared standalone.
+*/
+START_TEST(test_wfc_undeclared_entity_standalone) {
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity (standalone).");
+}
+END_TEST
+
+/* Test that an error is reported for unknown entities if we have read
+ an external subset, and standalone is true.
+*/
+START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity (external DTD).");
+}
+END_TEST
+
+/* Test that external entity handling is not done if the parsing flag
+ * is set to UNLESS_STANDALONE
+ */
+START_TEST(test_entity_with_external_subset_unless_standalone) {
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ENTITY entity 'bar'>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser,
+ XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity");
+}
+END_TEST
+
+/* Test that no error is reported for unknown entities if we have read
+ an external subset, and standalone is false.
+*/
+START_TEST(test_wfc_undeclared_entity_with_external_subset) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ run_ext_character_check(text, &test_data, XCS(""));
+}
+END_TEST
+
+/* Test that an error is reported if our NotStandalone handler fails */
+START_TEST(test_not_standalone_handler_reject) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
+ expect_failure(text, XML_ERROR_NOT_STANDALONE,
+ "NotStandalone handler failed to reject");
+
+ /* Try again but without external entity handling */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
+ expect_failure(text, XML_ERROR_NOT_STANDALONE,
+ "NotStandalone handler failed to reject");
+}
+END_TEST
+
+/* Test that no error is reported if our NotStandalone handler succeeds */
+START_TEST(test_not_standalone_handler_accept) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
+ run_ext_character_check(text, &test_data, XCS(""));
+
+ /* Repeat without the external entity handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
+ run_character_check(text, XCS(""));
+}
+END_TEST
+
+START_TEST(test_wfc_no_recursive_entity_refs) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#38;entity;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_RECURSIVE_ENTITY_REF,
+ "Parser did not report recursive entity reference.");
+}
+END_TEST
+
+/* Test incomplete external entities are faulted */
+START_TEST(test_ext_entity_invalid_parse) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ const ExtFaults faults[]
+ = {{"<", "Incomplete element declaration not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {"<\xe2\x82", /* First two bytes of a three-byte char */
+ "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
+ {"<tag>\xe2\x82", "Incomplete character in CDATA not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ const ExtFaults *fault = faults;
+
+ for (; fault->parse_text != NULL; fault++) {
+ set_subtest("\"%s\"", fault->parse_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, (void *)fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Parser did not report external entity error");
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Regression test for SF bug #483514. */
+START_TEST(test_dtd_default_handling) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
+ "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "<!ATTLIST doc a CDATA #IMPLIED>\n"
+ "<?pi in dtd?>\n"
+ "<!--comment in dtd-->\n"
+ "]><doc/>";
+
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
+ XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
+ run_character_check(text, XCS("\n\n\n\n\n\n\n<doc/>"));
+}
+END_TEST
+
+/* Test handling of attribute declarations */
+START_TEST(test_dtd_attr_handling) {
+ const char *prolog = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc EMPTY>\n";
+ AttTest attr_data[]
+ = {{"<!ATTLIST doc a ( one | two | three ) #REQUIRED>\n"
+ "]>"
+ "<doc a='two'/>",
+ XCS("doc"), XCS("a"),
+ XCS("(one|two|three)"), /* Extraneous spaces will be removed */
+ NULL, XML_TRUE},
+ {"<!NOTATION foo SYSTEM 'http://example.org/foo'>\n"
+ "<!ATTLIST doc a NOTATION (foo) #IMPLIED>\n"
+ "]>"
+ "<doc/>",
+ XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), NULL, XML_FALSE},
+ {"<!ATTLIST doc a NOTATION (foo) 'bar'>\n"
+ "]>"
+ "<doc/>",
+ XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), XCS("bar"), XML_FALSE},
+ {"<!ATTLIST doc a CDATA '\xdb\xb2'>\n"
+ "]>"
+ "<doc/>",
+ XCS("doc"), XCS("a"), XCS("CDATA"),
+#ifdef XML_UNICODE
+ XCS("\x06f2"),
+#else
+ XCS("\xdb\xb2"),
+#endif
+ XML_FALSE},
+ {NULL, NULL, NULL, NULL, NULL, XML_FALSE}};
+ AttTest *test;
+
+ for (test = attr_data; test->definition != NULL; test++) {
+ set_subtest("%s", test->definition);
+ XML_SetAttlistDeclHandler(g_parser, verify_attlist_decl_handler);
+ XML_SetUserData(g_parser, test);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)strlen(prolog),
+ XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, test->definition,
+ (int)strlen(test->definition), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* See related SF bug #673791.
+ When namespace processing is enabled, setting the namespace URI for
+ a prefix is not allowed; this test ensures that it *is* allowed
+ when namespace processing is not enabled.
+ (See Namespaces in XML, section 2.)
+*/
+START_TEST(test_empty_ns_without_namespaces) {
+ const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
+ " <e xmlns:prefix=''/>\n"
+ "</doc>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #824420.
+ Checks that an xmlns:prefix attribute set in an attribute's default
+ value isn't misinterpreted.
+*/
+START_TEST(test_ns_in_attribute_default_without_namespaces) {
+ const char *text = "<!DOCTYPE e:element [\n"
+ " <!ATTLIST e:element\n"
+ " xmlns:e CDATA 'http://example.org/'>\n"
+ " ]>\n"
+ "<e:element/>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #1515266: missing check of stopped
+ parser in doContext() 'for' loop. */
+START_TEST(test_stop_parser_between_char_data_calls) {
+ /* The sample data must be big enough that there are two calls to
+ the character data handler from within the inner "for" loop of
+ the XML_TOK_DATA_CHARS case in doContent(), and the character
+ handler must stop the parser and clear the character data
+ handler.
+ */
+ const char *text = long_character_data_text;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ g_resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #1515266: missing check of stopped
+ parser in doContext() 'for' loop. */
+START_TEST(test_suspend_parser_between_char_data_calls) {
+ /* The sample data must be big enough that there are two calls to
+ the character data handler from within the inner "for" loop of
+ the XML_TOK_DATA_CHARS case in doContent(), and the character
+ handler must stop the parser and clear the character data
+ handler.
+ */
+ const char *text = long_character_data_text;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ g_resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+ /* Try parsing directly */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Attempt to continue parse while suspended not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ fail("Suspended parse not faulted with correct error");
+}
+END_TEST
+
+/* Test repeated calls to XML_StopParser are handled correctly */
+START_TEST(test_repeated_stop_parser_between_char_data_calls) {
+ const char *text = long_character_data_text;
+
+ XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
+ g_resumable = XML_FALSE;
+ g_abortable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Failed to double-stop parser");
+
+ XML_ParserReset(g_parser, NULL);
+ XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
+ g_resumable = XML_TRUE;
+ g_abortable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ fail("Failed to double-suspend parser");
+
+ XML_ParserReset(g_parser, NULL);
+ XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
+ g_resumable = XML_TRUE;
+ g_abortable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Failed to suspend-abort parser");
+}
+END_TEST
+
+START_TEST(test_good_cdata_ascii) {
+ const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
+ const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ /* Add start and end handlers for coverage */
+ XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
+ XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+
+ /* Try again, this time with a default handler */
+ XML_ParserReset(g_parser, NULL);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_good_cdata_utf16) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[hello]]></a>
+ */
+ const char text[]
+ = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>";
+ const XML_Char *expected = XCS("hello");
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_good_cdata_utf16_le) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[hello]]></a>
+ */
+ const char text[]
+ = "<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>\0";
+ const XML_Char *expected = XCS("hello");
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test UTF16 conversion of a long cdata string */
+
+/* 16 characters: handy macro to reduce visual clutter */
+#define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"
+
+START_TEST(test_long_cdata_utf16) {
+ /* Test data is:
+ * <?xlm version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[
+ * ABCDEFGHIJKLMNOP
+ * ]]></a>
+ */
+ const char text[]
+ = "\0<\0?\0x\0m\0l\0 "
+ "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 "
+ "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
+ /* 64 characters per line */
+ /* clang-format off */
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16
+ /* clang-format on */
+ "\0]\0]\0>\0<\0/\0a\0>";
+ const XML_Char *expected =
+ /* clang-format off */
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOP");
+ /* clang-format on */
+ CharData storage;
+ void *buffer;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ buffer = XML_GetBuffer(g_parser, sizeof(text) - 1);
+ if (buffer == NULL)
+ fail("Could not allocate parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, text, sizeof(text) - 1);
+ if (XML_ParseBuffer(g_parser, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test handling of multiple unit UTF-16 characters */
+START_TEST(test_multichar_cdata_utf16) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[{MINIM}{CROTCHET}]]></a>
+ *
+ * where {MINIM} is U+1d15e (a minim or half-note)
+ * UTF-16: 0xd834 0xdd5e
+ * UTF-8: 0xf0 0x9d 0x85 0x9e
+ * and {CROTCHET} is U+1d15f (a crotchet or quarter-note)
+ * UTF-16: 0xd834 0xdd5f
+ * UTF-8: 0xf0 0x9d 0x85 0x9f
+ */
+ const char text[] = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
+ "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f"
+ "\0]\0]\0>\0<\0/\0a\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\xd834\xdd5e\xd834\xdd5f");
+#else
+ const XML_Char *expected = XCS("\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that an element name with a UTF-16 surrogate pair is rejected */
+START_TEST(test_utf16_bad_surrogate_pair) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[{BADLINB}]]></a>
+ *
+ * where {BADLINB} is U+10000 (the first Linear B character)
+ * with the UTF-16 surrogate pair in the wrong order, i.e.
+ * 0xdc00 0xd800
+ */
+ const char text[] = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
+ "\xdc\x00\xd8\x00"
+ "\0]\0]\0>\0<\0/\0a\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Reversed UTF-16 surrogate pair not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_bad_cdata) {
+ struct CaseData {
+ const char *text;
+ enum XML_Error expectedError;
+ };
+
+ struct CaseData cases[]
+ = {{"<a><", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><!", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![C", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN},
+
+ {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION},
+
+ {"<a><!<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
+ {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
+ {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN},
+
+ {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}};
+
+ size_t i = 0;
+ for (; i < sizeof(cases) / sizeof(struct CaseData); i++) {
+ set_subtest("%s", cases[i].text);
+ const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES(
+ g_parser, cases[i].text, (int)strlen(cases[i].text), XML_TRUE);
+ const enum XML_Error actualError = XML_GetErrorCode(g_parser);
+
+ assert(actualStatus == XML_STATUS_ERROR);
+
+ if (actualError != cases[i].expectedError) {
+ char message[100];
+ snprintf(message, sizeof(message),
+ "Expected error %d but got error %d for case %u: \"%s\"\n",
+ cases[i].expectedError, actualError, (unsigned int)i + 1,
+ cases[i].text);
+ fail(message);
+ }
+
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test failures in UTF-16 CDATA */
+START_TEST(test_bad_cdata_utf16) {
+ struct CaseData {
+ size_t text_bytes;
+ const char *text;
+ enum XML_Error expected_error;
+ };
+
+ const char prolog[] = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>";
+ struct CaseData cases[] = {
+ {1, "\0", XML_ERROR_UNCLOSED_TOKEN},
+ {2, "\0<", XML_ERROR_UNCLOSED_TOKEN},
+ {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN},
+ {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN},
+ {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN},
+ {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN},
+ {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN},
+ {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN},
+ {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN},
+ {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN},
+ {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN},
+ {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN},
+ {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN},
+ {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN},
+ {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN},
+ {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN},
+ {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN},
+ {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ /* Now add a four-byte UTF-16 character */
+ {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8",
+ XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", XML_ERROR_PARTIAL_CHAR},
+ {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd",
+ XML_ERROR_PARTIAL_CHAR},
+ {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e",
+ XML_ERROR_UNCLOSED_CDATA_SECTION}};
+ size_t i;
+
+ for (i = 0; i < sizeof(cases) / sizeof(struct CaseData); i++) {
+ set_subtest("case %lu", (long unsigned)(i + 1));
+ enum XML_Status actual_status;
+ enum XML_Error actual_error;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)sizeof(prolog) - 1,
+ XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ actual_status = _XML_Parse_SINGLE_BYTES(g_parser, cases[i].text,
+ (int)cases[i].text_bytes, XML_TRUE);
+ assert(actual_status == XML_STATUS_ERROR);
+ actual_error = XML_GetErrorCode(g_parser);
+ if (actual_error != cases[i].expected_error) {
+ char message[1024];
+
+ snprintf(message, sizeof(message),
+ "Expected error %d (%" XML_FMT_STR "), got %d (%" XML_FMT_STR
+ ") for case %lu\n",
+ cases[i].expected_error,
+ XML_ErrorString(cases[i].expected_error), actual_error,
+ XML_ErrorString(actual_error), (long unsigned)(i + 1));
+ fail(message);
+ }
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test stopping the parser in cdata handler */
+START_TEST(test_stop_parser_between_cdata_calls) {
+ const char *text = long_cdata_text;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ g_resumable = XML_FALSE;
+ expect_failure(text, XML_ERROR_ABORTED, "Parse not aborted in CDATA handler");
+}
+END_TEST
+
+/* Test suspending the parser in cdata handler */
+START_TEST(test_suspend_parser_between_cdata_calls) {
+ const char *text = long_cdata_text;
+ enum XML_Status result;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ g_resumable = XML_TRUE;
+ result = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+ if (result != XML_STATUS_SUSPENDED) {
+ if (result == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ fail("Parse not suspended in CDATA handler");
+ }
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test memory allocation functions */
+START_TEST(test_memory_allocation) {
+ char *buffer = (char *)XML_MemMalloc(g_parser, 256);
+ char *p;
+
+ if (buffer == NULL) {
+ fail("Allocation failed");
+ } else {
+ /* Try writing to memory; some OSes try to cheat! */
+ buffer[0] = 'T';
+ buffer[1] = 'E';
+ buffer[2] = 'S';
+ buffer[3] = 'T';
+ buffer[4] = '\0';
+ if (strcmp(buffer, "TEST") != 0) {
+ fail("Memory not writable");
+ } else {
+ p = (char *)XML_MemRealloc(g_parser, buffer, 512);
+ if (p == NULL) {
+ fail("Reallocation failed");
+ } else {
+ /* Write again, just to be sure */
+ buffer = p;
+ buffer[0] = 'V';
+ if (strcmp(buffer, "VEST") != 0) {
+ fail("Reallocated memory not writable");
+ }
+ }
+ }
+ XML_MemFree(g_parser, buffer);
+ }
+}
+END_TEST
+
+/* Test XML_DefaultCurrent() passes handling on correctly */
+START_TEST(test_default_current) {
+ const char *text = "<doc>hell]</doc>";
+ const char *entity_text = "<!DOCTYPE doc [\n"
+ "<!ENTITY entity '&#37;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ set_subtest("with defaulting");
+ {
+ struct handler_record_list storage;
+ storage.count = 0;
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ int i = 0;
+ assert_record_handler_called(&storage, i++, "record_default_handler", 5);
+ // we should have gotten one or more cdata callbacks, totaling 5 chars
+ int cdata_len_remaining = 5;
+ while (cdata_len_remaining > 0) {
+ const struct handler_record_entry *c_entry
+ = handler_record_get(&storage, i++);
+ assert_true(strcmp(c_entry->name, "record_cdata_handler") == 0);
+ assert_true(c_entry->arg > 0);
+ assert_true(c_entry->arg <= cdata_len_remaining);
+ cdata_len_remaining -= c_entry->arg;
+ // default handler must follow, with the exact same len argument.
+ assert_record_handler_called(&storage, i++, "record_default_handler",
+ c_entry->arg);
+ }
+ assert_record_handler_called(&storage, i++, "record_default_handler", 6);
+ assert_true(storage.count == i);
+ }
+
+ /* Again, without the defaulting */
+ set_subtest("no defaulting");
+ {
+ struct handler_record_list storage;
+ storage.count = 0;
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ int i = 0;
+ assert_record_handler_called(&storage, i++, "record_default_handler", 5);
+ // we should have gotten one or more cdata callbacks, totaling 5 chars
+ int cdata_len_remaining = 5;
+ while (cdata_len_remaining > 0) {
+ const struct handler_record_entry *c_entry
+ = handler_record_get(&storage, i++);
+ assert_true(strcmp(c_entry->name, "record_cdata_nodefault_handler") == 0);
+ assert_true(c_entry->arg > 0);
+ assert_true(c_entry->arg <= cdata_len_remaining);
+ cdata_len_remaining -= c_entry->arg;
+ }
+ assert_record_handler_called(&storage, i++, "record_default_handler", 6);
+ assert_true(storage.count == i);
+ }
+
+ /* Now with an internal entity to complicate matters */
+ set_subtest("with internal entity");
+ {
+ struct handler_record_list storage;
+ storage.count = 0;
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* The default handler suppresses the entity */
+ assert_record_handler_called(&storage, 0, "record_default_handler", 9);
+ assert_record_handler_called(&storage, 1, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 2, "record_default_handler", 3);
+ assert_record_handler_called(&storage, 3, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 4, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 5, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 6, "record_default_handler", 8);
+ assert_record_handler_called(&storage, 7, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 8, "record_default_handler", 6);
+ assert_record_handler_called(&storage, 9, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 10, "record_default_handler", 7);
+ assert_record_handler_called(&storage, 11, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 12, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 13, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 14, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 15, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 16, "record_default_handler", 5);
+ assert_record_handler_called(&storage, 17, "record_default_handler", 8);
+ assert_record_handler_called(&storage, 18, "record_default_handler", 6);
+ assert_true(storage.count == 19);
+ }
+
+ /* Again, with a skip handler */
+ set_subtest("with skip handler");
+ {
+ struct handler_record_list storage;
+ storage.count = 0;
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ XML_SetSkippedEntityHandler(g_parser, record_skip_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* The default handler suppresses the entity */
+ assert_record_handler_called(&storage, 0, "record_default_handler", 9);
+ assert_record_handler_called(&storage, 1, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 2, "record_default_handler", 3);
+ assert_record_handler_called(&storage, 3, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 4, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 5, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 6, "record_default_handler", 8);
+ assert_record_handler_called(&storage, 7, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 8, "record_default_handler", 6);
+ assert_record_handler_called(&storage, 9, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 10, "record_default_handler", 7);
+ assert_record_handler_called(&storage, 11, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 12, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 13, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 14, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 15, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 16, "record_default_handler", 5);
+ assert_record_handler_called(&storage, 17, "record_skip_handler", 0);
+ assert_record_handler_called(&storage, 18, "record_default_handler", 6);
+ assert_true(storage.count == 19);
+ }
+
+ /* This time, allow the entity through */
+ set_subtest("allow entity");
+ {
+ struct handler_record_list storage;
+ storage.count = 0;
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ assert_record_handler_called(&storage, 0, "record_default_handler", 9);
+ assert_record_handler_called(&storage, 1, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 2, "record_default_handler", 3);
+ assert_record_handler_called(&storage, 3, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 4, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 5, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 6, "record_default_handler", 8);
+ assert_record_handler_called(&storage, 7, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 8, "record_default_handler", 6);
+ assert_record_handler_called(&storage, 9, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 10, "record_default_handler", 7);
+ assert_record_handler_called(&storage, 11, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 12, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 13, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 14, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 15, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 16, "record_default_handler", 5);
+ assert_record_handler_called(&storage, 17, "record_cdata_handler", 1);
+ assert_record_handler_called(&storage, 18, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 19, "record_default_handler", 6);
+ assert_true(storage.count == 20);
+ }
+
+ /* Finally, without passing the cdata to the default handler */
+ set_subtest("not passing cdata");
+ {
+ struct handler_record_list storage;
+ storage.count = 0;
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ assert_record_handler_called(&storage, 0, "record_default_handler", 9);
+ assert_record_handler_called(&storage, 1, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 2, "record_default_handler", 3);
+ assert_record_handler_called(&storage, 3, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 4, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 5, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 6, "record_default_handler", 8);
+ assert_record_handler_called(&storage, 7, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 8, "record_default_handler", 6);
+ assert_record_handler_called(&storage, 9, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 10, "record_default_handler", 7);
+ assert_record_handler_called(&storage, 11, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 12, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 13, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 14, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 15, "record_default_handler", 1);
+ assert_record_handler_called(&storage, 16, "record_default_handler", 5);
+ assert_record_handler_called(&storage, 17, "record_cdata_nodefault_handler",
+ 1);
+ assert_record_handler_called(&storage, 18, "record_default_handler", 6);
+ assert_true(storage.count == 19);
+ }
+}
+END_TEST
+
+/* Test DTD element parsing code paths */
+START_TEST(test_dtd_elements) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc (chapter)>\n"
+ "<!ELEMENT chapter (#PCDATA)>\n"
+ "]>\n"
+ "<doc><chapter>Wombats are go</chapter></doc>";
+
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+static void XMLCALL
+element_decl_check_model(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ UNUSED_P(userData);
+ uint32_t errorFlags = 0;
+
+ /* Expected model array structure is this:
+ * [0] (type 6, quant 0)
+ * [1] (type 5, quant 0)
+ * [3] (type 4, quant 0, name "bar")
+ * [4] (type 4, quant 0, name "foo")
+ * [5] (type 4, quant 3, name "xyz")
+ * [2] (type 4, quant 2, name "zebra")
+ */
+ errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0));
+ errorFlags |= ((model != NULL) ? 0 : (1u << 1));
+
+ if (model != NULL) {
+ errorFlags |= ((model[0].type == XML_CTYPE_SEQ) ? 0 : (1u << 2));
+ errorFlags |= ((model[0].quant == XML_CQUANT_NONE) ? 0 : (1u << 3));
+ errorFlags |= ((model[0].numchildren == 2) ? 0 : (1u << 4));
+ errorFlags |= ((model[0].children == &model[1]) ? 0 : (1u << 5));
+ errorFlags |= ((model[0].name == NULL) ? 0 : (1u << 6));
+
+ errorFlags |= ((model[1].type == XML_CTYPE_CHOICE) ? 0 : (1u << 7));
+ errorFlags |= ((model[1].quant == XML_CQUANT_NONE) ? 0 : (1u << 8));
+ errorFlags |= ((model[1].numchildren == 3) ? 0 : (1u << 9));
+ errorFlags |= ((model[1].children == &model[3]) ? 0 : (1u << 10));
+ errorFlags |= ((model[1].name == NULL) ? 0 : (1u << 11));
+
+ errorFlags |= ((model[2].type == XML_CTYPE_NAME) ? 0 : (1u << 12));
+ errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13));
+ errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14));
+ errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15));
+ errorFlags
+ |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16));
+
+ errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17));
+ errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18));
+ errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19));
+ errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20));
+ errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21));
+
+ errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22));
+ errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23));
+ errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24));
+ errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25));
+ errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26));
+
+ errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27));
+ errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28));
+ errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29));
+ errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30));
+ errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31));
+ }
+
+ XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags);
+ XML_FreeContentModel(g_parser, model);
+}
+
+START_TEST(test_dtd_elements_nesting) {
+ // Payload inspired by a test in Perl's XML::Parser
+ const char *text = "<!DOCTYPE foo [\n"
+ "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>\n"
+ "]>\n"
+ "<foo/>";
+
+ XML_SetUserData(g_parser, (void *)(uintptr_t)-1);
+
+ XML_SetElementDeclHandler(g_parser, element_decl_check_model);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ if ((uint32_t)(uintptr_t)XML_GetUserData(g_parser) != 0)
+ fail("Element declaration model regression detected");
+}
+END_TEST
+
+/* Test foreign DTD handling */
+START_TEST(test_set_foreign_dtd) {
+ const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
+ const char *text2 = "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ /* Check hash salt is passed through too */
+ XML_SetHashSalt(g_parser, 0x12345678);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ /* Add a default handler to exercise more code paths */
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Ensure that trying to set the DTD after parsing has started
+ * is faulted, even if it's the same setting.
+ */
+ if (XML_UseForeignDTD(g_parser, XML_TRUE)
+ != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
+ fail("Failed to reject late foreign DTD setting");
+ /* Ditto for the hash salt */
+ if (XML_SetHashSalt(g_parser, 0x23456789))
+ fail("Failed to reject late hash salt change");
+
+ /* Now finish the parse */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test foreign DTD handling with a failing NotStandalone handler */
+START_TEST(test_foreign_dtd_not_standalone) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ expect_failure(text, XML_ERROR_NOT_STANDALONE,
+ "NotStandalonehandler failed to reject");
+}
+END_TEST
+
+/* Test invalid character in a foreign DTD is faulted */
+START_TEST(test_invalid_foreign_dtd) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+ ExtFaults test_data
+ = {"$", "Dollar not faulted", NULL, XML_ERROR_INVALID_TOKEN};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_UseForeignDTD(g_parser, XML_TRUE);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad DTD should not have been accepted");
+}
+END_TEST
+
+/* Test foreign DTD use with a doctype */
+START_TEST(test_foreign_dtd_with_doctype) {
+ const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n";
+ const char *text2 = "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ /* Check hash salt is passed through too */
+ XML_SetHashSalt(g_parser, 0x12345678);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ /* Add a default handler to exercise more code paths */
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Ensure that trying to set the DTD after parsing has started
+ * is faulted, even if it's the same setting.
+ */
+ if (XML_UseForeignDTD(g_parser, XML_TRUE)
+ != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
+ fail("Failed to reject late foreign DTD setting");
+ /* Ditto for the hash salt */
+ if (XML_SetHashSalt(g_parser, 0x23456789))
+ fail("Failed to reject late hash salt change");
+
+ /* Now finish the parse */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test XML_UseForeignDTD with no external subset present */
+START_TEST(test_foreign_dtd_without_external_subset) {
+ const char *text = "<!DOCTYPE doc [<!ENTITY foo 'bar'>]>\n"
+ "<doc>&foo;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, NULL);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
+ XML_UseForeignDTD(g_parser, XML_TRUE);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_empty_foreign_dtd) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
+ XML_UseForeignDTD(g_parser, XML_TRUE);
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Undefined entity not faulted");
+}
+END_TEST
+
+/* Test XML Base is set and unset appropriately */
+START_TEST(test_set_base) {
+ const XML_Char *old_base;
+ const XML_Char *new_base = XCS("/local/file/name.xml");
+
+ old_base = XML_GetBase(g_parser);
+ if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK)
+ fail("Unable to set base");
+ if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0)
+ fail("Base setting not correct");
+ if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK)
+ fail("Unable to NULL base");
+ if (XML_GetBase(g_parser) != NULL)
+ fail("Base setting not nulled");
+ XML_SetBase(g_parser, old_base);
+}
+END_TEST
+
+/* Test attribute counts, indexing, etc */
+START_TEST(test_attributes) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc (tag)>\n"
+ "<!ATTLIST doc id ID #REQUIRED>\n"
+ "]>"
+ "<doc a='1' id='one' b='2'>"
+ "<tag c='3'/>"
+ "</doc>";
+ AttrInfo doc_info[] = {{XCS("a"), XCS("1")},
+ {XCS("b"), XCS("2")},
+ {XCS("id"), XCS("one")},
+ {NULL, NULL}};
+ AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL},
+ {XCS("tag"), 1, NULL, NULL},
+ {NULL, 0, NULL, NULL}};
+ info[0].attributes = doc_info;
+ info[1].attributes = tag_info;
+
+ XML_SetStartElementHandler(g_parser, counting_start_element_handler);
+ XML_SetUserData(g_parser, info);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test reset works correctly in the middle of processing an internal
+ * entity. Exercises some obscure code in XML_ParserReset().
+ */
+START_TEST(test_reset_in_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY wombat 'wom'>\n"
+ "<!ENTITY entity 'hi &wom; there'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+ XML_ParsingStatus status;
+
+ g_resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_SUSPENDED)
+ fail("Parsing status not SUSPENDED");
+ XML_ParserReset(g_parser, NULL);
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_INITIALIZED)
+ fail("Parsing status doesn't reset to INITIALIZED");
+}
+END_TEST
+
+/* Test that resume correctly passes through parse errors */
+START_TEST(test_resume_invalid_parse) {
+ const char *text = "<doc>Hello</doc"; /* Missing closing wedge */
+
+ g_resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_ResumeParser(g_parser) == XML_STATUS_OK)
+ fail("Resumed invalid parse not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_UNCLOSED_TOKEN)
+ fail("Invalid parse not correctly faulted");
+}
+END_TEST
+
+/* Test that re-suspended parses are correctly passed through */
+START_TEST(test_resume_resuspended) {
+ const char *text = "<doc>Hello<meep/>world</doc>";
+
+ g_resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ g_resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
+ fail("Resumption not suspended");
+ /* This one should succeed and finish up */
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that CDATA shows up correctly through a default handler */
+START_TEST(test_cdata_default) {
+ const char *text = "<doc><![CDATA[Hello\nworld]]></doc>";
+ const XML_Char *expected = XCS("<doc><![CDATA[Hello\nworld]]></doc>");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test resetting a subordinate parser does exactly nothing */
+START_TEST(test_subordinate_reset) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_resetter);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test suspending a subordinate parser */
+START_TEST(test_subordinate_suspend) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_suspender);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test suspending a subordinate parser from an XML declaration */
+/* Increases code coverage of the tests */
+
+START_TEST(test_subordinate_xdecl_suspend) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
+ g_resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_subordinate_xdecl_abort) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
+ g_resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test external entity fault handling with suspension */
+START_TEST(test_ext_entity_invalid_suspended_parse) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtFaults faults[]
+ = {{"<?xml version='1.0' encoding='us-ascii'?><",
+ "Incomplete element declaration not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {/* First two bytes of a three-byte char */
+ "<?xml version='1.0' encoding='utf-8'?>\xe2\x82",
+ "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ ExtFaults *fault;
+
+ for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
+ set_subtest("%s", fault->parse_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser,
+ external_entity_suspending_faulter);
+ XML_SetUserData(g_parser, fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Parser did not report external entity error");
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test setting an explicit encoding */
+START_TEST(test_explicit_encoding) {
+ const char *text1 = "<doc>Hello ";
+ const char *text2 = " World</doc>";
+
+ /* Just check that we can set the encoding to NULL before starting */
+ if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
+ fail("Failed to initialise encoding to NULL");
+ /* Say we are UTF-8 */
+ if (XML_SetEncoding(g_parser, XCS("utf-8")) != XML_STATUS_OK)
+ fail("Failed to set explicit encoding");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Try to switch encodings mid-parse */
+ if (XML_SetEncoding(g_parser, XCS("us-ascii")) != XML_STATUS_ERROR)
+ fail("Allowed encoding change");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Try now the parse is over */
+ if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
+ fail("Failed to unset encoding");
+}
+END_TEST
+
+/* Test handling of trailing CR (rather than newline) */
+START_TEST(test_trailing_cr) {
+ const char *text = "<doc>\r";
+ int found_cr;
+
+ /* Try with a character handler, for code coverage */
+ XML_SetCharacterDataHandler(g_parser, cr_cdata_handler);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_cr == 0)
+ fail("Did not catch the carriage return");
+ XML_ParserReset(g_parser, NULL);
+
+ /* Now with a default handler instead */
+ XML_SetDefaultHandler(g_parser, cr_cdata_handler);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_cr == 0)
+ fail("Did not catch default carriage return");
+}
+END_TEST
+
+/* Test trailing CR in an external entity parse */
+START_TEST(test_ext_entity_trailing_cr) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int found_cr;
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_cr_catcher);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (found_cr == 0)
+ fail("No carriage return found");
+ XML_ParserReset(g_parser, NULL);
+
+ /* Try again with a different trailing CR */
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_bad_cr_catcher);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (found_cr == 0)
+ fail("No carriage return found");
+}
+END_TEST
+
+/* Test handling of trailing square bracket */
+START_TEST(test_trailing_rsqb) {
+ const char *text8 = "<doc>]";
+ const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000";
+ int found_rsqb;
+ int text8_len = (int)strlen(text8);
+
+ XML_SetCharacterDataHandler(g_parser, rsqb_handler);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text8, text8_len, XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_rsqb == 0)
+ fail("Did not catch the right square bracket");
+
+ /* Try again with a different encoding */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetCharacterDataHandler(g_parser, rsqb_handler);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
+ XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_rsqb == 0)
+ fail("Did not catch the right square bracket");
+
+ /* And finally with a default handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, rsqb_handler);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
+ XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_rsqb == 0)
+ fail("Did not catch the right square bracket");
+}
+END_TEST
+
+/* Test trailing right square bracket in an external entity parse */
+START_TEST(test_ext_entity_trailing_rsqb) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int found_rsqb;
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_rsqb_catcher);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (found_rsqb == 0)
+ fail("No right square bracket found");
+}
+END_TEST
+
+/* Test CDATA handling in an external entity */
+START_TEST(test_ext_entity_good_cdata) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_good_cdata_ascii);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test user parameter settings */
+START_TEST(test_user_parameters) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!-- Primary parse -->\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;";
+ const char *epilog = "<!-- Back to primary parser -->\n"
+ "</doc>";
+
+ g_comment_count = 0;
+ g_skip_count = 0;
+ g_xdecl_count = 0;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetXmlDeclHandler(g_parser, xml_decl_handler);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_param_checker);
+ XML_SetCommentHandler(g_parser, data_check_comment_handler);
+ XML_SetSkippedEntityHandler(g_parser, param_check_skip_handler);
+ XML_UseParserAsHandlerArg(g_parser);
+ XML_SetUserData(g_parser, (void *)1);
+ g_handler_data = g_parser;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Ensure we can't change policy mid-parse */
+ if (XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_NEVER))
+ fail("Changed param entity parsing policy while parsing");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (g_comment_count != 3)
+ fail("Comment handler not invoked enough times");
+ if (g_skip_count != 1)
+ fail("Skip handler not invoked enough times");
+ if (g_xdecl_count != 1)
+ fail("XML declaration handler not invoked");
+}
+END_TEST
+
+/* Test that an explicit external entity handler argument replaces
+ * the parser as the first argument.
+ *
+ * We do not call the first parameter to the external entity handler
+ * 'parser' for once, since the first time the handler is called it
+ * will actually be a text string. We need to be able to access the
+ * global 'parser' variable to create our external entity parser from,
+ * since there are code paths we need to ensure get executed.
+ */
+START_TEST(test_ext_entity_ref_parameter) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
+ /* Set a handler arg that is not NULL and not parser (which is
+ * what NULL would cause to be passed.
+ */
+ XML_SetExternalEntityRefHandlerArg(g_parser, (void *)text);
+ g_handler_data = text;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Now try again with unset args */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
+ XML_SetExternalEntityRefHandlerArg(g_parser, NULL);
+ g_handler_data = g_parser;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test the parsing of an empty string */
+START_TEST(test_empty_parse) {
+ const char *text = "<doc></doc>";
+ const char *partial = "<doc>";
+
+ if (XML_Parse(g_parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR)
+ fail("Parsing empty string faulted");
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Parsing final empty string not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_ELEMENTS)
+ fail("Parsing final empty string faulted for wrong reason");
+
+ /* Now try with valid text before the empty end */
+ XML_ParserReset(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR)
+ fail("Parsing final empty string faulted");
+
+ /* Now try with invalid text before the empty end */
+ XML_ParserReset(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, partial, (int)strlen(partial),
+ XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Parsing final incomplete empty string not faulted");
+}
+END_TEST
+
+/* Test odd corners of the XML_GetBuffer interface */
+static enum XML_Status
+get_feature(enum XML_FeatureEnum feature_id, long *presult) {
+ const XML_Feature *feature = XML_GetFeatureList();
+
+ if (feature == NULL)
+ return XML_STATUS_ERROR;
+ for (; feature->feature != XML_FEATURE_END; feature++) {
+ if (feature->feature == feature_id) {
+ *presult = feature->value;
+ return XML_STATUS_OK;
+ }
+ }
+ return XML_STATUS_ERROR;
+}
+
+/* Test odd corners of the XML_GetBuffer interface */
+START_TEST(test_get_buffer_1) {
+ const char *text = get_buffer_test_text;
+ void *buffer;
+ long context_bytes;
+
+ /* Attempt to allocate a negative length buffer */
+ if (XML_GetBuffer(g_parser, -12) != NULL)
+ fail("Negative length buffer not failed");
+
+ /* Now get a small buffer and extend it past valid length */
+ buffer = XML_GetBuffer(g_parser, 1536);
+ if (buffer == NULL)
+ fail("1.5K buffer failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_GetBuffer(g_parser, INT_MAX) != NULL)
+ fail("INT_MAX buffer not failed");
+
+ /* Now try extending it a more reasonable but still too large
+ * amount. The allocator in XML_GetBuffer() doubles the buffer
+ * size until it exceeds the requested amount or INT_MAX. If it
+ * exceeds INT_MAX, it rejects the request, so we want a request
+ * between INT_MAX and INT_MAX/2. A gap of 1K seems comfortable,
+ * with an extra byte just to ensure that the request is off any
+ * boundary. The request will be inflated internally by
+ * XML_CONTEXT_BYTES (if >=1), so we subtract that from our
+ * request.
+ */
+ if (get_feature(XML_FEATURE_CONTEXT_BYTES, &context_bytes) != XML_STATUS_OK)
+ context_bytes = 0;
+ if (XML_GetBuffer(g_parser, INT_MAX - (context_bytes + 1025)) != NULL)
+ fail("INT_MAX- buffer not failed");
+
+ /* Now try extending it a carefully crafted amount */
+ if (XML_GetBuffer(g_parser, 1000) == NULL)
+ fail("1000 buffer failed");
+}
+END_TEST
+
+/* Test more corners of the XML_GetBuffer interface */
+START_TEST(test_get_buffer_2) {
+ const char *text = get_buffer_test_text;
+ void *buffer;
+
+ /* Now get a decent buffer */
+ buffer = XML_GetBuffer(g_parser, 1536);
+ if (buffer == NULL)
+ fail("1.5K buffer failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Extend it, to catch a different code path */
+ if (XML_GetBuffer(g_parser, 1024) == NULL)
+ fail("1024 buffer failed");
+}
+END_TEST
+
+/* Test for signed integer overflow CVE-2022-23852 */
+#if XML_CONTEXT_BYTES > 0
+START_TEST(test_get_buffer_3_overflow) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert(parser != NULL);
+
+ const char *const text = "\n";
+ const int expectedKeepValue = (int)strlen(text);
+
+ // After this call, variable "keep" in XML_GetBuffer will
+ // have value expectedKeepValue
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text),
+ XML_FALSE /* isFinal */)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ assert(expectedKeepValue > 0);
+ if (XML_GetBuffer(parser, INT_MAX - expectedKeepValue + 1) != NULL)
+ fail("enlarging buffer not failed");
+
+ XML_ParserFree(parser);
+}
+END_TEST
+#endif // XML_CONTEXT_BYTES > 0
+
+START_TEST(test_buffer_can_grow_to_max) {
+ const char *const prefixes[] = {
+ "",
+ "<",
+ "<x a='",
+ "<doc><x a='",
+ "<document><x a='",
+ "<averylongelementnamesuchthatitwillhopefullystretchacrossmultiplelinesand"
+ "lookprettyridiculousitsalsoveryhardtoreadandifyouredoingitihavetowonderif"
+ "youreallydonthaveanythingbettertodoofcourseiguessicouldveputsomethingbadin"
+ "herebutipromisethatididntheybtwhowgreatarespacesandpunctuationforhelping"
+ "withreadabilityprettygreatithinkanywaysthisisprobablylongenoughbye><x a='"};
+ const int num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]);
+ int maxbuf = INT_MAX / 2 + (INT_MAX & 1); // round up without overflow
+#if defined(__MINGW32__) && ! defined(__MINGW64__)
+ // workaround for mingw/wine32 on GitHub CI not being able to reach 1GiB
+ // Can we make a big allocation?
+ void *big = malloc(maxbuf);
+ if (! big) {
+ // The big allocation failed. Let's be a little lenient.
+ maxbuf = maxbuf / 2;
+ }
+ free(big);
+#endif
+
+ for (int i = 0; i < num_prefixes; ++i) {
+ set_subtest("\"%s\"", prefixes[i]);
+ XML_Parser parser = XML_ParserCreate(NULL);
+ const int prefix_len = (int)strlen(prefixes[i]);
+ const enum XML_Status s
+ = _XML_Parse_SINGLE_BYTES(parser, prefixes[i], prefix_len, XML_FALSE);
+ if (s != XML_STATUS_OK)
+ xml_failure(parser);
+
+ // XML_CONTEXT_BYTES of the prefix may remain in the buffer;
+ // subtracting the whole prefix is easiest, and close enough.
+ assert_true(XML_GetBuffer(parser, maxbuf - prefix_len) != NULL);
+ // The limit should be consistent; no prefix should allow us to
+ // reach above the max buffer size.
+ assert_true(XML_GetBuffer(parser, maxbuf + 1) == NULL);
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+START_TEST(test_getbuffer_allocates_on_zero_len) {
+ for (int first_len = 1; first_len >= 0; first_len--) {
+ set_subtest("with len=%d first", first_len);
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ assert_true(XML_GetBuffer(parser, first_len) != NULL);
+ assert_true(XML_GetBuffer(parser, 0) != NULL);
+ if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_OK)
+ xml_failure(parser);
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+/* Test position information macros */
+START_TEST(test_byte_info_at_end) {
+ const char *text = "<doc></doc>";
+
+ if (XML_GetCurrentByteIndex(g_parser) != -1
+ || XML_GetCurrentByteCount(g_parser) != 0)
+ fail("Byte index/count incorrect at start of parse");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* At end, the count will be zero and the index the end of string */
+ if (XML_GetCurrentByteCount(g_parser) != 0)
+ fail("Terminal byte count incorrect");
+ if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text))
+ fail("Terminal byte index incorrect");
+}
+END_TEST
+
+/* Test position information from errors */
+#define PRE_ERROR_STR "<doc></"
+#define POST_ERROR_STR "wombat></doc>"
+START_TEST(test_byte_info_at_error) {
+ const char *text = PRE_ERROR_STR POST_ERROR_STR;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Syntax error not faulted");
+ if (XML_GetCurrentByteCount(g_parser) != 0)
+ fail("Error byte count incorrect");
+ if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR))
+ fail("Error byte index incorrect");
+}
+END_TEST
+#undef PRE_ERROR_STR
+#undef POST_ERROR_STR
+
+/* Test position information in handler */
+#define START_ELEMENT "<e>"
+#define CDATA_TEXT "Hello"
+#define END_ELEMENT "</e>"
+START_TEST(test_byte_info_at_cdata) {
+ const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT;
+ int offset, size;
+ ByteTestData data;
+
+ /* Check initial context is empty */
+ if (XML_GetInputContext(g_parser, &offset, &size) != NULL)
+ fail("Unexpected context at start of parse");
+
+ data.start_element_len = (int)strlen(START_ELEMENT);
+ data.cdata_len = (int)strlen(CDATA_TEXT);
+ data.total_string_len = (int)strlen(text);
+ XML_SetCharacterDataHandler(g_parser, byte_character_handler);
+ XML_SetUserData(g_parser, &data);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
+ xml_failure(g_parser);
+}
+END_TEST
+#undef START_ELEMENT
+#undef CDATA_TEXT
+#undef END_ELEMENT
+
+/* Test predefined entities are correctly recognised */
+START_TEST(test_predefined_entities) {
+ const char *text = "<doc>&lt;&gt;&amp;&quot;&apos;</doc>";
+ const XML_Char *expected = XCS("<doc>&lt;&gt;&amp;&quot;&apos;</doc>");
+ const XML_Char *result = XCS("<>&\"'");
+ CharData storage;
+
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ /* run_character_check uses XML_SetCharacterDataHandler(), which
+ * unfortunately heads off a code path that we need to exercise.
+ */
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* The default handler doesn't translate the entities */
+ CharData_CheckXMLChars(&storage, expected);
+
+ /* Now try again and check the translation */
+ XML_ParserReset(g_parser, NULL);
+ run_character_check(text, result);
+}
+END_TEST
+
+/* Regression test that an invalid tag in an external parameter
+ * reference in an external DTD is correctly faulted.
+ *
+ * Only a few specific tags are legal in DTDs ignoring comments and
+ * processing instructions, all of which begin with an exclamation
+ * mark. "<el/>" is not one of them, so the parser should raise an
+ * error on encountering it.
+ */
+START_TEST(test_invalid_tag_in_dtd) {
+ const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
+ "<doc></doc>\n";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_param);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Invalid tag IN DTD external param not rejected");
+}
+END_TEST
+
+/* Test entities not quite the predefined ones are not mis-recognised */
+START_TEST(test_not_predefined_entities) {
+ const char *text[] = {"<doc>&pt;</doc>", "<doc>&amo;</doc>",
+ "<doc>&quid;</doc>", "<doc>&apod;</doc>", NULL};
+ int i = 0;
+
+ while (text[i] != NULL) {
+ expect_failure(text[i], XML_ERROR_UNDEFINED_ENTITY,
+ "Undefined entity not rejected");
+ XML_ParserReset(g_parser, NULL);
+ i++;
+ }
+}
+END_TEST
+
+/* Test conditional inclusion (IGNORE) */
+START_TEST(test_ignore_section) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc><e>&entity;</e></doc>";
+ const XML_Char *expected
+ = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&entity;");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetEndElementHandler(g_parser, dummy_end_element);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ignore_section_utf16) {
+ const char text[] =
+ /* <!DOCTYPE d SYSTEM 's'> */
+ "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
+ "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n\0"
+ /* <d><e>&en;</e></d> */
+ "<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>\0";
+ const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore_utf16);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetEndElementHandler(g_parser, dummy_end_element);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ignore_section_utf16_be) {
+ const char text[] =
+ /* <!DOCTYPE d SYSTEM 's'> */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
+ "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n"
+ /* <d><e>&en;</e></d> */
+ "\0<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>";
+ const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetExternalEntityRefHandler(g_parser,
+ external_entity_load_ignore_utf16_be);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetEndElementHandler(g_parser, dummy_end_element);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test mis-formatted conditional exclusion */
+START_TEST(test_bad_ignore_section) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc><e>&entity;</e></doc>";
+ ExtFaults faults[]
+ = {{"<![IGNORE[<!ELEM", "Broken-off declaration not faulted", NULL,
+ XML_ERROR_SYNTAX},
+ {"<![IGNORE[\x01]]>", "Invalid XML character not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN},
+ {/* FIrst two bytes of a three-byte char */
+ "<![IGNORE[\xe2\x82", "Partial XML character not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ ExtFaults *fault;
+
+ for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
+ set_subtest("%s", fault->parse_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Incomplete IGNORE section not failed");
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+struct bom_testdata {
+ const char *external;
+ int split;
+ XML_Bool nested_callback_happened;
+};
+
+static int XMLCALL
+external_bom_checker(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text;
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+
+ XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+
+ if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ struct bom_testdata *const testdata
+ = (struct bom_testdata *)XML_GetUserData(parser);
+ const char *const external = testdata->external;
+ const int split = testdata->split;
+ testdata->nested_callback_happened = XML_TRUE;
+
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, external, split, XML_FALSE)
+ != XML_STATUS_OK) {
+ xml_failure(ext_parser);
+ }
+ text = external + split; // the parse below will continue where we left off.
+ } else if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ text = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n";
+ } else {
+ fail("unknown systemId");
+ }
+
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+/* regression test: BOM should be consumed when followed by a partial token. */
+START_TEST(test_external_bom_consumed) {
+ const char *const text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
+ "<doc></doc>\n";
+ const char *const external = "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>";
+ const int len = (int)strlen(external);
+ for (int split = 0; split <= len; ++split) {
+ set_subtest("split at byte %d", split);
+
+ struct bom_testdata testdata;
+ testdata.external = external;
+ testdata.split = split;
+ testdata.nested_callback_happened = XML_FALSE;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ if (parser == NULL) {
+ fail("Couldn't create parser");
+ }
+ XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(parser, external_bom_checker);
+ XML_SetUserData(parser, &testdata);
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+ if (! testdata.nested_callback_happened) {
+ fail("ref handler not called");
+ }
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+/* Test recursive parsing */
+START_TEST(test_external_entity_values) {
+ const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
+ "<doc></doc>\n";
+ ExtFaults data_004_2[] = {
+ {"<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, XML_ERROR_NONE},
+ {"<!ATTLIST $doc a1 CDATA 'value'>", "Invalid token not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN},
+ {"'wombat", "Unterminated string not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {"\xe2\x82", "Partial UTF-8 character not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {"<?xml version='1.0' encoding='utf-8'?>\n", NULL, NULL, XML_ERROR_NONE},
+ {"<?xml?>", "Malformed XML declaration not faulted", NULL,
+ XML_ERROR_XML_DECL},
+ {/* UTF-8 BOM */
+ "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL,
+ XML_ERROR_NONE},
+ {"<?xml version='1.0' encoding='utf-8'?>\n$",
+ "Invalid token after text declaration not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN},
+ {"<?xml version='1.0' encoding='utf-8'?>\n'wombat",
+ "Unterminated string after text decl not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {"<?xml version='1.0' encoding='utf-8'?>\n\xe2\x82",
+ "Partial UTF-8 character after text decl not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {"%e1;", "Recursive parameter entity not faulted", NULL,
+ XML_ERROR_RECURSIVE_ENTITY_REF},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ int i;
+
+ for (i = 0; data_004_2[i].parse_text != NULL; i++) {
+ set_subtest("%s", data_004_2[i].parse_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_valuer);
+ XML_SetUserData(g_parser, &data_004_2[i]);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test the recursive parse interacts with a not standalone handler */
+START_TEST(test_ext_entity_not_standalone) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc></doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_not_standalone);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Standalone rejection not caught");
+}
+END_TEST
+
+START_TEST(test_ext_entity_value_abort) {
+ const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
+ "<doc></doc>\n";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_value_aborter);
+ g_resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_bad_public_doctype) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!DOCTYPE doc PUBLIC '{BadName}' 'test'>\n"
+ "<doc></doc>";
+
+ /* Setting a handler provokes a particular code path */
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
+ dummy_end_doctype_handler);
+ expect_failure(text, XML_ERROR_PUBLICID, "Bad Public ID not failed");
+}
+END_TEST
+
+/* Test based on ibm/valid/P32/ibm32v04.xml */
+START_TEST(test_attribute_enum_value) {
+ const char *text = "<?xml version='1.0' standalone='no'?>\n"
+ "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
+ "<animal>This is a \n <a/> \n\nyellow tiger</animal>";
+ ExtTest dtd_data
+ = {"<!ELEMENT animal (#PCDATA|a)*>\n"
+ "<!ELEMENT a EMPTY>\n"
+ "<!ATTLIST animal xml:space (default|preserve) 'preserve'>",
+ NULL, NULL};
+ const XML_Char *expected = XCS("This is a \n \n\nyellow tiger");
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetUserData(g_parser, &dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ /* An attribute list handler provokes a different code path */
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ run_ext_character_check(text, &dtd_data, expected);
+}
+END_TEST
+
+/* Slightly bizarrely, the library seems to silently ignore entity
+ * definitions for predefined entities, even when they are wrong. The
+ * language of the XML 1.0 spec is somewhat unhelpful as to what ought
+ * to happen, so this is currently treated as acceptable.
+ */
+START_TEST(test_predefined_entity_redefinition) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY apos 'foo'>\n"
+ "]>\n"
+ "<doc>&apos;</doc>";
+ run_character_check(text, XCS("'"));
+}
+END_TEST
+
+/* Test that the parser stops processing the DTD after an unresolved
+ * parameter entity is encountered.
+ */
+START_TEST(test_dtd_stop_processing) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "%foo;\n"
+ "<!ENTITY bar 'bas'>\n"
+ "]><doc/>";
+
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (get_dummy_handler_flags() != 0)
+ fail("DTD processing still going after undefined PE");
+}
+END_TEST
+
+/* Test public notations with no system ID */
+START_TEST(test_public_notation_no_sysid) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!NOTATION note PUBLIC 'foo'>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+
+ init_dummy_handlers();
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (get_dummy_handler_flags() != DUMMY_NOTATION_DECL_HANDLER_FLAG)
+ fail("Notation declaration handler not called");
+}
+END_TEST
+
+START_TEST(test_nested_groups) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc "
+ /* Sixteen elements per line */
+ "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
+ "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
+ "))))))))))))))))))))))))))))))))>\n"
+ "<!ELEMENT e EMPTY>"
+ "]>\n"
+ "<doc><e/></doc>";
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS("doce"));
+ if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler not fired");
+}
+END_TEST
+
+START_TEST(test_group_choice) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc (a|b|c)+>\n"
+ "<!ELEMENT a EMPTY>\n"
+ "<!ELEMENT b (#PCDATA)>\n"
+ "<!ELEMENT c ANY>\n"
+ "]>\n"
+ "<doc>\n"
+ "<a/>\n"
+ "<b attr='foo'>This is a foo</b>\n"
+ "<c></c>\n"
+ "</doc>\n";
+
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler flag not raised");
+}
+END_TEST
+
+START_TEST(test_standalone_parameter_entity) {
+ const char *text = "<?xml version='1.0' standalone='yes'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/' [\n"
+ "<!ENTITY % entity '<!ELEMENT doc (#PCDATA)>'>\n"
+ "%entity;\n"
+ "]>\n"
+ "<doc></doc>";
+ char dtd_data[] = "<!ENTITY % e1 'foo'>\n";
+
+ XML_SetUserData(g_parser, dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test skipping of parameter entity in an external DTD */
+/* Derived from ibm/invalid/P69/ibm69i01.xml */
+START_TEST(test_skipped_parameter_entity) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
+ "<!ELEMENT root (#PCDATA|a)* >\n"
+ "]>\n"
+ "<root></root>";
+ ExtTest dtd_data = {"%pe2;", NULL, NULL};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetUserData(g_parser, &dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetSkippedEntityHandler(g_parser, dummy_skip_handler);
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (get_dummy_handler_flags() != DUMMY_SKIP_HANDLER_FLAG)
+ fail("Skip handler not executed");
+}
+END_TEST
+
+/* Test recursive parameter entity definition rejected in external DTD */
+START_TEST(test_recursive_external_parameter_entity) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
+ "<!ELEMENT root (#PCDATA|a)* >\n"
+ "]>\n"
+ "<root></root>";
+ ExtFaults dtd_data = {"<!ENTITY % pe2 '&#37;pe2;'>\n%pe2;",
+ "Recursive external parameter entity not faulted", NULL,
+ XML_ERROR_RECURSIVE_ENTITY_REF};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Recursive external parameter not spotted");
+}
+END_TEST
+
+/* Test undefined parameter entity in external entity handler */
+START_TEST(test_undefined_ext_entity_in_external_dtd) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc></doc>\n";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
+ XML_SetUserData(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Now repeat without the external entity ref handler invoking
+ * another copy of itself.
+ */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
+ XML_SetUserData(g_parser, g_parser); /* Any non-NULL value will do */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test suspending the parse on receiving an XML declaration works */
+START_TEST(test_suspend_xdecl) {
+ const char *text = long_character_data_text;
+
+ XML_SetXmlDeclHandler(g_parser, entity_suspending_xdecl_handler);
+ XML_SetUserData(g_parser, g_parser);
+ g_resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+ /* Attempt to start a new parse while suspended */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Attempt to parse while suspended not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ fail("Suspended parse not faulted with correct error");
+}
+END_TEST
+
+/* Test aborting the parse in an epilog works */
+START_TEST(test_abort_epilog) {
+ const char *text = "<doc></doc>\n\r\n";
+ XML_Char trigger_char = XCS('\r');
+
+ XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
+ XML_SetUserData(g_parser, &trigger_char);
+ g_resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Abort not triggered");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test a different code path for abort in the epilog */
+START_TEST(test_abort_epilog_2) {
+ const char *text = "<doc></doc>\n";
+ XML_Char trigger_char = XCS('\n');
+
+ XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
+ XML_SetUserData(g_parser, &trigger_char);
+ g_resumable = XML_FALSE;
+ expect_failure(text, XML_ERROR_ABORTED, "Abort not triggered");
+}
+END_TEST
+
+/* Test suspension from the epilog */
+START_TEST(test_suspend_epilog) {
+ const char *text = "<doc></doc>\n";
+ XML_Char trigger_char = XCS('\n');
+
+ XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
+ XML_SetUserData(g_parser, &trigger_char);
+ g_resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_suspend_in_sole_empty_tag) {
+ const char *text = "<doc/>";
+ enum XML_Status rc;
+
+ XML_SetEndElementHandler(g_parser, suspending_end_handler);
+ XML_SetUserData(g_parser, g_parser);
+ rc = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ else if (rc != XML_STATUS_SUSPENDED)
+ fail("Suspend not triggered");
+ rc = XML_ResumeParser(g_parser);
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ else if (rc != XML_STATUS_OK)
+ fail("Resume failed");
+}
+END_TEST
+
+START_TEST(test_unfinished_epilog) {
+ const char *text = "<doc></doc><";
+
+ expect_failure(text, XML_ERROR_UNCLOSED_TOKEN,
+ "Incomplete epilog entry not faulted");
+}
+END_TEST
+
+START_TEST(test_partial_char_in_epilog) {
+ const char *text = "<doc></doc>\xe2\x82";
+
+ /* First check that no fault is raised if the parse is not finished */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Now check that it is faulted once we finish */
+ if (XML_ParseBuffer(g_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Partial character in epilog not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_PARTIAL_CHAR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test resuming a parse suspended in entity substitution */
+START_TEST(test_suspend_resume_internal_entity) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ENTITY foo '<suspend>Hi<suspend>Ho</suspend></suspend>'>\n"
+ "]>\n"
+ "<doc>&foo;</doc>\n";
+ const XML_Char *expected1 = XCS("Hi");
+ const XML_Char *expected2 = XCS("HiHo");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, start_element_suspender);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ // can't use SINGLE_BYTES here, because it'll return early on suspension, and
+ // we won't know exactly how much input we actually managed to give Expat.
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS(""));
+ if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected1);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected2);
+}
+END_TEST
+
+START_TEST(test_suspend_resume_internal_entity_issue_629) {
+ const char *const text
+ = "<!DOCTYPE a [<!ENTITY e '<!--COMMENT-->a'>]><a>&e;<b>\n"
+ "<"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "/>"
+ "</b></a>";
+ const size_t firstChunkSizeBytes = 54;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_SetUserData(parser, parser);
+ XML_SetCommentHandler(parser, suspending_comment_handler);
+
+ if (XML_Parse(parser, text, (int)firstChunkSizeBytes, XML_FALSE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(parser);
+ if (XML_ResumeParser(parser) != XML_STATUS_OK)
+ xml_failure(parser);
+ if (_XML_Parse_SINGLE_BYTES(parser, text + firstChunkSizeBytes,
+ (int)(strlen(text) - firstChunkSizeBytes),
+ XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+ XML_ParserFree(parser);
+}
+END_TEST
+
+/* Test syntax error is caught at parse resumption */
+START_TEST(test_resume_entity_with_syntax_error) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY foo '<suspend>Hi</wombat>'>\n"
+ "]>\n"
+ "<doc>&foo;</doc>\n";
+
+ XML_SetStartElementHandler(g_parser, start_element_suspender);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
+ fail("Syntax error in entity not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_TAG_MISMATCH)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test suspending and resuming in a parameter entity substitution */
+START_TEST(test_suspend_resume_parameter_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY % foo '<!ELEMENT doc (#PCDATA)*>'>\n"
+ "%foo;\n"
+ "]>\n"
+ "<doc>Hello, world</doc>";
+ const XML_Char *expected = XCS("Hello, world");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetElementDeclHandler(g_parser, element_decl_suspender);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS(""));
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test attempting to use parser after an error is faulted */
+START_TEST(test_restart_on_error) {
+ const char *text = "<$doc><doc></doc>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid tag name not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Restarting invalid parse not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that angle brackets in an attribute default value are faulted */
+START_TEST(test_reject_lt_in_attribute_value) {
+ const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '<bar>'>]>\n"
+ "<doc></doc>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad attribute default not faulted");
+}
+END_TEST
+
+START_TEST(test_reject_unfinished_param_in_att_value) {
+ const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '&foo'>]>\n"
+ "<doc></doc>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad attribute default not faulted");
+}
+END_TEST
+
+START_TEST(test_trailing_cr_in_att_value) {
+ const char *text = "<doc a='value\r'/>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Try parsing a general entity within a parameter entity in a
+ * standalone internal DTD. Covers a corner case in the parser.
+ */
+START_TEST(test_standalone_internal_entity) {
+ const char *text = "<?xml version='1.0' standalone='yes' ?>\n"
+ "<!DOCTYPE doc [\n"
+ " <!ELEMENT doc (#PCDATA)>\n"
+ " <!ENTITY % pe '<!ATTLIST doc att2 CDATA \"&ge;\">'>\n"
+ " <!ENTITY ge 'AttDefaultValue'>\n"
+ " %pe;\n"
+ "]>\n"
+ "<doc att2='any'/>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that a reference to an unknown external entity is skipped */
+START_TEST(test_skipped_external_entity) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc></doc>\n";
+ ExtTest test_data = {"<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e2 '%e1;'>\n",
+ NULL, NULL};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test a different form of unknown external entity */
+START_TEST(test_skipped_null_loaded_ext_entity) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
+ "<doc />";
+ ExtHdlrData test_data
+ = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
+ "<!ENTITY % pe2 '%pe1;'>\n"
+ "%pe2;\n",
+ external_entity_null_loader};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_skipped_unloaded_ext_entity) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
+ "<doc />";
+ ExtHdlrData test_data
+ = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
+ "<!ENTITY % pe2 '%pe1;'>\n"
+ "%pe2;\n",
+ NULL};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that a parameter entity value ending with a carriage return
+ * has it translated internally into a newline.
+ */
+START_TEST(test_param_entity_with_trailing_cr) {
+#define PARAM_ENTITY_NAME "pe"
+#define PARAM_ENTITY_CORE_VALUE "<!ATTLIST doc att CDATA \"default\">"
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc/>";
+ ExtTest test_data
+ = {"<!ENTITY % " PARAM_ENTITY_NAME " '" PARAM_ENTITY_CORE_VALUE "\r'>\n"
+ "%" PARAM_ENTITY_NAME ";\n",
+ NULL, NULL};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetEntityDeclHandler(g_parser, param_entity_match_handler);
+ param_entity_match_init(XCS(PARAM_ENTITY_NAME),
+ XCS(PARAM_ENTITY_CORE_VALUE) XCS("\n"));
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ int entity_match_flag = get_param_entity_match_flag();
+ if (entity_match_flag == ENTITY_MATCH_FAIL)
+ fail("Parameter entity CR->NEWLINE conversion failed");
+ else if (entity_match_flag == ENTITY_MATCH_NOT_FOUND)
+ fail("Parameter entity not parsed");
+}
+#undef PARAM_ENTITY_NAME
+#undef PARAM_ENTITY_CORE_VALUE
+END_TEST
+
+START_TEST(test_invalid_character_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#x110000;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_BAD_CHAR_REF,
+ "Out of range character reference not faulted");
+}
+END_TEST
+
+START_TEST(test_invalid_character_entity_2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#xg0;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Out of range character reference not faulted");
+}
+END_TEST
+
+START_TEST(test_invalid_character_entity_3) {
+ const char text[] =
+ /* <!DOCTYPE doc [\n */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
+ /* U+0E04 = KHO KHWAI
+ * U+0E08 = CHO CHAN */
+ /* <!ENTITY entity '&\u0e04\u0e08;'>\n */
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0n\0t\0i\0t\0y\0 "
+ "\0'\0&\x0e\x04\x0e\x08\0;\0'\0>\0\n"
+ /* ]>\n */
+ "\0]\0>\0\n"
+ /* <doc>&entity;</doc> */
+ "\0<\0d\0o\0c\0>\0&\0e\0n\0t\0i\0t\0y\0;\0<\0/\0d\0o\0c\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid start of entity name not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_UNDEFINED_ENTITY)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_invalid_character_entity_4) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#1114112;'>\n" /* = &#x110000 */
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_BAD_CHAR_REF,
+ "Out of range character reference not faulted");
+}
+END_TEST
+
+/* Test that processing instructions are picked up by a default handler */
+START_TEST(test_pi_handled_in_default) {
+ const char *text = "<?test processing instruction?>\n<doc/>";
+ const XML_Char *expected = XCS("<?test processing instruction?>\n<doc/>");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that comments are picked up by a default handler */
+START_TEST(test_comment_handled_in_default) {
+ const char *text = "<!-- This is a comment -->\n<doc/>";
+ const XML_Char *expected = XCS("<!-- This is a comment -->\n<doc/>");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test PIs that look almost but not quite like XML declarations */
+START_TEST(test_pi_yml) {
+ const char *text = "<?yml something like data?><doc/>";
+ const XML_Char *expected = XCS("yml: something like data\n");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_pi_xnl) {
+ const char *text = "<?xnl nothing like data?><doc/>";
+ const XML_Char *expected = XCS("xnl: nothing like data\n");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_pi_xmm) {
+ const char *text = "<?xmm everything like data?><doc/>";
+ const XML_Char *expected = XCS("xmm: everything like data\n");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_pi) {
+ const char text[] =
+ /* <?{KHO KHWAI}{CHO CHAN}?>
+ * where {KHO KHWAI} = U+0E04
+ * and {CHO CHAN} = U+0E08
+ */
+ "<\0?\0\x04\x0e\x08\x0e?\0>\0"
+ /* <q/> */
+ "<\0q\0/\0>\0";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x0e04\x0e08: \n");
+#else
+ const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_be_pi) {
+ const char text[] =
+ /* <?{KHO KHWAI}{CHO CHAN}?>
+ * where {KHO KHWAI} = U+0E04
+ * and {CHO CHAN} = U+0E08
+ */
+ "\0<\0?\x0e\x04\x0e\x08\0?\0>"
+ /* <q/> */
+ "\0<\0q\0/\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x0e04\x0e08: \n");
+#else
+ const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that comments can be picked up and translated */
+START_TEST(test_utf16_be_comment) {
+ const char text[] =
+ /* <!-- Comment A --> */
+ "\0<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0A\0 \0-\0-\0>\0\n"
+ /* <doc/> */
+ "\0<\0d\0o\0c\0/\0>";
+ const XML_Char *expected = XCS(" Comment A ");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetCommentHandler(g_parser, accumulate_comment);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_le_comment) {
+ const char text[] =
+ /* <!-- Comment B --> */
+ "<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0B\0 \0-\0-\0>\0\n\0"
+ /* <doc/> */
+ "<\0d\0o\0c\0/\0>\0";
+ const XML_Char *expected = XCS(" Comment B ");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetCommentHandler(g_parser, accumulate_comment);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that the unknown encoding handler with map entries that expect
+ * conversion but no conversion function is faulted
+ */
+START_TEST(test_missing_encoding_conversion_fn) {
+ const char *text = "<?xml version='1.0' encoding='no-conv'?>\n"
+ "<doc>\x81</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ /* MiscEncodingHandler sets up an encoding with every top-bit-set
+ * character introducing a two-byte sequence. For this, it
+ * requires a convert function. The above function call doesn't
+ * pass one through, so when BadEncodingHandler actually gets
+ * called it should supply an invalid encoding.
+ */
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Encoding with missing convert() not faulted");
+}
+END_TEST
+
+START_TEST(test_failing_encoding_conversion_fn) {
+ const char *text = "<?xml version='1.0' encoding='failing-conv'?>\n"
+ "<doc>\x81</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ /* BadEncodingHandler sets up an encoding with every top-bit-set
+ * character introducing a two-byte sequence. For this, it
+ * requires a convert function. The above function call passes
+ * one that insists all possible sequences are invalid anyway.
+ */
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Encoding with failing convert() not faulted");
+}
+END_TEST
+
+/* Test unknown encoding conversions */
+START_TEST(test_unknown_encoding_success) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ /* Equivalent to <eoc>Hello, world</eoc> */
+ "<\x81\x64\x80oc>Hello, world</\x81\x64\x80oc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ run_character_check(text, XCS("Hello, world"));
+}
+END_TEST
+
+/* Test bad name character in unknown encoding */
+START_TEST(test_unknown_encoding_bad_name) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<\xff\x64oc>Hello, world</\xff\x64oc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad name start in unknown encoding not faulted");
+}
+END_TEST
+
+/* Test bad mid-name character in unknown encoding */
+START_TEST(test_unknown_encoding_bad_name_2) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<d\xffoc>Hello, world</d\xffoc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad name in unknown encoding not faulted");
+}
+END_TEST
+
+/* Test element name that is long enough to fill the conversion buffer
+ * in an unknown encoding, finishing with an encoded character.
+ */
+START_TEST(test_unknown_encoding_long_name_1) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>"
+ "Hi"
+ "</abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>";
+ const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test element name that is long enough to fill the conversion buffer
+ * in an unknown encoding, finishing with an simple character.
+ */
+START_TEST(test_unknown_encoding_long_name_2) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<abcdefghabcdefghabcdefghijklmnop>"
+ "Hi"
+ "</abcdefghabcdefghabcdefghijklmnop>";
+ const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_invalid_unknown_encoding) {
+ const char *text = "<?xml version='1.0' encoding='invalid-9'?>\n"
+ "<doc>Hello world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_ascii_encoding_ok) {
+ const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ run_character_check(text, XCS("Hello, world"));
+}
+END_TEST
+
+START_TEST(test_unknown_ascii_encoding_fail) {
+ const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
+ "<doc>Hello, \x80 world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_length) {
+ const char *text = "<?xml version='1.0' encoding='invalid-len'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_topbit) {
+ const char *text = "<?xml version='1.0' encoding='invalid-a'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_surrogate) {
+ const char *text = "<?xml version='1.0' encoding='invalid-surrogate'?>\n"
+ "<doc>Hello, \x82 world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_high) {
+ const char *text = "<?xml version='1.0' encoding='invalid-high'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_attr_value) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<doc attr='\xff\x30'/>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid attribute valid not faulted");
+}
+END_TEST
+
+/* Test an external entity parser set to use latin-1 detects UTF-16
+ * BOMs correctly.
+ */
+/* Test that UTF-16 BOM does not select UTF-16 given explicit encoding */
+START_TEST(test_ext_entity_latin1_utf16le_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00ff\x00feL ");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ext_entity_latin1_utf16be_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00fe\x00ff L");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = XCS("\xc3\xbe\xc3\xbf L");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Parsing the full buffer rather than a byte at a time makes a
+ * difference to the encoding scanning code, so repeat the above tests
+ * without breaking them down by byte.
+ */
+START_TEST(test_ext_entity_latin1_utf16le_bom2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00ff\x00feL ");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ext_entity_latin1_utf16be_bom2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00fe\x00ff L");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = "\xc3\xbe\xc3\xbf L";
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test little-endian UTF-16 given an explicit big-endian encoding */
+START_TEST(test_ext_entity_utf16_be) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data = {"<\0e\0/\0>\0", 8, XCS("utf-16be"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
+#else
+ const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
+ "\xe6\x94\x80" /* U+6500 */
+ "\xe2\xbc\x80" /* U+2F00 */
+ "\xe3\xb8\x80"); /* U+3E00 */
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test big-endian UTF-16 given an explicit little-endian encoding */
+START_TEST(test_ext_entity_utf16_le) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data = {"\0<\0e\0/\0>", 8, XCS("utf-16le"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
+#else
+ const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
+ "\xe6\x94\x80" /* U+6500 */
+ "\xe2\xbc\x80" /* U+2F00 */
+ "\xe3\xb8\x80"); /* U+3E00 */
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test little-endian UTF-16 given no explicit encoding.
+ * The existing default encoding (UTF-8) is assumed to hold without a
+ * BOM to contradict it, so the entity value will in fact provoke an
+ * error because 0x00 is not a valid XML character. We parse the
+ * whole buffer in one go rather than feeding it in byte by byte to
+ * exercise different code paths in the initial scanning routines.
+ */
+START_TEST(test_ext_entity_utf16_unknown) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtFaults2 test_data
+ = {"a\0b\0c\0", 6, "Invalid character in entity not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter2);
+ XML_SetUserData(g_parser, &test_data);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Invalid character should not have been accepted");
+}
+END_TEST
+
+/* Test not-quite-UTF-8 BOM (0xEF 0xBB 0xBF) */
+START_TEST(test_ext_entity_utf8_non_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {"\xef\xbb\x80", /* Arabic letter DAD medial form, U+FEC0 */
+ 3, NULL, NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\xfec0");
+#else
+ const XML_Char *expected = XCS("\xef\xbb\x80");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that UTF-8 in a CDATA section is correctly passed through */
+START_TEST(test_utf8_in_cdata_section) {
+ const char *text = "<doc><![CDATA[one \xc3\xa9 two]]></doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("one \x00e9 two");
+#else
+ const XML_Char *expected = XCS("one \xc3\xa9 two");
+#endif
+
+ run_character_check(text, expected);
+}
+END_TEST
+
+/* Test that little-endian UTF-16 in a CDATA section is handled */
+START_TEST(test_utf8_in_cdata_section_2) {
+ const char *text = "<doc><![CDATA[\xc3\xa9]\xc3\xa9two]]></doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9]\x00e9two");
+#else
+ const XML_Char *expected = XCS("\xc3\xa9]\xc3\xa9two");
+#endif
+
+ run_character_check(text, expected);
+}
+END_TEST
+
+START_TEST(test_utf8_in_start_tags) {
+ struct test_case {
+ bool goodName;
+ bool goodNameStart;
+ const char *tagName;
+ };
+
+ // The idea with the tests below is this:
+ // We want to cover 1-, 2- and 3-byte sequences, 4-byte sequences
+ // go to isNever and are hence not a concern.
+ //
+ // We start with a character that is a valid name character
+ // (or even name-start character, see XML 1.0r4 spec) and then we flip
+ // single bits at places where (1) the result leaves the UTF-8 encoding space
+ // and (2) we stay in the same n-byte sequence family.
+ //
+ // The flipped bits are highlighted in angle brackets in comments,
+ // e.g. "[<1>011 1001]" means we had [0011 1001] but we now flipped
+ // the most significant bit to 1 to leave UTF-8 encoding space.
+ struct test_case cases[] = {
+ // 1-byte UTF-8: [0xxx xxxx]
+ {true, true, "\x3A"}, // [0011 1010] = ASCII colon ':'
+ {false, false, "\xBA"}, // [<1>011 1010]
+ {true, false, "\x39"}, // [0011 1001] = ASCII nine '9'
+ {false, false, "\xB9"}, // [<1>011 1001]
+
+ // 2-byte UTF-8: [110x xxxx] [10xx xxxx]
+ {true, true, "\xDB\xA5"}, // [1101 1011] [1010 0101] =
+ // Arabic small waw U+06E5
+ {false, false, "\x9B\xA5"}, // [1<0>01 1011] [1010 0101]
+ {false, false, "\xDB\x25"}, // [1101 1011] [<0>010 0101]
+ {false, false, "\xDB\xE5"}, // [1101 1011] [1<1>10 0101]
+ {true, false, "\xCC\x81"}, // [1100 1100] [1000 0001] =
+ // combining char U+0301
+ {false, false, "\x8C\x81"}, // [1<0>00 1100] [1000 0001]
+ {false, false, "\xCC\x01"}, // [1100 1100] [<0>000 0001]
+ {false, false, "\xCC\xC1"}, // [1100 1100] [1<1>00 0001]
+
+ // 3-byte UTF-8: [1110 xxxx] [10xx xxxx] [10xxxxxx]
+ {true, true, "\xE0\xA4\x85"}, // [1110 0000] [1010 0100] [1000 0101] =
+ // Devanagari Letter A U+0905
+ {false, false, "\xA0\xA4\x85"}, // [1<0>10 0000] [1010 0100] [1000 0101]
+ {false, false, "\xE0\x24\x85"}, // [1110 0000] [<0>010 0100] [1000 0101]
+ {false, false, "\xE0\xE4\x85"}, // [1110 0000] [1<1>10 0100] [1000 0101]
+ {false, false, "\xE0\xA4\x05"}, // [1110 0000] [1010 0100] [<0>000 0101]
+ {false, false, "\xE0\xA4\xC5"}, // [1110 0000] [1010 0100] [1<1>00 0101]
+ {true, false, "\xE0\xA4\x81"}, // [1110 0000] [1010 0100] [1000 0001] =
+ // combining char U+0901
+ {false, false, "\xA0\xA4\x81"}, // [1<0>10 0000] [1010 0100] [1000 0001]
+ {false, false, "\xE0\x24\x81"}, // [1110 0000] [<0>010 0100] [1000 0001]
+ {false, false, "\xE0\xE4\x81"}, // [1110 0000] [1<1>10 0100] [1000 0001]
+ {false, false, "\xE0\xA4\x01"}, // [1110 0000] [1010 0100] [<0>000 0001]
+ {false, false, "\xE0\xA4\xC1"}, // [1110 0000] [1010 0100] [1<1>00 0001]
+ };
+ const bool atNameStart[] = {true, false};
+
+ size_t i = 0;
+ char doc[1024];
+ size_t failCount = 0;
+
+ // we need all the bytes to be parsed, but we don't want the errors that can
+ // trigger on isFinal=XML_TRUE, so we skip the test if the heuristic is on.
+ if (g_reparseDeferralEnabledDefault) {
+ return;
+ }
+
+ for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ size_t j = 0;
+ for (; j < sizeof(atNameStart) / sizeof(atNameStart[0]); j++) {
+ const bool expectedSuccess
+ = atNameStart[j] ? cases[i].goodNameStart : cases[i].goodName;
+ snprintf(doc, sizeof(doc), "<%s%s><!--", atNameStart[j] ? "" : "a",
+ cases[i].tagName);
+ XML_Parser parser = XML_ParserCreate(NULL);
+
+ const enum XML_Status status = _XML_Parse_SINGLE_BYTES(
+ parser, doc, (int)strlen(doc), /*isFinal=*/XML_FALSE);
+
+ bool success = true;
+ if ((status == XML_STATUS_OK) != expectedSuccess) {
+ success = false;
+ }
+ if ((status == XML_STATUS_ERROR)
+ && (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)) {
+ success = false;
+ }
+
+ if (! success) {
+ fprintf(
+ stderr,
+ "FAIL case %2u (%sat name start, %u-byte sequence, error code %d)\n",
+ (unsigned)i + 1u, atNameStart[j] ? " " : "not ",
+ (unsigned)strlen(cases[i].tagName), XML_GetErrorCode(parser));
+ failCount++;
+ }
+
+ XML_ParserFree(parser);
+ }
+ }
+
+ if (failCount > 0) {
+ fail("UTF-8 regression detected");
+ }
+}
+END_TEST
+
+/* Test trailing spaces in elements are accepted */
+START_TEST(test_trailing_spaces_in_elements) {
+ const char *text = "<doc >Hi</doc >";
+ const XML_Char *expected = XCS("doc/doc");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetElementHandler(g_parser, record_element_start_handler,
+ record_element_end_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_attribute) {
+ const char text[] =
+ /* <d {KHO KHWAI}{CHO CHAN}='a'/>
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ "<\0d\0 \0\x04\x0e\x08\x0e=\0'\0a\0'\0/\0>\0";
+ const XML_Char *expected = XCS("a");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_second_attr) {
+ /* <d a='1' {KHO KHWAI}{CHO CHAN}='2'/>
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ const char text[] = "<\0d\0 \0a\0=\0'\0\x31\0'\0 \0"
+ "\x04\x0e\x08\x0e=\0'\0\x32\0'\0/\0>\0";
+ const XML_Char *expected = XCS("1");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_attr_after_solidus) {
+ const char *text = "<doc attr1='a' / attr2='b'>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN, "Misplaced / not faulted");
+}
+END_TEST
+
+START_TEST(test_utf16_pe) {
+ /* <!DOCTYPE doc [
+ * <!ENTITY % {KHO KHWAI}{CHO CHAN} '<!ELEMENT doc (#PCDATA)>'>
+ * %{KHO KHWAI}{CHO CHAN};
+ * ]>
+ * <doc></doc>
+ *
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ const char text[] = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \x0e\x04\x0e\x08\0 "
+ "\0'\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 "
+ "\0d\0o\0c\0 \0(\0#\0P\0C\0D\0A\0T\0A\0)\0>\0'\0>\0\n"
+ "\0%\x0e\x04\x0e\x08\0;\0\n"
+ "\0]\0>\0\n"
+ "\0<\0d\0o\0c\0>\0<\0/\0d\0o\0c\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x0e04\x0e08=<!ELEMENT doc (#PCDATA)>\n");
+#else
+ const XML_Char *expected
+ = XCS("\xe0\xb8\x84\xe0\xb8\x88=<!ELEMENT doc (#PCDATA)>\n");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetEntityDeclHandler(g_parser, accumulate_entity_decl);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that duff attribute description keywords are rejected */
+START_TEST(test_bad_attr_desc_keyword) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attr CDATA #!IMPLIED>\n"
+ "]>\n"
+ "<doc />";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad keyword !IMPLIED not faulted");
+}
+END_TEST
+
+/* Test that an invalid attribute description keyword consisting of
+ * UTF-16 characters with their top bytes non-zero are correctly
+ * faulted
+ */
+START_TEST(test_bad_attr_desc_keyword_utf16) {
+ /* <!DOCTYPE d [
+ * <!ATTLIST d a CDATA #{KHO KHWAI}{CHO CHAN}>
+ * ]><d/>
+ *
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ const char text[]
+ = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
+ "\0<\0!\0A\0T\0T\0L\0I\0S\0T\0 \0d\0 \0a\0 \0C\0D\0A\0T\0A\0 "
+ "\0#\x0e\x04\x0e\x08\0>\0\n"
+ "\0]\0>\0<\0d\0/\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid UTF16 attribute keyword not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that invalid syntax in a <!DOCTYPE> is rejected. Do this
+ * using prefix-encoding (see above) to trigger specific code paths
+ */
+START_TEST(test_bad_doctype) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<!DOCTYPE doc [ \x80\x44 ]><doc/>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Invalid bytes in DOCTYPE not faulted");
+}
+END_TEST
+
+START_TEST(test_bad_doctype_utf8) {
+ const char *text = "<!DOCTYPE \xDB\x25"
+ "doc><doc/>"; // [1101 1011] [<0>010 0101]
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid UTF-8 in DOCTYPE not faulted");
+}
+END_TEST
+
+START_TEST(test_bad_doctype_utf16) {
+ const char text[] =
+ /* <!DOCTYPE doc [ \x06f2 ]><doc/>
+ *
+ * U+06F2 = EXTENDED ARABIC-INDIC DIGIT TWO, a valid number
+ * (name character) but not a valid letter (name start character)
+ */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0 "
+ "\x06\xf2"
+ "\0 \0]\0>\0<\0d\0o\0c\0/\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid bytes in DOCTYPE not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_bad_doctype_plus) {
+ const char *text = "<!DOCTYPE 1+ [ <!ENTITY foo 'bar'> ]>\n"
+ "<1+>&foo;</1+>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "'+' in document name not faulted");
+}
+END_TEST
+
+START_TEST(test_bad_doctype_star) {
+ const char *text = "<!DOCTYPE 1* [ <!ENTITY foo 'bar'> ]>\n"
+ "<1*>&foo;</1*>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "'*' in document name not faulted");
+}
+END_TEST
+
+START_TEST(test_bad_doctype_query) {
+ const char *text = "<!DOCTYPE 1? [ <!ENTITY foo 'bar'> ]>\n"
+ "<1?>&foo;</1?>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "'?' in document name not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_bad_ignore) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>"
+ "<!DOCTYPE doc SYSTEM 'foo'>"
+ "<doc><e>&entity;</e></doc>";
+ ExtFaults fault = {"<![IGNORE[<!ELEMENT \xffG (#PCDATA)*>]]>",
+ "Invalid character not faulted", XCS("prefix-conv"),
+ XML_ERROR_INVALID_TOKEN};
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad IGNORE section with unknown encoding not failed");
+}
+END_TEST
+
+START_TEST(test_entity_in_utf16_be_attr) {
+ const char text[] =
+ /* <e a='&#228; &#x00E4;'></e> */
+ "\0<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 "
+ "\0&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e4 \x00e4");
+#else
+ const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_entity_in_utf16_le_attr) {
+ const char text[] =
+ /* <e a='&#228; &#x00E4;'></e> */
+ "<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 \0"
+ "&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>\0";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e4 \x00e4");
+#else
+ const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_entity_public_utf16_be) {
+ const char text[] =
+ /* <!DOCTYPE d [ */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
+ /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 "
+ "\0'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n"
+ /* %e; */
+ "\0%\0e\0;\0\n"
+ /* ]> */
+ "\0]\0>\0\n"
+ /* <d>&j;</d> */
+ "\0<\0d\0>\0&\0j\0;\0<\0/\0d\0>";
+ ExtTest2 test_data
+ = {/* <!ENTITY j 'baz'> */
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>", 34, NULL, NULL};
+ const XML_Char *expected = XCS("baz");
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_entity_public_utf16_le) {
+ const char text[] =
+ /* <!DOCTYPE d [ */
+ "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
+ /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
+ "<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 \0"
+ "'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n\0"
+ /* %e; */
+ "%\0e\0;\0\n\0"
+ /* ]> */
+ "]\0>\0\n\0"
+ /* <d>&j;</d> */
+ "<\0d\0>\0&\0j\0;\0<\0/\0d\0>\0";
+ ExtTest2 test_data
+ = {/* <!ENTITY j 'baz'> */
+ "<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>\0", 34, NULL, NULL};
+ const XML_Char *expected = XCS("baz");
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that a doctype with neither an internal nor external subset is
+ * faulted
+ */
+START_TEST(test_short_doctype) {
+ const char *text = "<!DOCTYPE doc></doc>";
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "DOCTYPE without subset not rejected");
+}
+END_TEST
+
+START_TEST(test_short_doctype_2) {
+ const char *text = "<!DOCTYPE doc PUBLIC></doc>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "DOCTYPE without Public ID not rejected");
+}
+END_TEST
+
+START_TEST(test_short_doctype_3) {
+ const char *text = "<!DOCTYPE doc SYSTEM></doc>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "DOCTYPE without System ID not rejected");
+}
+END_TEST
+
+START_TEST(test_long_doctype) {
+ const char *text = "<!DOCTYPE doc PUBLIC 'foo' 'bar' 'baz'></doc>";
+ expect_failure(text, XML_ERROR_SYNTAX, "DOCTYPE with extra ID not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY foo PUBLIC>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+/* Test unquoted value is faulted */
+START_TEST(test_bad_entity_2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY % foo bar>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_entity_3) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY % foo PUBLIC>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Parameter ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_entity_4) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY % foo SYSTEM>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Parameter ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_notation) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!NOTATION n SYSTEM>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Notation without System ID is not rejected");
+}
+END_TEST
+
+/* Test for issue #11, wrongly suppressed default handler */
+START_TEST(test_default_doctype_handler) {
+ const char *text = "<!DOCTYPE doc PUBLIC 'pubname' 'test.dtd' [\n"
+ " <!ENTITY foo 'bar'>\n"
+ "]>\n"
+ "<doc>&foo;</doc>";
+ DefaultCheck test_data[] = {{XCS("'pubname'"), 9, XML_FALSE},
+ {XCS("'test.dtd'"), 10, XML_FALSE},
+ {NULL, 0, XML_FALSE}};
+ int i;
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetDefaultHandler(g_parser, checking_default_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ for (i = 0; test_data[i].expected != NULL; i++)
+ if (! test_data[i].seen)
+ fail("Default handler not run for public !DOCTYPE");
+}
+END_TEST
+
+START_TEST(test_empty_element_abort) {
+ const char *text = "<abort/>";
+
+ XML_SetStartElementHandler(g_parser, start_element_suspender);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Expected to error on abort");
+}
+END_TEST
+
+/* Regression test for GH issue #612: unfinished m_declAttributeType
+ * allocation in ->m_tempPool can corrupt following allocation.
+ */
+START_TEST(test_pool_integrity_with_unfinished_attr) {
+ const char *text = "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<!DOCTYPE foo [\n"
+ "<!ELEMENT foo ANY>\n"
+ "<!ENTITY % entp SYSTEM \"external.dtd\">\n"
+ "%entp;\n"
+ "]>\n"
+ "<a></a>\n";
+ const XML_Char *expected = XCS("COMMENT");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_unfinished_attlist);
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ XML_SetCommentHandler(g_parser, accumulate_comment);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_nested_entity_suspend) {
+ const char *const text = "<!DOCTYPE a [\n"
+ " <!ENTITY e1 '<!--e1-->'>\n"
+ " <!ENTITY e2 '<!--e2 head-->&e1;<!--e2 tail-->'>\n"
+ " <!ENTITY e3 '<!--e3 head-->&e2;<!--e3 tail-->'>\n"
+ "]>\n"
+ "<a><!--start-->&e3;<!--end--></a>";
+ const XML_Char *const expected = XCS("start") XCS("e3 head") XCS("e2 head")
+ XCS("e1") XCS("e2 tail") XCS("e3 tail") XCS("end");
+ CharData storage;
+ CharData_Init(&storage);
+ XML_Parser parser = XML_ParserCreate(NULL);
+ ParserPlusStorage parserPlusStorage = {parser, &storage};
+
+ XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetCommentHandler(parser, accumulate_and_suspend_comment_handler);
+ XML_SetUserData(parser, &parserPlusStorage);
+
+ enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE);
+ while (status == XML_STATUS_SUSPENDED) {
+ status = XML_ResumeParser(parser);
+ }
+ if (status != XML_STATUS_OK)
+ xml_failure(parser);
+
+ CharData_CheckXMLChars(&storage, expected);
+ XML_ParserFree(parser);
+}
+END_TEST
+
+/* Regression test for quadratic parsing on large tokens */
+START_TEST(test_big_tokens_take_linear_time) {
+ const char *const too_slow_failure_message
+ = "Compared to the baseline runtime of the first test, this test has a "
+ "slowdown of more than <max_slowdown>. "
+ "Please keep increasing the value by 1 until it reliably passes the "
+ "test on your hardware and open a bug sharing that number with us. "
+ "Thanks in advance!";
+ const struct {
+ const char *pre;
+ const char *post;
+ } text[] = {
+ {"<a>", "</a>"}, // assumed good, used as baseline
+ {"<b><![CDATA[ value: ", " ]]></b>"}, // CDATA, performed OK before patch
+ {"<c attr='", "'></c>"}, // big attribute, used to be O(N²)
+ {"<d><!-- ", " --></d>"}, // long comment, used to be O(N²)
+ {"<e><", "/></e>"}, // big elem name, used to be O(N²)
+ };
+ const int num_cases = sizeof(text) / sizeof(text[0]);
+ // For the test we need a <max_slowdown> value that is:
+ // (1) big enough that the test passes reliably (avoiding flaky tests), and
+ // (2) small enough that the test actually catches regressions.
+ const int max_slowdown = 15;
+ char aaaaaa[4096];
+ const int fillsize = (int)sizeof(aaaaaa);
+ const int fillcount = 100;
+
+ memset(aaaaaa, 'a', fillsize);
+
+ if (! g_reparseDeferralEnabledDefault) {
+ return; // heuristic is disabled; we would get O(n^2) and fail.
+ }
+#if ! defined(__linux__)
+ if (CLOCKS_PER_SEC < 100000) {
+ // Skip this test if clock() doesn't have reasonably good resolution.
+ // This workaround is primarily targeting Windows and FreeBSD, since
+ // XSI requires the value to be 1.000.000 (10x the condition here), and
+ // we want to be very sure that at least one platform in CI can catch
+ // regressions (through a failing test).
+ return;
+ }
+#endif
+
+ clock_t baseline = 0;
+ for (int i = 0; i < num_cases; ++i) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ enum XML_Status status;
+ set_subtest("max_slowdown=%d text=\"%saaaaaa%s\"", max_slowdown,
+ text[i].pre, text[i].post);
+ const clock_t start = clock();
+
+ // parse the start text
+ status = _XML_Parse_SINGLE_BYTES(parser, text[i].pre,
+ (int)strlen(text[i].pre), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ // parse lots of 'a', failing the test early if it takes too long
+ for (int f = 0; f < fillcount; ++f) {
+ status = _XML_Parse_SINGLE_BYTES(parser, aaaaaa, fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ // i == 0 means we're still calculating the baseline value
+ if (i > 0) {
+ const clock_t now = clock();
+ const clock_t clocks_so_far = now - start;
+ const int slowdown = clocks_so_far / baseline;
+ if (slowdown >= max_slowdown) {
+ fprintf(
+ stderr,
+ "fill#%d: clocks_so_far=%d baseline=%d slowdown=%d max_slowdown=%d\n",
+ f, (int)clocks_so_far, (int)baseline, slowdown, max_slowdown);
+ fail(too_slow_failure_message);
+ }
+ }
+ }
+ // parse the end text
+ status = _XML_Parse_SINGLE_BYTES(parser, text[i].post,
+ (int)strlen(text[i].post), XML_TRUE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+
+ // how long did it take in total?
+ const clock_t end = clock();
+ const clock_t taken = end - start;
+ if (i == 0) {
+ assert_true(taken > 0); // just to make sure we don't div-by-0 later
+ baseline = taken;
+ }
+ const int slowdown = taken / baseline;
+ if (slowdown >= max_slowdown) {
+ fprintf(stderr, "taken=%d baseline=%d slowdown=%d max_slowdown=%d\n",
+ (int)taken, (int)baseline, slowdown, max_slowdown);
+ fail(too_slow_failure_message);
+ }
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+START_TEST(test_set_reparse_deferral) {
+ const char *const pre = "<d>";
+ const char *const start = "<x attr='";
+ const char *const end = "'></x>";
+ char eeeeee[100];
+ const int fillsize = (int)sizeof(eeeeee);
+ memset(eeeeee, 'e', fillsize);
+
+ for (int enabled = 0; enabled <= 1; enabled += 1) {
+ set_subtest("deferral=%d", enabled);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ assert_true(XML_SetReparseDeferralEnabled(parser, enabled));
+ // pre-grow the buffer to avoid reparsing due to almost-fullness
+ assert_true(XML_GetBuffer(parser, fillsize * 10103) != NULL);
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(parser, &storage);
+ XML_SetStartElementHandler(parser, start_element_event_handler);
+
+ enum XML_Status status;
+ // parse the start text
+ status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ CharData_CheckXMLChars(&storage, XCS("d")); // first element should be done
+
+ // ..and the start of the token
+ status = XML_Parse(parser, start, (int)strlen(start), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ CharData_CheckXMLChars(&storage, XCS("d")); // still just the first one
+
+ // try to parse lots of 'e', but the token isn't finished
+ for (int c = 0; c < 100; ++c) {
+ status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ }
+ CharData_CheckXMLChars(&storage, XCS("d")); // *still* just the first one
+
+ // end the <x> token.
+ status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+
+ if (enabled) {
+ // In general, we may need to push more data to trigger a reparse attempt,
+ // but in this test, the data is constructed to always require it.
+ CharData_CheckXMLChars(&storage, XCS("d")); // or the test is incorrect
+ // 2x the token length should suffice; the +1 covers the start and end.
+ for (int c = 0; c < 101; ++c) {
+ status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ }
+ }
+ CharData_CheckXMLChars(&storage, XCS("dx")); // the <x> should be done
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+struct element_decl_data {
+ XML_Parser parser;
+ int count;
+};
+
+static void
+element_decl_counter(void *userData, const XML_Char *name, XML_Content *model) {
+ UNUSED_P(name);
+ struct element_decl_data *testdata = (struct element_decl_data *)userData;
+ testdata->count += 1;
+ XML_FreeContentModel(testdata->parser, model);
+}
+
+static int
+external_inherited_parser(XML_Parser p, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ const char *const pre = "<!ELEMENT document ANY>\n";
+ const char *const start = "<!ELEMENT ";
+ const char *const end = " ANY>\n";
+ const char *const post = "<!ELEMENT xyz ANY>\n";
+ const int enabled = *(int *)XML_GetUserData(p);
+ char eeeeee[100];
+ char spaces[100];
+ const int fillsize = (int)sizeof(eeeeee);
+ assert_true(fillsize == (int)sizeof(spaces));
+ memset(eeeeee, 'e', fillsize);
+ memset(spaces, ' ', fillsize);
+
+ XML_Parser parser = XML_ExternalEntityParserCreate(p, context, NULL);
+ assert_true(parser != NULL);
+ // pre-grow the buffer to avoid reparsing due to almost-fullness
+ assert_true(XML_GetBuffer(parser, fillsize * 10103) != NULL);
+
+ struct element_decl_data testdata;
+ testdata.parser = parser;
+ testdata.count = 0;
+ XML_SetUserData(parser, &testdata);
+ XML_SetElementDeclHandler(parser, element_decl_counter);
+
+ enum XML_Status status;
+ // parse the initial text
+ status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ assert_true(testdata.count == 1); // first element should be done
+
+ // ..and the start of the big token
+ status = XML_Parse(parser, start, (int)strlen(start), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ assert_true(testdata.count == 1); // still just the first one
+
+ // try to parse lots of 'e', but the token isn't finished
+ for (int c = 0; c < 100; ++c) {
+ status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ }
+ assert_true(testdata.count == 1); // *still* just the first one
+
+ // end the big token.
+ status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+
+ if (enabled) {
+ // In general, we may need to push more data to trigger a reparse attempt,
+ // but in this test, the data is constructed to always require it.
+ assert_true(testdata.count == 1); // or the test is incorrect
+ // 2x the token length should suffice; the +1 covers the start and end.
+ for (int c = 0; c < 101; ++c) {
+ status = XML_Parse(parser, spaces, fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ }
+ }
+ assert_true(testdata.count == 2); // the big token should be done
+
+ // parse the final text
+ status = XML_Parse(parser, post, (int)strlen(post), XML_TRUE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ assert_true(testdata.count == 3); // after isFinal=XML_TRUE, all must be done
+
+ XML_ParserFree(parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_reparse_deferral_is_inherited) {
+ const char *const text
+ = "<!DOCTYPE document SYSTEM 'something.ext'><document/>";
+ for (int enabled = 0; enabled <= 1; ++enabled) {
+ set_subtest("deferral=%d", enabled);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ XML_SetUserData(parser, (void *)&enabled);
+ XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ // this handler creates a sub-parser and checks that its deferral behavior
+ // is what we expected, based on the value of `enabled` (in userdata).
+ XML_SetExternalEntityRefHandler(parser, external_inherited_parser);
+ assert_true(XML_SetReparseDeferralEnabled(parser, enabled));
+ if (XML_Parse(parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+START_TEST(test_set_reparse_deferral_on_null_parser) {
+ assert_true(XML_SetReparseDeferralEnabled(NULL, 0) == XML_FALSE);
+ assert_true(XML_SetReparseDeferralEnabled(NULL, 1) == XML_FALSE);
+ assert_true(XML_SetReparseDeferralEnabled(NULL, 10) == XML_FALSE);
+ assert_true(XML_SetReparseDeferralEnabled(NULL, 100) == XML_FALSE);
+ assert_true(XML_SetReparseDeferralEnabled(NULL, (XML_Bool)INT_MIN)
+ == XML_FALSE);
+ assert_true(XML_SetReparseDeferralEnabled(NULL, (XML_Bool)INT_MAX)
+ == XML_FALSE);
+}
+END_TEST
+
+START_TEST(test_set_reparse_deferral_on_the_fly) {
+ const char *const pre = "<d><x attr='";
+ const char *const end = "'></x>";
+ char iiiiii[100];
+ const int fillsize = (int)sizeof(iiiiii);
+ memset(iiiiii, 'i', fillsize);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ assert_true(XML_SetReparseDeferralEnabled(parser, XML_TRUE));
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(parser, &storage);
+ XML_SetStartElementHandler(parser, start_element_event_handler);
+
+ enum XML_Status status;
+ // parse the start text
+ status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ CharData_CheckXMLChars(&storage, XCS("d")); // first element should be done
+
+ // try to parse some 'i', but the token isn't finished
+ status = XML_Parse(parser, iiiiii, fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ CharData_CheckXMLChars(&storage, XCS("d")); // *still* just the first one
+
+ // end the <x> token.
+ status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ CharData_CheckXMLChars(&storage, XCS("d")); // not yet.
+
+ // now change the heuristic setting and add *no* data
+ assert_true(XML_SetReparseDeferralEnabled(parser, XML_FALSE));
+ // we avoid isFinal=XML_TRUE, because that would force-bypass the heuristic.
+ status = XML_Parse(parser, "", 0, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ CharData_CheckXMLChars(&storage, XCS("dx"));
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_set_bad_reparse_option) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 2));
+ assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 3));
+ assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 99));
+ assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 127));
+ assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 128));
+ assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 129));
+ assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 255));
+ assert_true(XML_TRUE == XML_SetReparseDeferralEnabled(parser, 0));
+ assert_true(XML_TRUE == XML_SetReparseDeferralEnabled(parser, 1));
+ XML_ParserFree(parser);
+}
+END_TEST
+
+static size_t g_totalAlloc = 0;
+static size_t g_biggestAlloc = 0;
+
+static void *
+counting_realloc(void *ptr, size_t size) {
+ g_totalAlloc += size;
+ if (size > g_biggestAlloc) {
+ g_biggestAlloc = size;
+ }
+ return realloc(ptr, size);
+}
+
+static void *
+counting_malloc(size_t size) {
+ return counting_realloc(NULL, size);
+}
+
+START_TEST(test_bypass_heuristic_when_close_to_bufsize) {
+ if (g_chunkSize != 0) {
+ // this test does not use SINGLE_BYTES, because it depends on very precise
+ // buffer fills.
+ return;
+ }
+ if (! g_reparseDeferralEnabledDefault) {
+ return; // this test is irrelevant when the deferral heuristic is disabled.
+ }
+
+ const int document_length = 65536;
+ char *const document = (char *)malloc(document_length);
+
+ const XML_Memory_Handling_Suite memfuncs = {
+ counting_malloc,
+ counting_realloc,
+ free,
+ };
+
+ const int leading_list[] = {0, 3, 61, 96, 400, 401, 4000, 4010, 4099, -1};
+ const int bigtoken_list[] = {3000, 4000, 4001, 4096, 4099, 5000, 20000, -1};
+ const int fillsize_list[] = {131, 256, 399, 400, 401, 1025, 4099, 4321, -1};
+
+ for (const int *leading = leading_list; *leading >= 0; leading++) {
+ for (const int *bigtoken = bigtoken_list; *bigtoken >= 0; bigtoken++) {
+ for (const int *fillsize = fillsize_list; *fillsize >= 0; fillsize++) {
+ set_subtest("leading=%d bigtoken=%d fillsize=%d", *leading, *bigtoken,
+ *fillsize);
+ // start by checking that the test looks reasonably valid
+ assert_true(*leading + *bigtoken <= document_length);
+
+ // put 'x' everywhere; some will be overwritten by elements.
+ memset(document, 'x', document_length);
+ // maybe add an initial tag
+ if (*leading) {
+ assert_true(*leading >= 3); // or the test case is invalid
+ memcpy(document, "<a>", 3);
+ }
+ // add the large token
+ document[*leading + 0] = '<';
+ document[*leading + 1] = 'b';
+ memset(&document[*leading + 2], ' ', *bigtoken - 2); // a spacy token
+ document[*leading + *bigtoken - 1] = '>';
+
+ // 1 for 'b', plus 1 or 0 depending on the presence of 'a'
+ const int expected_elem_total = 1 + (*leading ? 1 : 0);
+
+ XML_Parser parser = XML_ParserCreate_MM(NULL, &memfuncs, NULL);
+ assert_true(parser != NULL);
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(parser, &storage);
+ XML_SetStartElementHandler(parser, start_element_event_handler);
+
+ g_biggestAlloc = 0;
+ g_totalAlloc = 0;
+ int offset = 0;
+ // fill data until the big token is covered (but not necessarily parsed)
+ while (offset < *leading + *bigtoken) {
+ assert_true(offset + *fillsize <= document_length);
+ const enum XML_Status status
+ = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ offset += *fillsize;
+ }
+ // Now, check that we've had a buffer allocation that could fit the
+ // context bytes and our big token. In order to detect a special case,
+ // we need to know how many bytes of our big token were included in the
+ // first push that contained _any_ bytes of the big token:
+ const int bigtok_first_chunk_bytes = *fillsize - (*leading % *fillsize);
+ if (bigtok_first_chunk_bytes >= *bigtoken && XML_CONTEXT_BYTES == 0) {
+ // Special case: we aren't saving any context, and the whole big token
+ // was covered by a single fill, so Expat may have parsed directly
+ // from our input pointer, without allocating an internal buffer.
+ } else if (*leading < XML_CONTEXT_BYTES) {
+ assert_true(g_biggestAlloc >= *leading + (size_t)*bigtoken);
+ } else {
+ assert_true(g_biggestAlloc >= XML_CONTEXT_BYTES + (size_t)*bigtoken);
+ }
+ // fill data until the big token is actually parsed
+ while (storage.count < expected_elem_total) {
+ const size_t alloc_before = g_totalAlloc;
+ assert_true(offset + *fillsize <= document_length);
+ const enum XML_Status status
+ = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ offset += *fillsize;
+ // since all the bytes of the big token are already in the buffer,
+ // the bufsize ceiling should make us finish its parsing without any
+ // further buffer allocations. We assume that there will be no other
+ // large allocations in this test.
+ assert_true(g_totalAlloc - alloc_before < 4096);
+ }
+ // test-the-test: was our alloc even called?
+ assert_true(g_totalAlloc > 0);
+ // test-the-test: there shouldn't be any extra start elements
+ assert_true(storage.count == expected_elem_total);
+
+ XML_ParserFree(parser);
+ }
+ }
+ }
+ free(document);
+}
+END_TEST
+
+START_TEST(test_varying_buffer_fills) {
+ const int KiB = 1024;
+ const int MiB = 1024 * KiB;
+ const int document_length = 16 * MiB;
+ const int big = 7654321; // arbitrarily chosen between 4 and 8 MiB
+
+ if (g_chunkSize != 0) {
+ return; // this test is slow, and doesn't use _XML_Parse_SINGLE_BYTES().
+ }
+
+ char *const document = (char *)malloc(document_length);
+ assert_true(document != NULL);
+ memset(document, 'x', document_length);
+ document[0] = '<';
+ document[1] = 't';
+ memset(&document[2], ' ', big - 2); // a very spacy token
+ document[big - 1] = '>';
+
+ // Each testcase is a list of buffer fill sizes, terminated by a value < 0.
+ // When reparse deferral is enabled, the final (negated) value is the expected
+ // maximum number of bytes scanned in parse attempts.
+ const int testcases[][30] = {
+ {8 * MiB, -8 * MiB},
+ {4 * MiB, 4 * MiB, -12 * MiB}, // try at 4MB, then 8MB = 12 MB total
+ // zero-size fills shouldn't trigger the bypass
+ {4 * MiB, 0, 4 * MiB, -12 * MiB},
+ {4 * MiB, 0, 0, 4 * MiB, -12 * MiB},
+ {4 * MiB, 0, 1 * MiB, 0, 3 * MiB, -12 * MiB},
+ // try to hit the buffer ceiling only once (at the end)
+ {4 * MiB, 2 * MiB, 1 * MiB, 512 * KiB, 256 * KiB, 256 * KiB, -12 * MiB},
+ // try to hit the same buffer ceiling multiple times
+ {4 * MiB + 1, 2 * MiB, 1 * MiB, 512 * KiB, -25 * MiB},
+
+ // try to hit every ceiling, by always landing 1K shy of the buffer size
+ {1 * KiB, 2 * KiB, 4 * KiB, 8 * KiB, 16 * KiB, 32 * KiB, 64 * KiB,
+ 128 * KiB, 256 * KiB, 512 * KiB, 1 * MiB, 2 * MiB, 4 * MiB, -16 * MiB},
+
+ // try to avoid every ceiling, by always landing 1B past the buffer size
+ // the normal 2x heuristic threshold still forces parse attempts.
+ {2 * KiB + 1, // will attempt 2KiB + 1 ==> total 2KiB + 1
+ 2 * KiB, 4 * KiB, // will attempt 8KiB + 1 ==> total 10KiB + 2
+ 8 * KiB, 16 * KiB, // will attempt 32KiB + 1 ==> total 42KiB + 3
+ 32 * KiB, 64 * KiB, // will attempt 128KiB + 1 ==> total 170KiB + 4
+ 128 * KiB, 256 * KiB, // will attempt 512KiB + 1 ==> total 682KiB + 5
+ 512 * KiB, 1 * MiB, // will attempt 2MiB + 1 ==> total 2M + 682K + 6
+ 2 * MiB, 4 * MiB, // will attempt 8MiB + 1 ==> total 10M + 682K + 7
+ -(10 * MiB + 682 * KiB + 7)},
+ // try to avoid every ceiling again, except on our last fill.
+ {2 * KiB + 1, // will attempt 2KiB + 1 ==> total 2KiB + 1
+ 2 * KiB, 4 * KiB, // will attempt 8KiB + 1 ==> total 10KiB + 2
+ 8 * KiB, 16 * KiB, // will attempt 32KiB + 1 ==> total 42KiB + 3
+ 32 * KiB, 64 * KiB, // will attempt 128KiB + 1 ==> total 170KiB + 4
+ 128 * KiB, 256 * KiB, // will attempt 512KiB + 1 ==> total 682KiB + 5
+ 512 * KiB, 1 * MiB, // will attempt 2MiB + 1 ==> total 2M + 682K + 6
+ 2 * MiB, 4 * MiB - 1, // will attempt 8MiB ==> total 10M + 682K + 6
+ -(10 * MiB + 682 * KiB + 6)},
+
+ // try to hit ceilings on the way multiple times
+ {512 * KiB + 1, 256 * KiB, 128 * KiB, 128 * KiB - 1, // 1 MiB buffer
+ 512 * KiB + 1, 256 * KiB, 128 * KiB, 128 * KiB - 1, // 2 MiB buffer
+ 1 * MiB + 1, 512 * KiB, 256 * KiB, 256 * KiB - 1, // 4 MiB buffer
+ 2 * MiB + 1, 1 * MiB, 512 * KiB, // 8 MiB buffer
+ // we'll make a parse attempt at every parse call
+ -(45 * MiB + 12)},
+ };
+ const int testcount = sizeof(testcases) / sizeof(testcases[0]);
+ for (int test_i = 0; test_i < testcount; test_i++) {
+ const int *fillsize = testcases[test_i];
+ set_subtest("#%d {%d %d %d %d ...}", test_i, fillsize[0], fillsize[1],
+ fillsize[2], fillsize[3]);
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ g_parseAttempts = 0;
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(parser, &storage);
+ XML_SetStartElementHandler(parser, start_element_event_handler);
+
+ int worstcase_bytes = 0; // sum of (buffered bytes at each XML_Parse call)
+ int scanned_bytes = 0; // sum of (buffered bytes at each actual parse)
+ int offset = 0;
+ while (*fillsize >= 0) {
+ assert_true(offset + *fillsize <= document_length); // or test is invalid
+ const unsigned attempts_before = g_parseAttempts;
+ const enum XML_Status status
+ = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE);
+ if (status != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+ offset += *fillsize;
+ fillsize++;
+ assert_true(offset <= INT_MAX - worstcase_bytes); // avoid overflow
+ worstcase_bytes += offset; // we might've tried to parse all pending bytes
+ if (g_parseAttempts != attempts_before) {
+ assert_true(g_parseAttempts == attempts_before + 1); // max 1/XML_Parse
+ assert_true(offset <= INT_MAX - scanned_bytes); // avoid overflow
+ scanned_bytes += offset; // we *did* try to parse all pending bytes
+ }
+ }
+ assert_true(storage.count == 1); // the big token should've been parsed
+ assert_true(scanned_bytes > 0); // test-the-test: does our counter work?
+ if (g_reparseDeferralEnabledDefault) {
+ // heuristic is enabled; some XML_Parse calls may have deferred reparsing
+ const int max_bytes_scanned = -*fillsize;
+ if (scanned_bytes > max_bytes_scanned) {
+ fprintf(stderr,
+ "bytes scanned in parse attempts: actual=%d limit=%d \n",
+ scanned_bytes, max_bytes_scanned);
+ fail("too many bytes scanned in parse attempts");
+ }
+ assert_true(scanned_bytes <= worstcase_bytes);
+ } else {
+ // heuristic is disabled; every XML_Parse() will have reparsed
+ assert_true(scanned_bytes == worstcase_bytes);
+ }
+
+ XML_ParserFree(parser);
+ }
+ free(document);
+}
+END_TEST
+
+void
+make_basic_test_case(Suite *s) {
+ TCase *tc_basic = tcase_create("basic tests");
+
+ suite_add_tcase(s, tc_basic);
+ tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
+
+ tcase_add_test(tc_basic, test_nul_byte);
+ tcase_add_test(tc_basic, test_u0000_char);
+ tcase_add_test(tc_basic, test_siphash_self);
+ tcase_add_test(tc_basic, test_siphash_spec);
+ tcase_add_test(tc_basic, test_bom_utf8);
+ tcase_add_test(tc_basic, test_bom_utf16_be);
+ tcase_add_test(tc_basic, test_bom_utf16_le);
+ tcase_add_test(tc_basic, test_nobom_utf16_le);
+ tcase_add_test(tc_basic, test_hash_collision);
+ tcase_add_test(tc_basic, test_illegal_utf8);
+ tcase_add_test(tc_basic, test_utf8_auto_align);
+ tcase_add_test(tc_basic, test_utf16);
+ tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
+ tcase_add_test(tc_basic, test_not_utf16);
+ tcase_add_test(tc_basic, test_bad_encoding);
+ tcase_add_test(tc_basic, test_latin1_umlauts);
+ tcase_add_test(tc_basic, test_long_utf8_character);
+ tcase_add_test(tc_basic, test_long_latin1_attribute);
+ tcase_add_test(tc_basic, test_long_ascii_attribute);
+ /* Regression test for SF bug #491986. */
+ tcase_add_test(tc_basic, test_danish_latin1);
+ /* Regression test for SF bug #514281. */
+ tcase_add_test(tc_basic, test_french_charref_hexidecimal);
+ tcase_add_test(tc_basic, test_french_charref_decimal);
+ tcase_add_test(tc_basic, test_french_latin1);
+ tcase_add_test(tc_basic, test_french_utf8);
+ tcase_add_test(tc_basic, test_utf8_false_rejection);
+ tcase_add_test(tc_basic, test_line_number_after_parse);
+ tcase_add_test(tc_basic, test_column_number_after_parse);
+ tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
+ tcase_add_test(tc_basic, test_line_number_after_error);
+ tcase_add_test(tc_basic, test_column_number_after_error);
+ tcase_add_test(tc_basic, test_really_long_lines);
+ tcase_add_test(tc_basic, test_really_long_encoded_lines);
+ tcase_add_test(tc_basic, test_end_element_events);
+ tcase_add_test(tc_basic, test_helper_is_whitespace_normalized);
+ tcase_add_test(tc_basic, test_attr_whitespace_normalization);
+ tcase_add_test(tc_basic, test_xmldecl_misplaced);
+ tcase_add_test(tc_basic, test_xmldecl_invalid);
+ tcase_add_test(tc_basic, test_xmldecl_missing_attr);
+ tcase_add_test(tc_basic, test_xmldecl_missing_value);
+ tcase_add_test__if_xml_ge(tc_basic, test_unknown_encoding_internal_entity);
+ tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_no_handler);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_bom);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding_2);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_unread_external_subset);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
+ tcase_add_test(tc_basic,
+ test_wfc_undeclared_entity_with_external_subset_standalone);
+ tcase_add_test(tc_basic, test_entity_with_external_subset_unless_standalone);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
+ tcase_add_test(tc_basic, test_not_standalone_handler_reject);
+ tcase_add_test(tc_basic, test_not_standalone_handler_accept);
+ tcase_add_test__if_xml_ge(tc_basic, test_wfc_no_recursive_entity_refs);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
+ tcase_add_test__if_xml_ge(tc_basic, test_dtd_default_handling);
+ tcase_add_test(tc_basic, test_dtd_attr_handling);
+ tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
+ tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
+ tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
+ tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
+ tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls);
+ tcase_add_test(tc_basic, test_good_cdata_ascii);
+ tcase_add_test(tc_basic, test_good_cdata_utf16);
+ tcase_add_test(tc_basic, test_good_cdata_utf16_le);
+ tcase_add_test(tc_basic, test_long_cdata_utf16);
+ tcase_add_test(tc_basic, test_multichar_cdata_utf16);
+ tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair);
+ tcase_add_test(tc_basic, test_bad_cdata);
+ tcase_add_test(tc_basic, test_bad_cdata_utf16);
+ tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls);
+ tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls);
+ tcase_add_test(tc_basic, test_memory_allocation);
+ tcase_add_test__if_xml_ge(tc_basic, test_default_current);
+ tcase_add_test(tc_basic, test_dtd_elements);
+ tcase_add_test(tc_basic, test_dtd_elements_nesting);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_with_doctype);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_foreign_dtd_without_external_subset);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd);
+ tcase_add_test(tc_basic, test_set_base);
+ tcase_add_test(tc_basic, test_attributes);
+ tcase_add_test__if_xml_ge(tc_basic, test_reset_in_entity);
+ tcase_add_test(tc_basic, test_resume_invalid_parse);
+ tcase_add_test(tc_basic, test_resume_resuspended);
+ tcase_add_test(tc_basic, test_cdata_default);
+ tcase_add_test(tc_basic, test_subordinate_reset);
+ tcase_add_test(tc_basic, test_subordinate_suspend);
+ tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_suspend);
+ tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_abort);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_ext_entity_invalid_suspended_parse);
+ tcase_add_test(tc_basic, test_explicit_encoding);
+ tcase_add_test(tc_basic, test_trailing_cr);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_trailing_cr);
+ tcase_add_test(tc_basic, test_trailing_rsqb);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_trailing_rsqb);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_good_cdata);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_user_parameters);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_ref_parameter);
+ tcase_add_test(tc_basic, test_empty_parse);
+ tcase_add_test(tc_basic, test_get_buffer_1);
+ tcase_add_test(tc_basic, test_get_buffer_2);
+#if XML_CONTEXT_BYTES > 0
+ tcase_add_test(tc_basic, test_get_buffer_3_overflow);
+#endif
+ tcase_add_test(tc_basic, test_buffer_can_grow_to_max);
+ tcase_add_test(tc_basic, test_getbuffer_allocates_on_zero_len);
+ tcase_add_test(tc_basic, test_byte_info_at_end);
+ tcase_add_test(tc_basic, test_byte_info_at_error);
+ tcase_add_test(tc_basic, test_byte_info_at_cdata);
+ tcase_add_test(tc_basic, test_predefined_entities);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_tag_in_dtd);
+ tcase_add_test(tc_basic, test_not_predefined_entities);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16_be);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_bad_ignore_section);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_bom_consumed);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_entity_values);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_not_standalone);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_value_abort);
+ tcase_add_test(tc_basic, test_bad_public_doctype);
+ tcase_add_test(tc_basic, test_attribute_enum_value);
+ tcase_add_test(tc_basic, test_predefined_entity_redefinition);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_dtd_stop_processing);
+ tcase_add_test(tc_basic, test_public_notation_no_sysid);
+ tcase_add_test(tc_basic, test_nested_groups);
+ tcase_add_test(tc_basic, test_group_choice);
+ tcase_add_test(tc_basic, test_standalone_parameter_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_skipped_parameter_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_recursive_external_parameter_entity);
+ tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd);
+ tcase_add_test(tc_basic, test_suspend_xdecl);
+ tcase_add_test(tc_basic, test_abort_epilog);
+ tcase_add_test(tc_basic, test_abort_epilog_2);
+ tcase_add_test(tc_basic, test_suspend_epilog);
+ tcase_add_test(tc_basic, test_suspend_in_sole_empty_tag);
+ tcase_add_test(tc_basic, test_unfinished_epilog);
+ tcase_add_test(tc_basic, test_partial_char_in_epilog);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_internal_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_suspend_resume_internal_entity_issue_629);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_resume_entity_with_syntax_error);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_parameter_entity);
+ tcase_add_test(tc_basic, test_restart_on_error);
+ tcase_add_test(tc_basic, test_reject_lt_in_attribute_value);
+ tcase_add_test(tc_basic, test_reject_unfinished_param_in_att_value);
+ tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
+ tcase_add_test(tc_basic, test_standalone_internal_entity);
+ tcase_add_test(tc_basic, test_skipped_external_entity);
+ tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
+ tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr);
+ tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity);
+ tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_2);
+ tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_3);
+ tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_4);
+ tcase_add_test(tc_basic, test_pi_handled_in_default);
+ tcase_add_test(tc_basic, test_comment_handled_in_default);
+ tcase_add_test(tc_basic, test_pi_yml);
+ tcase_add_test(tc_basic, test_pi_xnl);
+ tcase_add_test(tc_basic, test_pi_xmm);
+ tcase_add_test(tc_basic, test_utf16_pi);
+ tcase_add_test(tc_basic, test_utf16_be_pi);
+ tcase_add_test(tc_basic, test_utf16_be_comment);
+ tcase_add_test(tc_basic, test_utf16_le_comment);
+ tcase_add_test(tc_basic, test_missing_encoding_conversion_fn);
+ tcase_add_test(tc_basic, test_failing_encoding_conversion_fn);
+ tcase_add_test(tc_basic, test_unknown_encoding_success);
+ tcase_add_test(tc_basic, test_unknown_encoding_bad_name);
+ tcase_add_test(tc_basic, test_unknown_encoding_bad_name_2);
+ tcase_add_test(tc_basic, test_unknown_encoding_long_name_1);
+ tcase_add_test(tc_basic, test_unknown_encoding_long_name_2);
+ tcase_add_test(tc_basic, test_invalid_unknown_encoding);
+ tcase_add_test(tc_basic, test_unknown_ascii_encoding_ok);
+ tcase_add_test(tc_basic, test_unknown_ascii_encoding_fail);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_length);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_topbit);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_high);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom2);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom2);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_be);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_le);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_unknown);
+ tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf8_non_bom);
+ tcase_add_test(tc_basic, test_utf8_in_cdata_section);
+ tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
+ tcase_add_test(tc_basic, test_utf8_in_start_tags);
+ tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
+ tcase_add_test(tc_basic, test_utf16_attribute);
+ tcase_add_test(tc_basic, test_utf16_second_attr);
+ tcase_add_test(tc_basic, test_attr_after_solidus);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_utf16_pe);
+ tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
+ tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
+ tcase_add_test(tc_basic, test_bad_doctype);
+ tcase_add_test(tc_basic, test_bad_doctype_utf8);
+ tcase_add_test(tc_basic, test_bad_doctype_utf16);
+ tcase_add_test(tc_basic, test_bad_doctype_plus);
+ tcase_add_test(tc_basic, test_bad_doctype_star);
+ tcase_add_test(tc_basic, test_bad_doctype_query);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_unknown_encoding_bad_ignore);
+ tcase_add_test(tc_basic, test_entity_in_utf16_be_attr);
+ tcase_add_test(tc_basic, test_entity_in_utf16_le_attr);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_be);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_le);
+ tcase_add_test(tc_basic, test_short_doctype);
+ tcase_add_test(tc_basic, test_short_doctype_2);
+ tcase_add_test(tc_basic, test_short_doctype_3);
+ tcase_add_test(tc_basic, test_long_doctype);
+ tcase_add_test(tc_basic, test_bad_entity);
+ tcase_add_test(tc_basic, test_bad_entity_2);
+ tcase_add_test(tc_basic, test_bad_entity_3);
+ tcase_add_test(tc_basic, test_bad_entity_4);
+ tcase_add_test(tc_basic, test_bad_notation);
+ tcase_add_test(tc_basic, test_default_doctype_handler);
+ tcase_add_test(tc_basic, test_empty_element_abort);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_pool_integrity_with_unfinished_attr);
+ tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend);
+ tcase_add_test(tc_basic, test_big_tokens_take_linear_time);
+ tcase_add_test(tc_basic, test_set_reparse_deferral);
+ tcase_add_test(tc_basic, test_reparse_deferral_is_inherited);
+ tcase_add_test(tc_basic, test_set_reparse_deferral_on_null_parser);
+ tcase_add_test(tc_basic, test_set_reparse_deferral_on_the_fly);
+ tcase_add_test(tc_basic, test_set_bad_reparse_option);
+ tcase_add_test(tc_basic, test_bypass_heuristic_when_close_to_bufsize);
+ tcase_add_test(tc_basic, test_varying_buffer_fills);
+}
diff --git a/contrib/expat/tests/basic_tests.h b/contrib/expat/tests/basic_tests.h
new file mode 100644
index 000000000000..4c16562ca0fd
--- /dev/null
+++ b/contrib/expat/tests/basic_tests.h
@@ -0,0 +1,56 @@
+/* Tests in the "basic" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_BASIC_TESTS_H
+# define XML_BASIC_TESTS_H
+
+extern void make_basic_test_case(Suite *s);
+
+#endif /* XML_BASIC_TESTS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/basic_tests_cxx.cpp b/contrib/expat/tests/basic_tests_cxx.cpp
new file mode 100644
index 000000000000..d7e75a9061cf
--- /dev/null
+++ b/contrib/expat/tests/basic_tests_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "basic_tests.c"
diff --git a/contrib/expat/tests/benchmark/Makefile.am b/contrib/expat/tests/benchmark/Makefile.am
index f4d7a8e2c3eb..f1bf3365f63c 100644
--- a/contrib/expat/tests/benchmark/Makefile.am
+++ b/contrib/expat/tests/benchmark/Makefile.am
@@ -6,7 +6,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -28,7 +29,7 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
# USE OR OTHER DEALINGS IN THE SOFTWARE.
-AM_CPPFLAGS = -I$(srcdir)/../../lib
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../../lib
noinst_PROGRAMS = benchmark
diff --git a/contrib/expat/tests/benchmark/Makefile.in b/contrib/expat/tests/benchmark/Makefile.in
index 410ee04106d2..18f3b7bf7bf8 100644
--- a/contrib/expat/tests/benchmark/Makefile.in
+++ b/contrib/expat/tests/benchmark/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -132,6 +133,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/conftools/ax-append-compile-flags.m4 \
$(top_srcdir)/conftools/ax-append-link-flags.m4 \
$(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx-11.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -207,14 +210,16 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in \
$(top_srcdir)/conftools/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../../lib
+AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
@@ -224,8 +229,10 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CPP = @CPP@
+CMAKE_SHARED_LIBRARY_PREFIX = @CMAKE_SHARED_LIBRARY_PREFIX@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -241,10 +248,20 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
+EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
+EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
+EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
+EXPAT_DTD = @EXPAT_DTD@
+EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
+EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
+EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FILEMAP = @FILEMAP@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -254,6 +271,8 @@ LD = @LD@
LDFLAGS = @LDFLAGS@
LIBAGE = @LIBAGE@
LIBCURRENT = @LIBCURRENT@
+LIBDIR_BASENAME = @LIBDIR_BASENAME@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBREVISION = @LIBREVISION@
LIBS = @LIBS@
@@ -262,6 +281,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -283,6 +303,9 @@ RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SO_MAJOR = @SO_MAJOR@
+SO_MINOR = @SO_MINOR@
+SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
@@ -293,6 +316,7 @@ ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_void_p = @ac_cv_sizeof_void_p@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -330,6 +354,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -338,7 +363,6 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-AM_CPPFLAGS = -I$(srcdir)/../../lib
benchmark_SOURCES = benchmark.c
benchmark_LDADD = ../../lib/libexpat.la
EXTRA_DIST = \
@@ -348,7 +372,7 @@ all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -372,9 +396,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: $(am__configure_deps)
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
@@ -483,7 +507,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
diff --git a/contrib/expat/tests/benchmark/benchmark.c b/contrib/expat/tests/benchmark/benchmark.c
index fda8268f189f..355d83f896de 100644
--- a/contrib/expat/tests/benchmark/benchmark.c
+++ b/contrib/expat/tests/benchmark/benchmark.c
@@ -6,8 +6,10 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2003-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -31,6 +33,8 @@
*/
#include <sys/stat.h>
+#include <assert.h>
+#include <stddef.h> // ptrdiff_t
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
@@ -60,7 +64,8 @@ main(int argc, char *argv[]) {
char *XMLBuf, *XMLBufEnd, *XMLBufPtr;
FILE *fd;
struct stat fileAttr;
- int nrOfLoops, bufferSize, fileSize, i, isFinal;
+ int nrOfLoops, bufferSize, i, isFinal;
+ size_t fileSize;
int j = 0, ns = 0;
clock_t tstart, tend;
double cpuTime = 0.0;
@@ -112,12 +117,13 @@ main(int argc, char *argv[]) {
isFinal = 0;
tstart = clock();
do {
- int parseBufferSize = XMLBufEnd - XMLBufPtr;
- if (parseBufferSize <= bufferSize)
+ ptrdiff_t parseBufferSize = XMLBufEnd - XMLBufPtr;
+ if (parseBufferSize <= (ptrdiff_t)bufferSize)
isFinal = 1;
else
parseBufferSize = bufferSize;
- if (! XML_Parse(parser, XMLBufPtr, parseBufferSize, isFinal)) {
+ assert(parseBufferSize <= (ptrdiff_t)bufferSize);
+ if (! XML_Parse(parser, XMLBufPtr, (int)parseBufferSize, isFinal)) {
fprintf(stderr,
"error '%" XML_FMT_STR "' at line %" XML_FMT_INT_MOD
"u character %" XML_FMT_INT_MOD "u\n",
diff --git a/contrib/expat/tests/benchmark/benchmark.sln b/contrib/expat/tests/benchmark/benchmark.sln
deleted file mode 100644
index bc790bc0c59b..000000000000
--- a/contrib/expat/tests/benchmark/benchmark.sln
+++ /dev/null
@@ -1,25 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.40629.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "benchmark", "benchmark.vcxproj", "{FF89BA66-62C4-49EC-9189-1E7B603A1FD6}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- Template|Win32 = Template|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {FF89BA66-62C4-49EC-9189-1E7B603A1FD6}.Debug|Win32.ActiveCfg = Debug|Win32
- {FF89BA66-62C4-49EC-9189-1E7B603A1FD6}.Debug|Win32.Build.0 = Debug|Win32
- {FF89BA66-62C4-49EC-9189-1E7B603A1FD6}.Release|Win32.ActiveCfg = Release|Win32
- {FF89BA66-62C4-49EC-9189-1E7B603A1FD6}.Release|Win32.Build.0 = Release|Win32
- {FF89BA66-62C4-49EC-9189-1E7B603A1FD6}.Template|Win32.ActiveCfg = Template|Win32
- {FF89BA66-62C4-49EC-9189-1E7B603A1FD6}.Template|Win32.Build.0 = Template|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/contrib/expat/tests/chardata.c b/contrib/expat/tests/chardata.c
index 75a50166ec52..2adb2c5462bd 100644
--- a/contrib/expat/tests/chardata.c
+++ b/contrib/expat/tests/chardata.c
@@ -6,8 +6,13 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2002-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2016 Gilles Espinasse <g.esp@free.fr>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,9 +35,11 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifdef HAVE_EXPAT_CONFIG_H
-# include <expat_config.h>
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
#endif
+
+#include "expat_config.h"
#include "minicheck.h"
#include <assert.h>
@@ -78,15 +85,16 @@ CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len) {
int
CharData_CheckXMLChars(CharData *storage, const XML_Char *expected) {
- char buffer[1024];
int len = xmlstrlen(expected);
int count;
assert(storage != NULL);
count = (storage->count < 0) ? 0 : storage->count;
if (len != count) {
- sprintf(buffer, "wrong number of data characters: got %d, expected %d",
- count, len);
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer),
+ "wrong number of data characters: got %d, expected %d", count,
+ len);
fail(buffer);
return 0;
}
diff --git a/contrib/expat/tests/chardata.h b/contrib/expat/tests/chardata.h
index 4001b9b9d157..ccb631f64b22 100644
--- a/contrib/expat/tests/chardata.h
+++ b/contrib/expat/tests/chardata.h
@@ -7,8 +7,9 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2002-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/tests/chardata_cxx.cpp b/contrib/expat/tests/chardata_cxx.cpp
new file mode 100644
index 000000000000..81820c72dca1
--- /dev/null
+++ b/contrib/expat/tests/chardata_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "chardata.c"
diff --git a/contrib/expat/tests/common.c b/contrib/expat/tests/common.c
new file mode 100644
index 000000000000..26d0c5473a63
--- /dev/null
+++ b/contrib/expat/tests/common.c
@@ -0,0 +1,325 @@
+/* Commonly used functions for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "expat_config.h"
+#include "expat.h"
+#include "internal.h"
+#include "chardata.h"
+#include "minicheck.h"
+#include "common.h"
+
+/* Common test data */
+
+const char *long_character_data_text
+ = "<?xml version='1.0' encoding='iso-8859-1'?><s>"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "</s>";
+
+const char *long_cdata_text
+ = "<s><![CDATA["
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "]]></s>";
+
+/* Having an element name longer than 1024 characters exercises some
+ * of the pool allocation code in the parser that otherwise does not
+ * get executed. The count at the end of the line is the number of
+ * characters (bytes) in the element name by that point.x
+ */
+const char *get_buffer_test_text
+ = "<documentwitharidiculouslylongelementnametotease" /* 0x030 */
+ "aparticularcorneroftheallocationinXML_GetBuffers" /* 0x060 */
+ "othatwecanimprovethecoverageyetagain012345678901" /* 0x090 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0c0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0f0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x120 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x150 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x180 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1b0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1e0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x210 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x240 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x270 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2a0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2d0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x300 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x330 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x360 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x390 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3c0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3f0 */
+ "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */
+
+/* Test control globals */
+
+/* Used as the "resumable" parameter to XML_StopParser by some tests */
+XML_Bool g_resumable = XML_FALSE;
+
+/* Used to control abort checks in some tests */
+XML_Bool g_abortable = XML_FALSE;
+
+/* Used to control _XML_Parse_SINGLE_BYTES() chunk size */
+int g_chunkSize = 1;
+
+/* Common test functions */
+
+void
+tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) {
+#ifdef XML_DTD
+ tcase_add_test(tc, test);
+#else
+ UNUSED_P(tc);
+ UNUSED_P(test);
+#endif
+}
+
+void
+tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test) {
+#if XML_GE == 1
+ tcase_add_test(tc, test);
+#else
+ UNUSED_P(tc);
+ UNUSED_P(test);
+#endif
+}
+
+void
+basic_teardown(void) {
+ if (g_parser != NULL) {
+ XML_ParserFree(g_parser);
+ g_parser = NULL;
+ }
+}
+
+/* Generate a failure using the parser state to create an error message;
+ this should be used when the parser reports an error we weren't
+ expecting.
+*/
+void
+_xml_failure(XML_Parser parser, const char *file, int line) {
+ char buffer[1024];
+ enum XML_Error err = XML_GetErrorCode(parser);
+ snprintf(buffer, sizeof(buffer),
+ " %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
+ "u, offset %" XML_FMT_INT_MOD "u)\n reported from %s, line %d\n",
+ err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser), file, line);
+ _fail(file, line, buffer);
+}
+
+enum XML_Status
+_XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
+ int isFinal) {
+ // This ensures that tests have to run pathological parse cases
+ // (e.g. when `s` is NULL) against plain XML_Parse rather than
+ // chunking _XML_Parse_SINGLE_BYTES.
+ assert((parser != NULL) && (s != NULL) && (len >= 0));
+ const int chunksize = g_chunkSize;
+ if (chunksize > 0) {
+ // parse in chunks of `chunksize` bytes as long as not exhausting
+ for (; len > chunksize; len -= chunksize, s += chunksize) {
+ enum XML_Status res = XML_Parse(parser, s, chunksize, XML_FALSE);
+ if (res != XML_STATUS_OK) {
+ return res;
+ }
+ }
+ }
+ // parse the final chunk, the size of which will be <= chunksize
+ return XML_Parse(parser, s, len, isFinal);
+}
+
+void
+_expect_failure(const char *text, enum XML_Error errorCode,
+ const char *errorMessage, const char *file, int lineno) {
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ /* Hackish use of _fail() macro, but lets us report
+ the right filename and line number. */
+ _fail(file, lineno, errorMessage);
+ if (XML_GetErrorCode(g_parser) != errorCode)
+ _xml_failure(g_parser, file, lineno);
+}
+
+/* Character data support for handlers, built on top of the code in
+ * chardata.c
+ */
+void XMLCALL
+accumulate_characters(void *userData, const XML_Char *s, int len) {
+ CharData_AppendXMLChars((CharData *)userData, s, len);
+}
+
+void XMLCALL
+accumulate_attribute(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ CharData *storage = (CharData *)userData;
+ UNUSED_P(name);
+ /* Check there are attributes to deal with */
+ if (atts == NULL)
+ return;
+
+ while (storage->count < 0 && atts[0] != NULL) {
+ /* "accumulate" the value of the first attribute we see */
+ CharData_AppendXMLChars(storage, atts[1], -1);
+ atts += 2;
+ }
+}
+
+void
+_run_character_check(const char *text, const XML_Char *expected,
+ const char *file, int line) {
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ _xml_failure(g_parser, file, line);
+ CharData_CheckXMLChars(&storage, expected);
+}
+
+void
+_run_attribute_check(const char *text, const XML_Char *expected,
+ const char *file, int line) {
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ _xml_failure(g_parser, file, line);
+ CharData_CheckXMLChars(&storage, expected);
+}
+
+void XMLCALL
+ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
+ ExtTest *test_data = (ExtTest *)userData;
+ accumulate_characters(test_data->storage, s, len);
+}
+
+void
+_run_ext_character_check(const char *text, ExtTest *test_data,
+ const XML_Char *expected, const char *file, int line) {
+ CharData *const storage = (CharData *)malloc(sizeof(CharData));
+
+ CharData_Init(storage);
+ test_data->storage = storage;
+ XML_SetUserData(g_parser, test_data);
+ XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ _xml_failure(g_parser, file, line);
+ CharData_CheckXMLChars(storage, expected);
+
+ free(storage);
+}
+
+/* Control variable; the number of times duff_allocator() will successfully
+ * allocate */
+#define ALLOC_ALWAYS_SUCCEED (-1)
+#define REALLOC_ALWAYS_SUCCEED (-1)
+
+int g_allocation_count = ALLOC_ALWAYS_SUCCEED;
+int g_reallocation_count = REALLOC_ALWAYS_SUCCEED;
+
+/* Crocked allocator for allocation failure tests */
+void *
+duff_allocator(size_t size) {
+ if (g_allocation_count == 0)
+ return NULL;
+ if (g_allocation_count != ALLOC_ALWAYS_SUCCEED)
+ g_allocation_count--;
+ return malloc(size);
+}
+
+/* Crocked reallocator for allocation failure tests */
+void *
+duff_reallocator(void *ptr, size_t size) {
+ if (g_reallocation_count == 0)
+ return NULL;
+ if (g_reallocation_count != REALLOC_ALWAYS_SUCCEED)
+ g_reallocation_count--;
+ return realloc(ptr, size);
+}
diff --git a/contrib/expat/tests/common.h b/contrib/expat/tests/common.h
new file mode 100644
index 000000000000..52f00cc0eeb0
--- /dev/null
+++ b/contrib/expat/tests/common.h
@@ -0,0 +1,162 @@
+/* Commonly used functions for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_COMMON_H
+# define XML_COMMON_H
+
+# include "expat_config.h"
+# include "minicheck.h"
+# include "chardata.h"
+
+# ifdef XML_LARGE_SIZE
+# define XML_FMT_INT_MOD "ll"
+# else
+# define XML_FMT_INT_MOD "l"
+# endif
+
+# ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_STR "ls"
+# include <wchar.h>
+# define xcstrlen(s) wcslen(s)
+# define xcstrcmp(s, t) wcscmp((s), (t))
+# define xcstrncmp(s, t, n) wcsncmp((s), (t), (n))
+# define XCS(s) _XCS(s)
+# define _XCS(s) L##s
+# else
+# ifdef XML_UNICODE
+# error "No support for UTF-16 character without wchar_t in tests"
+# else
+# define XML_FMT_STR "s"
+# define xcstrlen(s) strlen(s)
+# define xcstrcmp(s, t) strcmp((s), (t))
+# define xcstrncmp(s, t, n) strncmp((s), (t), (n))
+# define XCS(s) s
+# endif /* XML_UNICODE */
+# endif /* XML_UNICODE_WCHAR_T */
+
+extern XML_Parser g_parser;
+
+extern XML_Bool g_resumable;
+extern XML_Bool g_abortable;
+
+extern int g_chunkSize;
+
+extern const char *long_character_data_text;
+extern const char *long_cdata_text;
+extern const char *get_buffer_test_text;
+
+extern void tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test);
+extern void tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test);
+
+extern void basic_teardown(void);
+
+extern void _xml_failure(XML_Parser parser, const char *file, int line);
+
+# define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
+
+extern enum XML_Status _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s,
+ int len, int isFinal);
+
+extern void _expect_failure(const char *text, enum XML_Error errorCode,
+ const char *errorMessage, const char *file,
+ int lineno);
+
+# define expect_failure(text, errorCode, errorMessage) \
+ _expect_failure((text), (errorCode), (errorMessage), __FILE__, __LINE__)
+
+/* Support functions for handlers to collect up character and attribute data.
+ */
+
+extern void XMLCALL accumulate_characters(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL accumulate_attribute(void *userData, const XML_Char *name,
+ const XML_Char **atts);
+
+extern void _run_character_check(const char *text, const XML_Char *expected,
+ const char *file, int line);
+
+# define run_character_check(text, expected) \
+ _run_character_check(text, expected, __FILE__, __LINE__)
+
+extern void _run_attribute_check(const char *text, const XML_Char *expected,
+ const char *file, int line);
+
+# define run_attribute_check(text, expected) \
+ _run_attribute_check(text, expected, __FILE__, __LINE__)
+
+typedef struct ExtTest {
+ const char *parse_text;
+ const XML_Char *encoding;
+ CharData *storage;
+} ExtTest;
+
+extern void XMLCALL ext_accumulate_characters(void *userData, const XML_Char *s,
+ int len);
+
+extern void _run_ext_character_check(const char *text, ExtTest *test_data,
+ const XML_Char *expected, const char *file,
+ int line);
+
+# define run_ext_character_check(text, test_data, expected) \
+ _run_ext_character_check(text, test_data, expected, __FILE__, __LINE__)
+
+# define ALLOC_ALWAYS_SUCCEED (-1)
+# define REALLOC_ALWAYS_SUCCEED (-1)
+
+extern int g_allocation_count;
+extern int g_reallocation_count;
+
+extern void *duff_allocator(size_t size);
+
+extern void *duff_reallocator(void *ptr, size_t size);
+
+#endif /* XML_COMMON_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/common_cxx.cpp b/contrib/expat/tests/common_cxx.cpp
new file mode 100644
index 000000000000..698a0ccfa9d5
--- /dev/null
+++ b/contrib/expat/tests/common_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "common.c"
diff --git a/contrib/expat/tests/dummy.c b/contrib/expat/tests/dummy.c
new file mode 100644
index 000000000000..4ab57edd2cf2
--- /dev/null
+++ b/contrib/expat/tests/dummy.c
@@ -0,0 +1,261 @@
+/* Dummy handler functions for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "expat.h"
+#include "internal.h"
+#include "common.h"
+#include "dummy.h"
+
+/* Dummy handlers for when we need to set a handler to tickle a bug,
+ but it doesn't need to do anything.
+*/
+static unsigned long dummy_handler_flags = 0;
+
+void
+init_dummy_handlers(void) {
+ dummy_handler_flags = 0;
+}
+
+unsigned long
+get_dummy_handler_flags(void) {
+ return dummy_handler_flags;
+}
+
+void XMLCALL
+dummy_xdecl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone) {
+ UNUSED_P(userData);
+ UNUSED_P(version);
+ UNUSED_P(encoding);
+ UNUSED_P(standalone);
+}
+
+void XMLCALL
+dummy_start_doctype_handler(void *userData, const XML_Char *doctypeName,
+ const XML_Char *sysid, const XML_Char *pubid,
+ int has_internal_subset) {
+ UNUSED_P(userData);
+ UNUSED_P(doctypeName);
+ UNUSED_P(sysid);
+ UNUSED_P(pubid);
+ UNUSED_P(has_internal_subset);
+ dummy_handler_flags |= DUMMY_START_DOCTYPE_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_end_doctype_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_END_DOCTYPE_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_entity_decl_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity, const XML_Char *value,
+ int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName) {
+ UNUSED_P(userData);
+ UNUSED_P(entityName);
+ UNUSED_P(is_parameter_entity);
+ UNUSED_P(value);
+ UNUSED_P(value_length);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ dummy_handler_flags |= DUMMY_ENTITY_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_notation_decl_handler(void *userData, const XML_Char *notationName,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(userData);
+ UNUSED_P(notationName);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ dummy_handler_flags |= DUMMY_NOTATION_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_element_decl_handler(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ /* The content model must be freed by the handler. Unfortunately
+ * we cannot pass the parser as the userData because this is used
+ * with other handlers that require other userData.
+ */
+ XML_FreeContentModel(g_parser, model);
+ dummy_handler_flags |= DUMMY_ELEMENT_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_attlist_decl_handler(void *userData, const XML_Char *elname,
+ const XML_Char *attname, const XML_Char *att_type,
+ const XML_Char *dflt, int isrequired) {
+ UNUSED_P(userData);
+ UNUSED_P(elname);
+ UNUSED_P(attname);
+ UNUSED_P(att_type);
+ UNUSED_P(dflt);
+ UNUSED_P(isrequired);
+ dummy_handler_flags |= DUMMY_ATTLIST_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_comment_handler(void *userData, const XML_Char *data) {
+ UNUSED_P(userData);
+ UNUSED_P(data);
+ dummy_handler_flags |= DUMMY_COMMENT_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data) {
+ UNUSED_P(userData);
+ UNUSED_P(target);
+ UNUSED_P(data);
+ dummy_handler_flags |= DUMMY_PI_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_start_element(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ UNUSED_P(atts);
+ dummy_handler_flags |= DUMMY_START_ELEMENT_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_end_element(void *userData, const XML_Char *name) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+}
+
+void XMLCALL
+dummy_start_cdata_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_START_CDATA_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_end_cdata_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_END_CDATA_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_cdata_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+}
+
+void XMLCALL
+dummy_start_namespace_decl_handler(void *userData, const XML_Char *prefix,
+ const XML_Char *uri) {
+ UNUSED_P(userData);
+ UNUSED_P(prefix);
+ UNUSED_P(uri);
+ dummy_handler_flags |= DUMMY_START_NS_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_end_namespace_decl_handler(void *userData, const XML_Char *prefix) {
+ UNUSED_P(userData);
+ UNUSED_P(prefix);
+ dummy_handler_flags |= DUMMY_END_NS_DECL_HANDLER_FLAG;
+}
+
+/* This handler is obsolete, but while the code exists we should
+ * ensure that dealing with the handler is covered by tests.
+ */
+void XMLCALL
+dummy_unparsed_entity_decl_handler(void *userData, const XML_Char *entityName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName) {
+ UNUSED_P(userData);
+ UNUSED_P(entityName);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ dummy_handler_flags |= DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_default_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+}
+
+void XMLCALL
+dummy_start_doctype_decl_handler(void *userData, const XML_Char *doctypeName,
+ const XML_Char *sysid, const XML_Char *pubid,
+ int has_internal_subset) {
+ UNUSED_P(userData);
+ UNUSED_P(doctypeName);
+ UNUSED_P(sysid);
+ UNUSED_P(pubid);
+ UNUSED_P(has_internal_subset);
+ dummy_handler_flags |= DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_end_doctype_decl_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG;
+}
+
+void XMLCALL
+dummy_skip_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity) {
+ UNUSED_P(userData);
+ UNUSED_P(entityName);
+ UNUSED_P(is_parameter_entity);
+ dummy_handler_flags |= DUMMY_SKIP_HANDLER_FLAG;
+}
diff --git a/contrib/expat/tests/dummy.h b/contrib/expat/tests/dummy.h
new file mode 100644
index 000000000000..3d7ec63ed336
--- /dev/null
+++ b/contrib/expat/tests/dummy.h
@@ -0,0 +1,150 @@
+/* Dummy handler functions for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_DUMMY_H
+# define XML_DUMMY_H
+
+# define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
+# define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
+# define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
+# define DUMMY_NOTATION_DECL_HANDLER_FLAG (1UL << 3)
+# define DUMMY_ELEMENT_DECL_HANDLER_FLAG (1UL << 4)
+# define DUMMY_ATTLIST_DECL_HANDLER_FLAG (1UL << 5)
+# define DUMMY_COMMENT_HANDLER_FLAG (1UL << 6)
+# define DUMMY_PI_HANDLER_FLAG (1UL << 7)
+# define DUMMY_START_ELEMENT_HANDLER_FLAG (1UL << 8)
+# define DUMMY_START_CDATA_HANDLER_FLAG (1UL << 9)
+# define DUMMY_END_CDATA_HANDLER_FLAG (1UL << 10)
+# define DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG (1UL << 11)
+# define DUMMY_START_NS_DECL_HANDLER_FLAG (1UL << 12)
+# define DUMMY_END_NS_DECL_HANDLER_FLAG (1UL << 13)
+# define DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG (1UL << 14)
+# define DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG (1UL << 15)
+# define DUMMY_SKIP_HANDLER_FLAG (1UL << 16)
+# define DUMMY_DEFAULT_HANDLER_FLAG (1UL << 17)
+
+extern void init_dummy_handlers(void);
+extern unsigned long get_dummy_handler_flags(void);
+
+extern void XMLCALL dummy_xdecl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding,
+ int standalone);
+
+extern void XMLCALL dummy_start_doctype_handler(void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid,
+ int has_internal_subset);
+
+extern void XMLCALL dummy_end_doctype_handler(void *userData);
+
+extern void XMLCALL dummy_entity_decl_handler(
+ void *userData, const XML_Char *entityName, int is_parameter_entity,
+ const XML_Char *value, int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName);
+
+extern void XMLCALL dummy_notation_decl_handler(void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern void XMLCALL dummy_element_decl_handler(void *userData,
+ const XML_Char *name,
+ XML_Content *model);
+
+extern void XMLCALL dummy_attlist_decl_handler(
+ void *userData, const XML_Char *elname, const XML_Char *attname,
+ const XML_Char *att_type, const XML_Char *dflt, int isrequired);
+
+extern void XMLCALL dummy_comment_handler(void *userData, const XML_Char *data);
+
+extern void XMLCALL dummy_pi_handler(void *userData, const XML_Char *target,
+ const XML_Char *data);
+
+extern void XMLCALL dummy_start_element(void *userData, const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL dummy_end_element(void *userData, const XML_Char *name);
+
+extern void XMLCALL dummy_start_cdata_handler(void *userData);
+
+extern void XMLCALL dummy_end_cdata_handler(void *userData);
+
+extern void XMLCALL dummy_cdata_handler(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL dummy_start_namespace_decl_handler(void *userData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
+
+extern void XMLCALL dummy_end_namespace_decl_handler(void *userData,
+ const XML_Char *prefix);
+
+extern void XMLCALL dummy_unparsed_entity_decl_handler(
+ void *userData, const XML_Char *entityName, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName);
+
+extern void XMLCALL dummy_default_handler(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL dummy_start_doctype_decl_handler(
+ void *userData, const XML_Char *doctypeName, const XML_Char *sysid,
+ const XML_Char *pubid, int has_internal_subset);
+
+extern void XMLCALL dummy_end_doctype_decl_handler(void *userData);
+
+extern void XMLCALL dummy_skip_handler(void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity);
+
+#endif /* XML_DUMMY_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/dummy_cxx.cpp b/contrib/expat/tests/dummy_cxx.cpp
new file mode 100644
index 000000000000..27c9f431ecd8
--- /dev/null
+++ b/contrib/expat/tests/dummy_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "dummy.c"
diff --git a/contrib/expat/tests/handlers.c b/contrib/expat/tests/handlers.c
new file mode 100644
index 000000000000..449ada70f9a2
--- /dev/null
+++ b/contrib/expat/tests/handlers.c
@@ -0,0 +1,1932 @@
+/* XML handler functions for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "expat_config.h"
+
+#include "expat.h"
+#include "internal.h"
+#include "chardata.h"
+#include "structdata.h"
+#include "common.h"
+#include "handlers.h"
+
+/* Global variables for user parameter settings tests */
+/* Variable holding the expected handler userData */
+const void *g_handler_data = NULL;
+/* Count of the number of times the comment handler has been invoked */
+int g_comment_count = 0;
+/* Count of the number of skipped entities */
+int g_skip_count = 0;
+/* Count of the number of times the XML declaration handler is invoked */
+int g_xdecl_count = 0;
+
+/* Start/End Element Handlers */
+
+void XMLCALL
+start_element_event_handler(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(atts);
+ CharData_AppendXMLChars((CharData *)userData, name, -1);
+}
+
+void XMLCALL
+end_element_event_handler(void *userData, const XML_Char *name) {
+ CharData *storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, XCS("/"), 1);
+ CharData_AppendXMLChars(storage, name, -1);
+}
+
+void XMLCALL
+start_element_event_handler2(void *userData, const XML_Char *name,
+ const XML_Char **attr) {
+ StructData *storage = (StructData *)userData;
+ UNUSED_P(attr);
+ StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
+ XML_GetCurrentLineNumber(g_parser), STRUCT_START_TAG);
+}
+
+void XMLCALL
+end_element_event_handler2(void *userData, const XML_Char *name) {
+ StructData *storage = (StructData *)userData;
+ StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
+ XML_GetCurrentLineNumber(g_parser), STRUCT_END_TAG);
+}
+
+void XMLCALL
+counting_start_element_handler(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ ElementInfo *info = (ElementInfo *)userData;
+ AttrInfo *attr;
+ int count, id, i;
+
+ while (info->name != NULL) {
+ if (! xcstrcmp(name, info->name))
+ break;
+ info++;
+ }
+ if (info->name == NULL)
+ fail("Element not recognised");
+ /* The attribute count is twice what you might expect. It is a
+ * count of items in atts, an array which contains alternating
+ * attribute names and attribute values. For the naive user this
+ * is possibly a little unexpected, but it is what the
+ * documentation in expat.h tells us to expect.
+ */
+ count = XML_GetSpecifiedAttributeCount(g_parser);
+ if (info->attr_count * 2 != count) {
+ fail("Not got expected attribute count");
+ return;
+ }
+ id = XML_GetIdAttributeIndex(g_parser);
+ if (id == -1 && info->id_name != NULL) {
+ fail("ID not present");
+ return;
+ }
+ if (id != -1 && xcstrcmp(atts[id], info->id_name)) {
+ fail("ID does not have the correct name");
+ return;
+ }
+ for (i = 0; i < info->attr_count; i++) {
+ attr = info->attributes;
+ while (attr->name != NULL) {
+ if (! xcstrcmp(atts[0], attr->name))
+ break;
+ attr++;
+ }
+ if (attr->name == NULL) {
+ fail("Attribute not recognised");
+ return;
+ }
+ if (xcstrcmp(atts[1], attr->value)) {
+ fail("Attribute has wrong value");
+ return;
+ }
+ /* Remember, two entries in atts per attribute (see above) */
+ atts += 2;
+ }
+}
+
+void XMLCALL
+suspending_end_handler(void *userData, const XML_Char *s) {
+ UNUSED_P(s);
+ XML_StopParser((XML_Parser)userData, 1);
+}
+
+void XMLCALL
+start_element_suspender(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(userData);
+ UNUSED_P(atts);
+ if (! xcstrcmp(name, XCS("suspend")))
+ XML_StopParser(g_parser, XML_TRUE);
+ if (! xcstrcmp(name, XCS("abort")))
+ XML_StopParser(g_parser, XML_FALSE);
+}
+
+/* Check that an element name and attribute name match the expected values.
+ The expected values are passed as an array reference of string pointers
+ provided as the userData argument; the first is the expected
+ element name, and the second is the expected attribute name.
+*/
+int g_triplet_start_flag = XML_FALSE;
+int g_triplet_end_flag = XML_FALSE;
+
+void XMLCALL
+triplet_start_checker(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ XML_Char **elemstr = (XML_Char **)userData;
+ char buffer[1024];
+ if (xcstrcmp(elemstr[0], name) != 0) {
+ snprintf(buffer, sizeof(buffer),
+ "unexpected start string: '%" XML_FMT_STR "'", name);
+ fail(buffer);
+ }
+ if (xcstrcmp(elemstr[1], atts[0]) != 0) {
+ snprintf(buffer, sizeof(buffer),
+ "unexpected attribute string: '%" XML_FMT_STR "'", atts[0]);
+ fail(buffer);
+ }
+ g_triplet_start_flag = XML_TRUE;
+}
+
+/* Check that the element name passed to the end-element handler matches
+ the expected value. The expected value is passed as the first element
+ in an array of strings passed as the userData argument.
+*/
+void XMLCALL
+triplet_end_checker(void *userData, const XML_Char *name) {
+ XML_Char **elemstr = (XML_Char **)userData;
+ if (xcstrcmp(elemstr[0], name) != 0) {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer),
+ "unexpected end string: '%" XML_FMT_STR "'", name);
+ fail(buffer);
+ }
+ g_triplet_end_flag = XML_TRUE;
+}
+
+void XMLCALL
+overwrite_start_checker(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ CharData *storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, XCS("start "), 6);
+ CharData_AppendXMLChars(storage, name, -1);
+ while (*atts != NULL) {
+ CharData_AppendXMLChars(storage, XCS("\nattribute "), 11);
+ CharData_AppendXMLChars(storage, *atts, -1);
+ atts += 2;
+ }
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
+}
+
+void XMLCALL
+overwrite_end_checker(void *userData, const XML_Char *name) {
+ CharData *storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, XCS("end "), 4);
+ CharData_AppendXMLChars(storage, name, -1);
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
+}
+
+void XMLCALL
+start_element_fail(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ UNUSED_P(atts);
+
+ /* We should never get here. */
+ fail("should never reach start_element_fail()");
+}
+
+void XMLCALL
+start_ns_clearing_start_element(void *userData, const XML_Char *prefix,
+ const XML_Char *uri) {
+ UNUSED_P(prefix);
+ UNUSED_P(uri);
+ XML_SetStartElementHandler((XML_Parser)userData, NULL);
+}
+
+void XMLCALL
+start_element_issue_240(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ DataIssue240 *mydata = (DataIssue240 *)userData;
+ UNUSED_P(name);
+ UNUSED_P(atts);
+ mydata->deep++;
+}
+
+void XMLCALL
+end_element_issue_240(void *userData, const XML_Char *name) {
+ DataIssue240 *mydata = (DataIssue240 *)userData;
+
+ UNUSED_P(name);
+ mydata->deep--;
+ if (mydata->deep == 0) {
+ XML_StopParser(mydata->parser, 0);
+ }
+}
+
+/* Text encoding handlers */
+
+int XMLCALL
+UnknownEncodingHandler(void *data, const XML_Char *encoding,
+ XML_Encoding *info) {
+ UNUSED_P(data);
+ if (xcstrcmp(encoding, XCS("unsupported-encoding")) == 0) {
+ int i;
+ for (i = 0; i < 256; ++i)
+ info->map[i] = i;
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = NULL;
+ return XML_STATUS_OK;
+ }
+ return XML_STATUS_ERROR;
+}
+
+static void
+dummy_release(void *data) {
+ UNUSED_P(data);
+}
+
+int XMLCALL
+UnrecognisedEncodingHandler(void *data, const XML_Char *encoding,
+ XML_Encoding *info) {
+ UNUSED_P(data);
+ UNUSED_P(encoding);
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = dummy_release;
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+unknown_released_encoding_handler(void *data, const XML_Char *encoding,
+ XML_Encoding *info) {
+ UNUSED_P(data);
+ if (! xcstrcmp(encoding, XCS("unsupported-encoding"))) {
+ int i;
+
+ for (i = 0; i < 256; i++)
+ info->map[i] = i;
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = dummy_release;
+ return XML_STATUS_OK;
+ }
+ return XML_STATUS_ERROR;
+}
+
+static int XMLCALL
+failing_converter(void *data, const char *s) {
+ UNUSED_P(data);
+ UNUSED_P(s);
+ /* Always claim to have failed */
+ return -1;
+}
+
+static int XMLCALL
+prefix_converter(void *data, const char *s) {
+ UNUSED_P(data);
+ /* If the first byte is 0xff, raise an error */
+ if (s[0] == (char)-1)
+ return -1;
+ /* Just add the low bits of the first byte to the second */
+ return (s[1] + (s[0] & 0x7f)) & 0x01ff;
+}
+
+int XMLCALL
+MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
+ int i;
+ int high_map = -2; /* Assume a 2-byte sequence */
+
+ if (! xcstrcmp(encoding, XCS("invalid-9"))
+ || ! xcstrcmp(encoding, XCS("ascii-like"))
+ || ! xcstrcmp(encoding, XCS("invalid-len"))
+ || ! xcstrcmp(encoding, XCS("invalid-a"))
+ || ! xcstrcmp(encoding, XCS("invalid-surrogate"))
+ || ! xcstrcmp(encoding, XCS("invalid-high")))
+ high_map = -1;
+
+ for (i = 0; i < 128; ++i)
+ info->map[i] = i;
+ for (; i < 256; ++i)
+ info->map[i] = high_map;
+
+ /* If required, put an invalid value in the ASCII entries */
+ if (! xcstrcmp(encoding, XCS("invalid-9")))
+ info->map[9] = 5;
+ /* If required, have a top-bit set character starts a 5-byte sequence */
+ if (! xcstrcmp(encoding, XCS("invalid-len")))
+ info->map[0x81] = -5;
+ /* If required, make a top-bit set character a valid ASCII character */
+ if (! xcstrcmp(encoding, XCS("invalid-a")))
+ info->map[0x82] = 'a';
+ /* If required, give a top-bit set character a forbidden value,
+ * what would otherwise be the first of a surrogate pair.
+ */
+ if (! xcstrcmp(encoding, XCS("invalid-surrogate")))
+ info->map[0x83] = 0xd801;
+ /* If required, give a top-bit set character too high a value */
+ if (! xcstrcmp(encoding, XCS("invalid-high")))
+ info->map[0x84] = 0x010101;
+
+ info->data = data;
+ info->release = NULL;
+ if (! xcstrcmp(encoding, XCS("failing-conv")))
+ info->convert = failing_converter;
+ else if (! xcstrcmp(encoding, XCS("prefix-conv")))
+ info->convert = prefix_converter;
+ else
+ info->convert = NULL;
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+long_encoding_handler(void *userData, const XML_Char *encoding,
+ XML_Encoding *info) {
+ int i;
+
+ UNUSED_P(userData);
+ UNUSED_P(encoding);
+ for (i = 0; i < 256; i++)
+ info->map[i] = i;
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = NULL;
+ return XML_STATUS_OK;
+}
+
+/* External Entity Handlers */
+
+int XMLCALL
+external_entity_optioner(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtOption *options = (ExtOption *)XML_GetUserData(parser);
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ while (options->parse_text != NULL) {
+ if (! xcstrcmp(systemId, options->system_id)) {
+ enum XML_Status rc;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ rc = _XML_Parse_SINGLE_BYTES(ext_parser, options->parse_text,
+ (int)strlen(options->parse_text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ return rc;
+ }
+ options++;
+ }
+ fail("No suitable option found");
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+external_entity_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtTest *test_data = (ExtTest *)XML_GetUserData(parser);
+ XML_Parser extparser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (extparser == NULL)
+ fail("Could not create external entity parser.");
+ if (test_data->encoding != NULL) {
+ if (! XML_SetEncoding(extparser, test_data->encoding))
+ fail("XML_SetEncoding() ignored for external entity");
+ }
+ if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
+ (int)strlen(test_data->parse_text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(extparser);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(extparser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_faulter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ XML_Parser ext_parser;
+ ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (fault->encoding != NULL) {
+ if (! XML_SetEncoding(ext_parser, fault->encoding))
+ fail("XML_SetEncoding failed");
+ }
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
+ (int)strlen(fault->parse_text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail(fault->fail_text);
+ if (XML_GetErrorCode(ext_parser) != fault->error)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+external_entity_null_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(parser);
+ UNUSED_P(context);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_resetter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+ XML_ParsingStatus status;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_GetParsingStatus(ext_parser, &status);
+ if (status.parsing != XML_INITIALIZED) {
+ fail("Parsing status is not INITIALIZED");
+ return XML_STATUS_ERROR;
+ }
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(parser);
+ return XML_STATUS_ERROR;
+ }
+ XML_GetParsingStatus(ext_parser, &status);
+ if (status.parsing != XML_FINISHED) {
+ fail("Parsing status is not FINISHED");
+ return XML_STATUS_ERROR;
+ }
+ /* Check we can't parse here */
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Parsing when finished not faulted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_FINISHED)
+ fail("Parsing when finished faulted with wrong code");
+ XML_ParserReset(ext_parser, NULL);
+ XML_GetParsingStatus(ext_parser, &status);
+ if (status.parsing != XML_FINISHED) {
+ fail("Parsing status not still FINISHED");
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+void XMLCALL
+entity_suspending_decl_handler(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ XML_Parser ext_parser = (XML_Parser)userData;
+
+ UNUSED_P(name);
+ if (XML_StopParser(ext_parser, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Attempting to suspend a subordinate parser not faulted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_SUSPEND_PE)
+ fail("Suspending subordinate parser get wrong code");
+ XML_SetElementDeclHandler(ext_parser, NULL);
+ XML_FreeContentModel(g_parser, model);
+}
+
+int XMLCALL
+external_entity_suspender(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetElementDeclHandler(ext_parser, entity_suspending_decl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(ext_parser);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+void XMLCALL
+entity_suspending_xdecl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone) {
+ XML_Parser ext_parser = (XML_Parser)userData;
+
+ UNUSED_P(version);
+ UNUSED_P(encoding);
+ UNUSED_P(standalone);
+ XML_StopParser(ext_parser, g_resumable);
+ XML_SetXmlDeclHandler(ext_parser, NULL);
+}
+
+int XMLCALL
+external_entity_suspend_xmldecl(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>";
+ XML_Parser ext_parser;
+ XML_ParsingStatus status;
+ enum XML_Status rc;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ rc = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_GetParsingStatus(ext_parser, &status);
+ if (g_resumable) {
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ if (status.parsing != XML_SUSPENDED)
+ fail("Ext Parsing status not SUSPENDED");
+ } else {
+ if (rc != XML_STATUS_ERROR)
+ fail("Ext parsing not aborted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
+ xml_failure(ext_parser);
+ if (status.parsing != XML_FINISHED)
+ fail("Ext Parsing status not FINISHED");
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ XML_Parser ext_parser;
+ ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+ void *buffer;
+ int parse_len = (int)strlen(fault->parse_text);
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ g_resumable = XML_TRUE;
+ buffer = XML_GetBuffer(ext_parser, parse_len);
+ if (buffer == NULL)
+ fail("Could not allocate parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, fault->parse_text, parse_len);
+ if (XML_ParseBuffer(ext_parser, parse_len, XML_FALSE) != XML_STATUS_SUSPENDED)
+ fail("XML declaration did not suspend");
+ if (XML_ResumeParser(ext_parser) != XML_STATUS_OK)
+ xml_failure(ext_parser);
+ if (XML_ParseBuffer(ext_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail(fault->fail_text);
+ if (XML_GetErrorCode(ext_parser) != fault->error)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+external_entity_failer__if_not_xml_ge(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(parser);
+ UNUSED_P(context);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+#if XML_GE == 0
+ fail(
+ "Function external_entity_suspending_failer was called despite XML_GE==0.");
+#endif
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_cr_catcher(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "\r";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_bad_cr_catcher(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<tag>\r";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Async entity error not caught");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
+ xml_failure(ext_parser);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_rsqb_catcher(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<tag>]";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetCharacterDataHandler(ext_parser, rsqb_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Async entity error not caught");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
+ xml_failure(ext_parser);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_good_cdata_ascii(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
+ const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
+ CharData storage;
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ CharData_Init(&storage);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetUserData(ext_parser, &storage);
+ XML_SetCharacterDataHandler(ext_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ CharData_CheckXMLChars(&storage, expected);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_param_checker(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!-- Subordinate parser -->\n"
+ "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ g_handler_data = ext_parser;
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(parser);
+ return XML_STATUS_ERROR;
+ }
+ g_handler_data = parser;
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_ref_param_checker(XML_Parser parameter, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if ((void *)parameter != g_handler_data)
+ fail("External entity ref handler parameter not correct");
+
+ /* Here we use the global 'parser' variable */
+ ext_parser = XML_ExternalEntityParserCreate(g_parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_param(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n"
+ "%e1;\n";
+ const char *text2 = "<!ELEMENT el EMPTY>\n"
+ "<el/>\n";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+
+ if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Inner DTD with invalid tag not rejected");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
+ xml_failure(ext_parser);
+ } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid tag in external param not rejected");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_SYNTAX)
+ xml_failure(ext_parser);
+ } else {
+ fail("Unknown system ID");
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+external_entity_load_ignore(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_load_ignore_utf16(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char text[] =
+ /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
+ "<\0!\0[\0I\0G\0N\0O\0R\0E\0[\0"
+ "<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 \0"
+ "(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>\0";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_load_ignore_utf16_be(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char text[] =
+ /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
+ "\0<\0!\0[\0I\0G\0N\0O\0R\0E\0["
+ "\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 "
+ "\0(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_valuer(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n"
+ "%e1;\n";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+ enum XML_Status status;
+ enum XML_Error error;
+
+ status = _XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
+ (int)strlen(fault->parse_text), XML_TRUE);
+ if (fault->error == XML_ERROR_NONE) {
+ if (status == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ } else {
+ if (status != XML_STATUS_ERROR)
+ fail(fault->fail_text);
+ error = XML_GetErrorCode(ext_parser);
+ if (error != fault->error
+ && (fault->error != XML_ERROR_XML_DECL
+ || error != XML_ERROR_TEXT_DECL))
+ xml_failure(ext_parser);
+ }
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM 'bar'>\n"
+ "%e1;\n";
+ const char *text2 = "<!ATTLIST doc a1 CDATA 'value'>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (! xcstrcmp(systemId, XCS("foo"))) {
+ XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Expected not standalone rejection");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_NOT_STANDALONE)
+ xml_failure(ext_parser);
+ XML_SetNotStandaloneHandler(ext_parser, NULL);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+ } else if (! xcstrcmp(systemId, XCS("bar"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_value_aborter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n"
+ "%e1;\n";
+ const char *text2 = "<?xml version='1.0' encoding='utf-8'?>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ }
+ if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Aborted parse not faulted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
+ xml_failure(ext_parser);
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_public(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = (const char *)XML_GetUserData(parser);
+ const char *text2 = "<!ATTLIST doc a CDATA 'value'>";
+ const char *text = NULL;
+ XML_Parser ext_parser;
+ int parse_res;
+
+ UNUSED_P(base);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ if (systemId != NULL && ! xcstrcmp(systemId, XCS("http://example.org/"))) {
+ text = text1;
+ } else if (publicId != NULL && ! xcstrcmp(publicId, XCS("foo"))) {
+ text = text2;
+ } else
+ fail("Unexpected parameters to external entity parser");
+ assert(text != NULL);
+ parse_res
+ = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ return parse_res;
+}
+
+int XMLCALL
+external_entity_devaluer(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM 'bar'>\n"
+ "%e1;\n";
+ XML_Parser ext_parser;
+ int clear_handler_flag = (XML_GetUserData(parser) != NULL);
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL || ! xcstrcmp(systemId, XCS("bar")))
+ return XML_STATUS_OK;
+ if (xcstrcmp(systemId, XCS("foo")))
+ fail("Unexpected system ID");
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could note create external entity parser");
+ if (clear_handler_flag)
+ XML_SetExternalEntityRefHandler(ext_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser);
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser.");
+ /* Use the requested entity parser for further externals */
+ XML_SetExternalEntityRefHandler(ext_parser, test_data->handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, test_data->parse_text,
+ (int)strlen(test_data->parse_text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(ext_parser);
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_loader2(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser);
+ XML_Parser extparser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (extparser == NULL)
+ fail("Coulr not create external entity parser");
+ if (test_data->encoding != NULL) {
+ if (! XML_SetEncoding(extparser, test_data->encoding))
+ fail("XML_SetEncoding() ignored for external entity");
+ }
+ if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
+ test_data->parse_len, XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(extparser);
+ }
+
+ XML_ParserFree(extparser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_faulter2(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser);
+ XML_Parser extparser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (extparser == NULL)
+ fail("Could not create external entity parser");
+ if (test_data->encoding != NULL) {
+ if (! XML_SetEncoding(extparser, test_data->encoding))
+ fail("XML_SetEncoding() ignored for external entity");
+ }
+ if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
+ test_data->parse_len, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail(test_data->fail_text);
+ if (XML_GetErrorCode(extparser) != test_data->error)
+ xml_failure(extparser);
+
+ XML_ParserFree(extparser);
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+external_entity_unfinished_attlist(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT barf ANY>\n"
+ "<!ATTLIST barf my_attr (blah|%blah;a|foo) #REQUIRED>\n"
+ "<!--COMMENT-->\n";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_handler(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ void *user_data = XML_GetUserData(parser);
+ const char *text;
+ XML_Parser p2;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if (user_data == NULL)
+ text = ("<!ELEMENT doc (e+)>\n"
+ "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
+ "<!ELEMENT e EMPTY>\n");
+ else
+ text = ("<?xml version='1.0' encoding='us-ascii'?>"
+ "<e/>");
+
+ /* Set user data to any non-NULL value */
+ XML_SetUserData(parser, parser);
+ p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (_XML_Parse_SINGLE_BYTES(p2, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(p2);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(p2);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_duff_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ XML_Parser new_parser;
+ unsigned int i;
+ const unsigned int max_alloc_count = 10;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ /* Try a few different allocation levels */
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser != NULL) {
+ XML_ParserFree(new_parser);
+ break;
+ }
+ }
+ if (i == 0)
+ fail("External parser creation ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Extern parser not created with max allocation count");
+
+ /* Make sure other random allocation doesn't now fail */
+ g_allocation_count = ALLOC_ALWAYS_SUCCEED;
+
+ /* Make sure the failure code path is executed too */
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+external_entity_dbl_handler(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ int *pcallno = (int *)XML_GetUserData(parser);
+ int callno = *pcallno;
+ const char *text;
+ XML_Parser new_parser = NULL;
+ int i;
+ const int max_alloc_count = 20;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if (callno == 0) {
+ /* First time through, check how many calls to malloc occur */
+ text = ("<!ELEMENT doc (e+)>\n"
+ "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
+ "<!ELEMENT e EMPTY>\n");
+ g_allocation_count = 10000;
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser == NULL) {
+ fail("Unable to allocate first external parser");
+ return XML_STATUS_ERROR;
+ }
+ /* Stash the number of calls in the user data */
+ *pcallno = 10000 - g_allocation_count;
+ } else {
+ text = ("<?xml version='1.0' encoding='us-ascii'?>"
+ "<e/>");
+ /* Try at varying levels to exercise more code paths */
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = callno + i;
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser != NULL)
+ break;
+ }
+ if (i == 0) {
+ fail("Second external parser unexpectedly created");
+ XML_ParserFree(new_parser);
+ return XML_STATUS_ERROR;
+ } else if (i == max_alloc_count) {
+ fail("Second external parser not created");
+ return XML_STATUS_ERROR;
+ }
+ }
+
+ g_allocation_count = ALLOC_ALWAYS_SUCCEED;
+ if (_XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(new_parser);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(new_parser);
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ int *pcallno = (int *)XML_GetUserData(parser);
+ int callno = *pcallno;
+ const char *text;
+ XML_Parser new_parser;
+ enum XML_Status rv;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if (callno == 0) {
+ /* Try different allocation levels for whole exercise */
+ text = ("<!ELEMENT doc (e+)>\n"
+ "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
+ "<!ELEMENT e EMPTY>\n");
+ *pcallno = 1;
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser == NULL)
+ return XML_STATUS_ERROR;
+ rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
+ } else {
+ /* Just run through once */
+ text = ("<?xml version='1.0' encoding='us-ascii'?>"
+ "<e/>");
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser == NULL)
+ return XML_STATUS_ERROR;
+ rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
+ }
+ XML_ParserFree(new_parser);
+ if (rv == XML_STATUS_ERROR)
+ return XML_STATUS_ERROR;
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_alloc_set_encoding(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ /* As for external_entity_loader() */
+ const char *text = "<?xml encoding='iso-8859-3'?>"
+ "\xC3\xA9";
+ XML_Parser ext_parser;
+ enum XML_Status status;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ if (! XML_SetEncoding(ext_parser, XCS("utf-8"))) {
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+ }
+ status
+ = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ if (status == XML_STATUS_ERROR)
+ return XML_STATUS_ERROR;
+ return XML_STATUS_OK;
+}
+
+int XMLCALL
+external_entity_reallocator(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = get_buffer_test_text;
+ XML_Parser ext_parser;
+ void *buffer;
+ enum XML_Status status;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+
+ g_reallocation_count = *(int *)XML_GetUserData(parser);
+ buffer = XML_GetBuffer(ext_parser, 1536);
+ if (buffer == NULL)
+ fail("Buffer allocation failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ status = XML_ParseBuffer(ext_parser, (int)strlen(text), XML_FALSE);
+ g_reallocation_count = -1;
+ XML_ParserFree(ext_parser);
+ return (status == XML_STATUS_OK) ? XML_STATUS_OK : XML_STATUS_ERROR;
+}
+
+int XMLCALL
+external_entity_alloc(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = (const char *)XML_GetUserData(parser);
+ XML_Parser ext_parser;
+ int parse_res;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ parse_res
+ = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ return parse_res;
+}
+
+int XMLCALL
+external_entity_parser_create_alloc_fail_handler(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+
+ if (context != NULL)
+ fail("Unexpected non-NULL context");
+
+ // The following number intends to fail the upcoming allocation in line
+ // "parser->m_protocolEncodingName = copyString(encodingName,
+ // &(parser->m_mem));" in function parserInit.
+ g_allocation_count = 3;
+
+ const XML_Char *const encodingName = XCS("UTF-8"); // needs something non-NULL
+ const XML_Parser ext_parser
+ = XML_ExternalEntityParserCreate(parser, context, encodingName);
+ if (ext_parser != NULL)
+ fail(
+ "Call to XML_ExternalEntityParserCreate was expected to fail out-of-memory");
+
+ g_allocation_count = ALLOC_ALWAYS_SUCCEED;
+ return XML_STATUS_ERROR;
+}
+
+#if XML_GE == 1
+int
+accounting_external_entity_ref_handler(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+
+ const struct AccountingTestCase *const testCase
+ = (const struct AccountingTestCase *)XML_GetUserData(parser);
+
+ const char *externalText = NULL;
+ if (xcstrcmp(systemId, XCS("first.ent")) == 0) {
+ externalText = testCase->firstExternalText;
+ } else if (xcstrcmp(systemId, XCS("second.ent")) == 0) {
+ externalText = testCase->secondExternalText;
+ } else {
+ assert(! "systemId is neither \"first.ent\" nor \"second.ent\"");
+ }
+ assert(externalText);
+
+ XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
+ assert(entParser);
+
+ const enum XML_Status status = _XML_Parse_SINGLE_BYTES(
+ entParser, externalText, (int)strlen(externalText), XML_TRUE);
+
+ XML_ParserFree(entParser);
+ return status;
+}
+#endif /* XML_GE == 1 */
+
+/* NotStandalone handlers */
+
+int XMLCALL
+reject_not_standalone_handler(void *userData) {
+ UNUSED_P(userData);
+ return XML_STATUS_ERROR;
+}
+
+int XMLCALL
+accept_not_standalone_handler(void *userData) {
+ UNUSED_P(userData);
+ return XML_STATUS_OK;
+}
+
+/* Attribute List handlers */
+void XMLCALL
+verify_attlist_decl_handler(void *userData, const XML_Char *element_name,
+ const XML_Char *attr_name,
+ const XML_Char *attr_type,
+ const XML_Char *default_value, int is_required) {
+ AttTest *at = (AttTest *)userData;
+
+ if (xcstrcmp(element_name, at->element_name))
+ fail("Unexpected element name in attribute declaration");
+ if (xcstrcmp(attr_name, at->attr_name))
+ fail("Unexpected attribute name in attribute declaration");
+ if (xcstrcmp(attr_type, at->attr_type))
+ fail("Unexpected attribute type in attribute declaration");
+ if ((default_value == NULL && at->default_value != NULL)
+ || (default_value != NULL && at->default_value == NULL)
+ || (default_value != NULL && xcstrcmp(default_value, at->default_value)))
+ fail("Unexpected default value in attribute declaration");
+ if (is_required != at->is_required)
+ fail("Requirement mismatch in attribute declaration");
+}
+
+/* Character Data handlers */
+
+void XMLCALL
+clearing_aborting_character_handler(void *userData, const XML_Char *s,
+ int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+ XML_StopParser(g_parser, g_resumable);
+ XML_SetCharacterDataHandler(g_parser, NULL);
+}
+
+void XMLCALL
+parser_stop_character_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+ XML_ParsingStatus status;
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing == XML_FINISHED) {
+ return; // the parser was stopped by a previous call to this handler.
+ }
+ XML_StopParser(g_parser, g_resumable);
+ XML_SetCharacterDataHandler(g_parser, NULL);
+ if (! g_resumable) {
+ /* Check that aborting an aborted parser is faulted */
+ if (XML_StopParser(g_parser, XML_FALSE) != XML_STATUS_ERROR)
+ fail("Aborting aborted parser not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
+ xml_failure(g_parser);
+ } else if (g_abortable) {
+ /* Check that aborting a suspended parser works */
+ if (XML_StopParser(g_parser, XML_FALSE) == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ } else {
+ /* Check that suspending a suspended parser works */
+ if (XML_StopParser(g_parser, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Suspending suspended parser not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ xml_failure(g_parser);
+ }
+}
+
+void XMLCALL
+cr_cdata_handler(void *userData, const XML_Char *s, int len) {
+ int *pfound = (int *)userData;
+
+ /* Internal processing turns the CR into a newline for the
+ * character data handler, but not for the default handler
+ */
+ if (len == 1 && (*s == XCS('\n') || *s == XCS('\r')))
+ *pfound = 1;
+}
+
+void XMLCALL
+rsqb_handler(void *userData, const XML_Char *s, int len) {
+ int *pfound = (int *)userData;
+
+ if (len == 1 && *s == XCS(']'))
+ *pfound = 1;
+}
+
+void XMLCALL
+byte_character_handler(void *userData, const XML_Char *s, int len) {
+#if XML_CONTEXT_BYTES > 0
+ int offset, size;
+ const char *buffer;
+ ByteTestData *data = (ByteTestData *)userData;
+
+ UNUSED_P(s);
+ buffer = XML_GetInputContext(g_parser, &offset, &size);
+ if (buffer == NULL)
+ fail("Failed to get context buffer");
+ if (offset != data->start_element_len)
+ fail("Context offset in unexpected position");
+ if (len != data->cdata_len)
+ fail("CDATA length reported incorrectly");
+ if (size != data->total_string_len)
+ fail("Context size is not full buffer");
+ if (XML_GetCurrentByteIndex(g_parser) != offset)
+ fail("Character byte index incorrect");
+ if (XML_GetCurrentByteCount(g_parser) != len)
+ fail("Character byte count incorrect");
+#else
+ UNUSED_P(s);
+ UNUSED_P(userData);
+ UNUSED_P(len);
+#endif
+}
+
+void XMLCALL
+ext2_accumulate_characters(void *userData, const XML_Char *s, int len) {
+ ExtTest2 *test_data = (ExtTest2 *)userData;
+ accumulate_characters(test_data->storage, s, len);
+}
+
+/* Handlers that record their function name and int arg. */
+
+static void
+record_call(struct handler_record_list *const rec, const char *funcname,
+ const int arg) {
+ const int max_entries = sizeof(rec->entries) / sizeof(rec->entries[0]);
+ assert_true(rec->count < max_entries);
+ struct handler_record_entry *const e = &rec->entries[rec->count++];
+ e->name = funcname;
+ e->arg = arg;
+}
+
+void XMLCALL
+record_default_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ record_call((struct handler_record_list *)userData, __func__, len);
+}
+
+void XMLCALL
+record_cdata_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ record_call((struct handler_record_list *)userData, __func__, len);
+ XML_DefaultCurrent(g_parser);
+}
+
+void XMLCALL
+record_cdata_nodefault_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ record_call((struct handler_record_list *)userData, __func__, len);
+}
+
+void XMLCALL
+record_skip_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity) {
+ UNUSED_P(entityName);
+ record_call((struct handler_record_list *)userData, __func__,
+ is_parameter_entity);
+}
+
+void XMLCALL
+record_element_start_handler(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(atts);
+ CharData_AppendXMLChars((CharData *)userData, name, (int)xcstrlen(name));
+}
+
+void XMLCALL
+record_element_end_handler(void *userData, const XML_Char *name) {
+ CharData *storage = (CharData *)userData;
+
+ CharData_AppendXMLChars(storage, XCS("/"), 1);
+ CharData_AppendXMLChars(storage, name, -1);
+}
+
+const struct handler_record_entry *
+_handler_record_get(const struct handler_record_list *storage, int index,
+ const char *file, int line) {
+ if (storage->count <= index) {
+ _fail(file, line, "too few handler calls");
+ }
+ return &storage->entries[index];
+}
+
+/* Entity Declaration Handlers */
+static const XML_Char *entity_name_to_match = NULL;
+static const XML_Char *entity_value_to_match = NULL;
+static int entity_match_flag = ENTITY_MATCH_NOT_FOUND;
+
+void XMLCALL
+param_entity_match_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity, const XML_Char *value,
+ int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName) {
+ UNUSED_P(userData);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ if (! is_parameter_entity || entity_name_to_match == NULL
+ || entity_value_to_match == NULL) {
+ return;
+ }
+ if (! xcstrcmp(entityName, entity_name_to_match)) {
+ /* The cast here is safe because we control the horizontal and
+ * the vertical, and we therefore know our strings are never
+ * going to overflow an int.
+ */
+ if (value_length != (int)xcstrlen(entity_value_to_match)
+ || xcstrncmp(value, entity_value_to_match, value_length)) {
+ entity_match_flag = ENTITY_MATCH_FAIL;
+ } else {
+ entity_match_flag = ENTITY_MATCH_SUCCESS;
+ }
+ }
+ /* Else leave the match flag alone */
+}
+
+void
+param_entity_match_init(const XML_Char *name, const XML_Char *value) {
+ entity_name_to_match = name;
+ entity_value_to_match = value;
+ entity_match_flag = ENTITY_MATCH_NOT_FOUND;
+}
+
+int
+get_param_entity_match_flag(void) {
+ return entity_match_flag;
+}
+
+/* Misc handlers */
+
+void XMLCALL
+xml_decl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone) {
+ UNUSED_P(version);
+ UNUSED_P(encoding);
+ if (userData != g_handler_data)
+ fail("User data (xml decl) not correctly set");
+ if (standalone != -1)
+ fail("Standalone not flagged as not present in XML decl");
+ g_xdecl_count++;
+}
+
+void XMLCALL
+param_check_skip_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity) {
+ UNUSED_P(entityName);
+ UNUSED_P(is_parameter_entity);
+ if (userData != g_handler_data)
+ fail("User data (skip) not correctly set");
+ g_skip_count++;
+}
+
+void XMLCALL
+data_check_comment_handler(void *userData, const XML_Char *data) {
+ UNUSED_P(data);
+ /* Check that the userData passed through is what we expect */
+ if (userData != g_handler_data)
+ fail("User data (parser) not correctly set");
+ /* Check that the user data in the parser is appropriate */
+ if (XML_GetUserData(userData) != (void *)1)
+ fail("User data in parser not correctly set");
+ g_comment_count++;
+}
+
+void XMLCALL
+selective_aborting_default_handler(void *userData, const XML_Char *s, int len) {
+ const XML_Char trigger_char = *(const XML_Char *)userData;
+
+ int found = 0;
+ for (int i = 0; i < len; ++i) {
+ if (s[i] == trigger_char) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ XML_StopParser(g_parser, g_resumable);
+ XML_SetDefaultHandler(g_parser, NULL);
+ }
+}
+
+void XMLCALL
+suspending_comment_handler(void *userData, const XML_Char *data) {
+ UNUSED_P(data);
+ XML_Parser parser = (XML_Parser)userData;
+ XML_StopParser(parser, XML_TRUE);
+}
+
+void XMLCALL
+element_decl_suspender(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ XML_StopParser(g_parser, XML_TRUE);
+ XML_FreeContentModel(g_parser, model);
+}
+
+void XMLCALL
+accumulate_pi_characters(void *userData, const XML_Char *target,
+ const XML_Char *data) {
+ CharData *storage = (CharData *)userData;
+
+ CharData_AppendXMLChars(storage, target, -1);
+ CharData_AppendXMLChars(storage, XCS(": "), 2);
+ CharData_AppendXMLChars(storage, data, -1);
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
+}
+
+void XMLCALL
+accumulate_comment(void *userData, const XML_Char *data) {
+ CharData *storage = (CharData *)userData;
+
+ CharData_AppendXMLChars(storage, data, -1);
+}
+
+void XMLCALL
+accumulate_entity_decl(void *userData, const XML_Char *entityName,
+ int is_parameter_entity, const XML_Char *value,
+ int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName) {
+ CharData *storage = (CharData *)userData;
+
+ UNUSED_P(is_parameter_entity);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ CharData_AppendXMLChars(storage, entityName, -1);
+ CharData_AppendXMLChars(storage, XCS("="), 1);
+ if (value == NULL)
+ CharData_AppendXMLChars(storage, XCS("(null)"), -1);
+ else
+ CharData_AppendXMLChars(storage, value, value_length);
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
+}
+
+void XMLCALL
+accumulate_char_data(void *userData, const XML_Char *s, int len) {
+ CharData *const storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, s, len);
+}
+
+void XMLCALL
+accumulate_start_element(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ CharData *const storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, XCS("("), 1);
+ CharData_AppendXMLChars(storage, name, -1);
+
+ if ((atts != NULL) && (atts[0] != NULL)) {
+ CharData_AppendXMLChars(storage, XCS("("), 1);
+ while (atts[0] != NULL) {
+ CharData_AppendXMLChars(storage, atts[0], -1);
+ CharData_AppendXMLChars(storage, XCS("="), 1);
+ CharData_AppendXMLChars(storage, atts[1], -1);
+ atts += 2;
+ if (atts[0] != NULL) {
+ CharData_AppendXMLChars(storage, XCS(","), 1);
+ }
+ }
+ CharData_AppendXMLChars(storage, XCS(")"), 1);
+ }
+
+ CharData_AppendXMLChars(storage, XCS(")\n"), 2);
+}
+
+void XMLCALL
+checking_default_handler(void *userData, const XML_Char *s, int len) {
+ DefaultCheck *data = (DefaultCheck *)userData;
+ int i;
+
+ for (i = 0; data[i].expected != NULL; i++) {
+ if (data[i].expectedLen == len
+ && ! memcmp(data[i].expected, s, len * sizeof(XML_Char))) {
+ data[i].seen = XML_TRUE;
+ break;
+ }
+ }
+}
+
+void XMLCALL
+accumulate_and_suspend_comment_handler(void *userData, const XML_Char *data) {
+ ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData;
+ accumulate_comment(parserPlusStorage->storage, data);
+ XML_StopParser(parserPlusStorage->parser, XML_TRUE);
+}
diff --git a/contrib/expat/tests/handlers.h b/contrib/expat/tests/handlers.h
new file mode 100644
index 000000000000..e1f0995f79e6
--- /dev/null
+++ b/contrib/expat/tests/handlers.h
@@ -0,0 +1,595 @@
+/* XML handler functions for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_HANDLERS_H
+# define XML_HANDLERS_H
+
+# include "expat_config.h"
+
+# include "expat.h"
+
+/* Variable holding the expected handler userData */
+extern const void *g_handler_data;
+/* Count of the number of times the comment handler has been invoked */
+extern int g_comment_count;
+/* Count of the number of skipped entities */
+extern int g_skip_count;
+/* Count of the number of times the XML declaration handler is invoked */
+extern int g_xdecl_count;
+
+/* Start/End Element Handlers */
+
+extern void XMLCALL start_element_event_handler(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL end_element_event_handler(void *userData,
+ const XML_Char *name);
+
+# define STRUCT_START_TAG 0
+# define STRUCT_END_TAG 1
+
+extern void XMLCALL start_element_event_handler2(void *userData,
+ const XML_Char *name,
+ const XML_Char **attr);
+
+extern void XMLCALL end_element_event_handler2(void *userData,
+ const XML_Char *name);
+
+typedef struct attrInfo {
+ const XML_Char *name;
+ const XML_Char *value;
+} AttrInfo;
+
+typedef struct elementInfo {
+ const XML_Char *name;
+ int attr_count;
+ const XML_Char *id_name;
+ AttrInfo *attributes;
+} ElementInfo;
+
+extern void XMLCALL counting_start_element_handler(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL suspending_end_handler(void *userData, const XML_Char *s);
+
+extern void XMLCALL start_element_suspender(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+extern int g_triplet_start_flag;
+extern int g_triplet_end_flag;
+
+extern void XMLCALL triplet_start_checker(void *userData, const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL triplet_end_checker(void *userData, const XML_Char *name);
+
+extern void XMLCALL overwrite_start_checker(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL overwrite_end_checker(void *userData, const XML_Char *name);
+
+extern void XMLCALL start_element_fail(void *userData, const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL start_ns_clearing_start_element(void *userData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
+
+typedef struct {
+ XML_Parser parser;
+ int deep;
+} DataIssue240;
+
+extern void XMLCALL start_element_issue_240(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL end_element_issue_240(void *userData, const XML_Char *name);
+
+/* Text encoding handlers */
+
+extern int XMLCALL UnknownEncodingHandler(void *data, const XML_Char *encoding,
+ XML_Encoding *info);
+
+extern int XMLCALL UnrecognisedEncodingHandler(void *data,
+ const XML_Char *encoding,
+ XML_Encoding *info);
+
+extern int XMLCALL unknown_released_encoding_handler(void *data,
+ const XML_Char *encoding,
+ XML_Encoding *info);
+
+extern int XMLCALL MiscEncodingHandler(void *data, const XML_Char *encoding,
+ XML_Encoding *info);
+
+extern int XMLCALL long_encoding_handler(void *userData,
+ const XML_Char *encoding,
+ XML_Encoding *info);
+
+/* External Entity Handlers */
+
+typedef struct ExtOption {
+ const XML_Char *system_id;
+ const char *parse_text;
+} ExtOption;
+
+extern int XMLCALL external_entity_optioner(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_loader(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+typedef struct ext_faults {
+ const char *parse_text;
+ const char *fail_text;
+ const XML_Char *encoding;
+ enum XML_Error error;
+} ExtFaults;
+
+extern int XMLCALL external_entity_faulter(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+extern int XMLCALL external_entity_failer__if_not_xml_ge(
+ XML_Parser parser, const XML_Char *context, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId);
+extern int XMLCALL external_entity_null_loader(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_resetter(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_suspender(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_suspend_xmldecl(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_suspending_faulter(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_cr_catcher(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_bad_cr_catcher(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_rsqb_catcher(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_good_cdata_ascii(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* Entity declaration handlers */
+
+extern void XMLCALL entity_suspending_decl_handler(void *userData,
+ const XML_Char *name,
+ XML_Content *model);
+
+extern void XMLCALL entity_suspending_xdecl_handler(void *userData,
+ const XML_Char *version,
+ const XML_Char *encoding,
+ int standalone);
+
+extern int XMLCALL external_entity_param_checker(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_ref_param_checker(XML_Parser parameter,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_param(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_load_ignore(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_load_ignore_utf16(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_load_ignore_utf16_be(
+ XML_Parser parser, const XML_Char *context, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId);
+
+extern int XMLCALL external_entity_valuer(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_not_standalone(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_value_aborter(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_public(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_devaluer(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+typedef struct ext_hdlr_data {
+ const char *parse_text;
+ XML_ExternalEntityRefHandler handler;
+} ExtHdlrData;
+
+extern int XMLCALL external_entity_oneshot_loader(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+typedef struct ExtTest2 {
+ const char *parse_text;
+ int parse_len;
+ const XML_Char *encoding;
+ CharData *storage;
+} ExtTest2;
+
+extern int XMLCALL external_entity_loader2(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+typedef struct ExtFaults2 {
+ const char *parse_text;
+ int parse_len;
+ const char *fail_text;
+ const XML_Char *encoding;
+ enum XML_Error error;
+} ExtFaults2;
+
+extern int XMLCALL external_entity_faulter2(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_unfinished_attlist(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_handler(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_duff_loader(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_dbl_handler(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_dbl_handler_2(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_alloc_set_encoding(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_reallocator(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_alloc(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+extern int XMLCALL external_entity_parser_create_alloc_fail_handler(
+ XML_Parser parser, const XML_Char *context, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId);
+
+struct AccountingTestCase {
+ const char *primaryText;
+ const char *firstExternalText; /* often NULL */
+ const char *secondExternalText; /* often NULL */
+ const unsigned long long expectedCountBytesIndirectExtra;
+};
+
+extern int accounting_external_entity_ref_handler(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* NotStandalone handlers */
+
+extern int XMLCALL reject_not_standalone_handler(void *userData);
+
+extern int XMLCALL accept_not_standalone_handler(void *userData);
+
+/* Attribute List handlers */
+
+typedef struct AttTest {
+ const char *definition;
+ const XML_Char *element_name;
+ const XML_Char *attr_name;
+ const XML_Char *attr_type;
+ const XML_Char *default_value;
+ int is_required;
+} AttTest;
+
+extern void XMLCALL verify_attlist_decl_handler(
+ void *userData, const XML_Char *element_name, const XML_Char *attr_name,
+ const XML_Char *attr_type, const XML_Char *default_value, int is_required);
+
+/* Character data handlers */
+
+extern void XMLCALL clearing_aborting_character_handler(void *userData,
+ const XML_Char *s,
+ int len);
+
+extern void XMLCALL parser_stop_character_handler(void *userData,
+ const XML_Char *s, int len);
+
+extern void XMLCALL cr_cdata_handler(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL rsqb_handler(void *userData, const XML_Char *s, int len);
+
+typedef struct ByteTestData {
+ int start_element_len;
+ int cdata_len;
+ int total_string_len;
+} ByteTestData;
+
+extern void XMLCALL byte_character_handler(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL ext2_accumulate_characters(void *userData,
+ const XML_Char *s, int len);
+
+/* Handlers that record their `len` arg and a single identifying character */
+
+struct handler_record_entry {
+ const char *name;
+ int arg;
+};
+struct handler_record_list {
+ int count;
+ struct handler_record_entry entries[50]; // arbitrary big-enough max count
+};
+
+extern void XMLCALL record_default_handler(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL record_cdata_handler(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL record_cdata_nodefault_handler(void *userData,
+ const XML_Char *s, int len);
+
+extern void XMLCALL record_skip_handler(void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity);
+
+extern void XMLCALL record_element_start_handler(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+extern void XMLCALL record_element_end_handler(void *userData,
+ const XML_Char *name);
+
+extern const struct handler_record_entry *
+_handler_record_get(const struct handler_record_list *storage, int index,
+ const char *file, int line);
+
+# define handler_record_get(storage, index) \
+ _handler_record_get((storage), (index), __FILE__, __LINE__)
+
+# define assert_record_handler_called(storage, index, expected_name, \
+ expected_arg) \
+ do { \
+ const struct handler_record_entry *e \
+ = handler_record_get(storage, index); \
+ assert_true(strcmp(e->name, expected_name) == 0); \
+ assert_true(e->arg == (expected_arg)); \
+ } while (0)
+
+/* Entity Declaration Handlers */
+# define ENTITY_MATCH_FAIL (-1)
+# define ENTITY_MATCH_NOT_FOUND (0)
+# define ENTITY_MATCH_SUCCESS (1)
+
+extern void XMLCALL param_entity_match_handler(
+ void *userData, const XML_Char *entityName, int is_parameter_entity,
+ const XML_Char *value, int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName);
+
+extern void param_entity_match_init(const XML_Char *name,
+ const XML_Char *value);
+
+extern int get_param_entity_match_flag(void);
+
+/* Misc handlers */
+
+extern void XMLCALL xml_decl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone);
+
+extern void XMLCALL param_check_skip_handler(void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity);
+
+extern void XMLCALL data_check_comment_handler(void *userData,
+ const XML_Char *data);
+
+extern void XMLCALL selective_aborting_default_handler(void *userData,
+ const XML_Char *s,
+ int len);
+
+extern void XMLCALL suspending_comment_handler(void *userData,
+ const XML_Char *data);
+
+extern void XMLCALL element_decl_suspender(void *userData, const XML_Char *name,
+ XML_Content *model);
+
+extern void XMLCALL accumulate_pi_characters(void *userData,
+ const XML_Char *target,
+ const XML_Char *data);
+
+extern void XMLCALL accumulate_comment(void *userData, const XML_Char *data);
+
+extern void XMLCALL accumulate_entity_decl(
+ void *userData, const XML_Char *entityName, int is_parameter_entity,
+ const XML_Char *value, int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName);
+
+extern void XMLCALL accumulate_char_data(void *userData, const XML_Char *s,
+ int len);
+
+extern void XMLCALL accumulate_start_element(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+typedef struct default_check {
+ const XML_Char *expected;
+ const int expectedLen;
+ XML_Bool seen;
+} DefaultCheck;
+
+void XMLCALL checking_default_handler(void *userData, const XML_Char *s,
+ int len);
+
+typedef struct {
+ XML_Parser parser;
+ CharData *storage;
+} ParserPlusStorage;
+
+extern void XMLCALL
+accumulate_and_suspend_comment_handler(void *userData, const XML_Char *data);
+
+#endif /* XML_HANDLERS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/handlers_cxx.cpp b/contrib/expat/tests/handlers_cxx.cpp
new file mode 100644
index 000000000000..86c62b159cc7
--- /dev/null
+++ b/contrib/expat/tests/handlers_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "handlers.c"
diff --git a/contrib/expat/tests/memcheck.c b/contrib/expat/tests/memcheck.c
index 41355f6c8d91..de9254997214 100644
--- a/contrib/expat/tests/memcheck.c
+++ b/contrib/expat/tests/memcheck.c
@@ -6,8 +6,9 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -49,12 +50,13 @@ typedef struct allocation_entry {
static AllocationEntry *alloc_head = NULL;
static AllocationEntry *alloc_tail = NULL;
-static AllocationEntry *find_allocation(void *ptr);
+static AllocationEntry *find_allocation(const void *ptr);
/* Allocate some memory and keep track of it. */
void *
tracking_malloc(size_t size) {
- AllocationEntry *entry = malloc(sizeof(AllocationEntry));
+ AllocationEntry *const entry
+ = (AllocationEntry *)malloc(sizeof(AllocationEntry));
if (entry == NULL) {
printf("Allocator failure\n");
@@ -82,7 +84,7 @@ tracking_malloc(size_t size) {
}
static AllocationEntry *
-find_allocation(void *ptr) {
+find_allocation(const void *ptr) {
AllocationEntry *entry;
for (entry = alloc_head; entry != NULL; entry = entry->next) {
@@ -140,7 +142,7 @@ tracking_realloc(void *ptr, size_t size) {
entry = find_allocation(ptr);
if (entry == NULL) {
printf("Attempting to realloc unallocated memory at %p\n", ptr);
- entry = malloc(sizeof(AllocationEntry));
+ entry = (AllocationEntry *)malloc(sizeof(AllocationEntry));
if (entry == NULL) {
printf("Reallocator failure\n");
return NULL;
@@ -162,12 +164,11 @@ tracking_realloc(void *ptr, size_t size) {
alloc_tail = entry;
}
} else {
- entry->allocation = realloc(ptr, size);
- if (entry->allocation == NULL) {
- /* Realloc semantics say the original is still allocated */
- entry->allocation = ptr;
+ void *const reallocated = realloc(ptr, size);
+ if (reallocated == NULL) {
return NULL;
}
+ entry->allocation = reallocated;
}
entry->num_bytes = size;
diff --git a/contrib/expat/tests/memcheck.h b/contrib/expat/tests/memcheck.h
index 4d20f4bb972d..4c0cb7281b91 100644
--- a/contrib/expat/tests/memcheck.h
+++ b/contrib/expat/tests/memcheck.h
@@ -7,8 +7,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/tests/memcheck_cxx.cpp b/contrib/expat/tests/memcheck_cxx.cpp
new file mode 100644
index 000000000000..e62ac98999c8
--- /dev/null
+++ b/contrib/expat/tests/memcheck_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "memcheck.c"
diff --git a/contrib/expat/tests/minicheck.c b/contrib/expat/tests/minicheck.c
index a5a1efb159f5..baccd76b4415 100644
--- a/contrib/expat/tests/minicheck.c
+++ b/contrib/expat/tests/minicheck.c
@@ -10,8 +10,12 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2004-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -34,6 +38,11 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
+#endif
+
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
@@ -85,7 +94,8 @@ tcase_add_test(TCase *tc, tcase_test_function test) {
if (tc->allocated == tc->ntests) {
int nalloc = tc->allocated + 100;
size_t new_size = sizeof(tcase_test_function) * nalloc;
- tcase_test_function *new_tests = realloc(tc->tests, new_size);
+ tcase_test_function *const new_tests
+ = (tcase_test_function *)realloc(tc->tests, new_size);
assert(new_tests != NULL);
tc->tests = new_tests;
tc->allocated = nalloc;
@@ -120,7 +130,7 @@ suite_free(Suite *suite) {
SRunner *
srunner_create(Suite *suite) {
- SRunner *runner = calloc(1, sizeof(SRunner));
+ SRunner *const runner = (SRunner *)calloc(1, sizeof(SRunner));
if (runner != NULL) {
runner->suite = suite;
}
@@ -129,28 +139,57 @@ srunner_create(Suite *suite) {
static jmp_buf env;
+#define SUBTEST_LEN (50) // informative, but not too long
static char const *_check_current_function = NULL;
+static char _check_current_subtest[SUBTEST_LEN];
static int _check_current_lineno = -1;
static char const *_check_current_filename = NULL;
void
_check_set_test_info(char const *function, char const *filename, int lineno) {
_check_current_function = function;
+ set_subtest("%s", "");
_check_current_lineno = lineno;
_check_current_filename = filename;
}
+void
+set_subtest(char const *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(_check_current_subtest, SUBTEST_LEN, fmt, ap);
+ va_end(ap);
+ // replace line feeds with spaces, for nicer error logs
+ for (size_t i = 0; i < SUBTEST_LEN; ++i) {
+ if (_check_current_subtest[i] == '\n') {
+ _check_current_subtest[i] = ' ';
+ }
+ }
+ _check_current_subtest[SUBTEST_LEN - 1] = '\0'; // ensure termination
+}
+
static void
-add_failure(SRunner *runner, int verbosity) {
- runner->nfailures++;
+handle_success(int verbosity) {
if (verbosity >= CK_VERBOSE) {
- printf("%s:%d: %s\n", _check_current_filename, _check_current_lineno,
- _check_current_function);
+ printf("PASS: %s\n", _check_current_function);
+ }
+}
+
+static void
+handle_failure(SRunner *runner, int verbosity, const char *context,
+ const char *phase_info) {
+ runner->nfailures++;
+ if (verbosity != CK_SILENT) {
+ if (strlen(_check_current_subtest) != 0) {
+ phase_info = _check_current_subtest;
+ }
+ printf("FAIL [%s]: %s (%s at %s:%d)\n", context, _check_current_function,
+ phase_info, _check_current_filename, _check_current_lineno);
}
}
void
-srunner_run_all(SRunner *runner, int verbosity) {
+srunner_run_all(SRunner *runner, const char *context, int verbosity) {
Suite *suite;
TCase *volatile tc;
assert(runner != NULL);
@@ -160,34 +199,42 @@ srunner_run_all(SRunner *runner, int verbosity) {
volatile int i;
for (i = 0; i < tc->ntests; ++i) {
runner->nchecks++;
+ set_subtest("%s", "");
if (tc->setup != NULL) {
/* setup */
if (setjmp(env)) {
- add_failure(runner, verbosity);
+ handle_failure(runner, verbosity, context, "during setup");
continue;
}
tc->setup();
}
/* test */
if (setjmp(env)) {
- add_failure(runner, verbosity);
+ handle_failure(runner, verbosity, context, "during actual test");
continue;
}
(tc->tests[i])();
+ set_subtest("%s", "");
/* teardown */
if (tc->teardown != NULL) {
if (setjmp(env)) {
- add_failure(runner, verbosity);
+ handle_failure(runner, verbosity, context, "during teardown");
continue;
}
tc->teardown();
}
+
+ handle_success(verbosity);
}
tc = tc->next_tcase;
}
- if (verbosity) {
+}
+
+void
+srunner_summarize(SRunner *runner, int verbosity) {
+ if (verbosity != CK_SILENT) {
int passed = runner->nchecks - runner->nfailures;
double percentage = ((double)passed) / runner->nchecks;
int display = (int)(percentage * 100);
@@ -197,14 +244,13 @@ srunner_run_all(SRunner *runner, int verbosity) {
}
void
-_fail_unless(int condition, const char *file, int line, const char *msg) {
+_fail(const char *file, int line, const char *msg) {
/* Always print the error message so it isn't lost. In this case,
we have a failure, so there's no reason to be quiet about what
it is.
*/
- UNUSED_P(condition);
- UNUSED_P(file);
- UNUSED_P(line);
+ _check_current_filename = file;
+ _check_current_lineno = line;
if (msg != NULL) {
const int has_newline = (msg[strlen(msg) - 1] == '\n');
fprintf(stderr, "ERROR: %s%s", msg, has_newline ? "" : "\n");
diff --git a/contrib/expat/tests/minicheck.h b/contrib/expat/tests/minicheck.h
index 88a16584fb5b..3d888f8d2a36 100644
--- a/contrib/expat/tests/minicheck.h
+++ b/contrib/expat/tests/minicheck.h
@@ -12,8 +12,11 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2004-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2006-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -40,30 +43,54 @@
extern "C" {
#endif
-#define CK_NOFORK 0
-#define CK_FORK 1
+#ifndef XML_MINICHECK_H
+# define XML_MINICHECK_H
-#define CK_SILENT 0
-#define CK_NORMAL 1
-#define CK_VERBOSE 2
+# define CK_NOFORK 0
+# define CK_FORK 1
+
+# define CK_SILENT 0
+# define CK_NORMAL 1
+# define CK_VERBOSE 2
/* Workaround for Microsoft's compiler and Tru64 Unix systems where the
C compiler has a working __func__, but the C++ compiler only has a
working __FUNCTION__. This could be fixed in configure.in, but it's
not worth it right now. */
-#if defined(_MSC_VER) || (defined(__osf__) && defined(__cplusplus))
-# define __func__ __FUNCTION__
-#endif
-
-#define START_TEST(testname) \
- static void testname(void) { \
- _check_set_test_info(__func__, __FILE__, __LINE__); \
- {
-#define END_TEST \
- } \
- }
-
-#define fail(msg) _fail_unless(0, __FILE__, __LINE__, msg)
+# if defined(_MSC_VER) || (defined(__osf__) && defined(__cplusplus))
+# define __func__ __FUNCTION__
+# endif
+
+/* PRINTF_LIKE has two effects:
+ 1. Make clang's -Wformat-nonliteral stop warning about non-literal format
+ strings in annotated functions' code.
+ 2. Make both clang and gcc's -Wformat-nonliteral warn about *callers* of
+ the annotated function that use a non-literal format string.
+*/
+# if defined(__GNUC__)
+# define PRINTF_LIKE(fmtpos, argspos) \
+ __attribute__((format(printf, fmtpos, argspos)))
+# else
+# define PRINTF_LIKE(fmtpos, argspos)
+# endif
+
+# define START_TEST(testname) \
+ static void testname(void) { \
+ _check_set_test_info(__func__, __FILE__, __LINE__); \
+ {
+# define END_TEST \
+ } \
+ }
+
+void PRINTF_LIKE(1, 2) set_subtest(char const *fmt, ...);
+
+# define fail(msg) _fail(__FILE__, __LINE__, msg)
+# define assert_true(cond) \
+ do { \
+ if (! (cond)) { \
+ _fail(__FILE__, __LINE__, "check failed: " #cond); \
+ } \
+ } while (0)
typedef void (*tcase_setup_function)(void);
typedef void (*tcase_teardown_function)(void);
@@ -102,18 +129,25 @@ void _check_set_test_info(char const *function, char const *filename,
* Prototypes for the actual implementation.
*/
-void _fail_unless(int condition, const char *file, int line, const char *msg);
+# if defined(__GNUC__)
+__attribute__((noreturn))
+# endif
+void
+_fail(const char *file, int line, const char *msg);
Suite *suite_create(const char *name);
TCase *tcase_create(const char *name);
void suite_add_tcase(Suite *suite, TCase *tc);
-void tcase_add_checked_fixture(TCase *, tcase_setup_function,
- tcase_teardown_function);
+void tcase_add_checked_fixture(TCase *tc, tcase_setup_function setup,
+ tcase_teardown_function teardown);
void tcase_add_test(TCase *tc, tcase_test_function test);
SRunner *srunner_create(Suite *suite);
-void srunner_run_all(SRunner *runner, int verbosity);
+void srunner_run_all(SRunner *runner, const char *context, int verbosity);
+void srunner_summarize(SRunner *runner, int verbosity);
int srunner_ntests_failed(SRunner *runner);
void srunner_free(SRunner *runner);
+#endif /* XML_MINICHECK_H */
+
#ifdef __cplusplus
}
#endif
diff --git a/contrib/expat/tests/minicheck_cxx.cpp b/contrib/expat/tests/minicheck_cxx.cpp
new file mode 100644
index 000000000000..58881c60ba07
--- /dev/null
+++ b/contrib/expat/tests/minicheck_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "minicheck.c"
diff --git a/contrib/expat/tests/misc_tests.c b/contrib/expat/tests/misc_tests.c
new file mode 100644
index 000000000000..b5212f58a5bb
--- /dev/null
+++ b/contrib/expat/tests/misc_tests.c
@@ -0,0 +1,523 @@
+/* Tests in the "miscellaneous" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "expat_config.h"
+
+#include "expat.h"
+#include "internal.h"
+#include "minicheck.h"
+#include "memcheck.h"
+#include "common.h"
+#include "ascii.h" /* for ASCII_xxx */
+#include "handlers.h"
+#include "misc_tests.h"
+
+/* Test that a failure to allocate the parser structure fails gracefully */
+START_TEST(test_misc_alloc_create_parser) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
+ unsigned int i;
+ const unsigned int max_alloc_count = 10;
+
+ /* Something this simple shouldn't need more than 10 allocations */
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
+ if (g_parser != NULL)
+ break;
+ }
+ if (i == 0)
+ fail("Parser unexpectedly ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Parser not created with max allocation count");
+}
+END_TEST
+
+/* Test memory allocation failures for a parser with an encoding */
+START_TEST(test_misc_alloc_create_parser_with_encoding) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
+ unsigned int i;
+ const unsigned int max_alloc_count = 10;
+
+ /* Try several levels of allocation */
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ g_parser = XML_ParserCreate_MM(XCS("us-ascii"), &memsuite, NULL);
+ if (g_parser != NULL)
+ break;
+ }
+ if (i == 0)
+ fail("Parser ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Parser not created with max allocation count");
+}
+END_TEST
+
+/* Test that freeing a NULL parser doesn't cause an explosion.
+ * (Not actually tested anywhere else)
+ */
+START_TEST(test_misc_null_parser) {
+ XML_ParserFree(NULL);
+}
+END_TEST
+
+#if defined(__has_feature)
+# if __has_feature(undefined_behavior_sanitizer)
+# define EXPAT_TESTS_UBSAN 1
+# else
+# define EXPAT_TESTS_UBSAN 0
+# endif
+#else
+# define EXPAT_TESTS_UBSAN 0
+#endif
+
+/* Test that XML_ErrorString rejects out-of-range codes */
+START_TEST(test_misc_error_string) {
+#if ! EXPAT_TESTS_UBSAN // because this would trigger UBSan
+ union {
+ enum XML_Error xml_error;
+ int integer;
+ } trickery;
+
+ assert_true(sizeof(enum XML_Error) == sizeof(int)); // self-test
+
+ trickery.integer = -1;
+ if (XML_ErrorString(trickery.xml_error) != NULL)
+ fail("Negative error code not rejected");
+
+ trickery.integer = 100;
+ if (XML_ErrorString(trickery.xml_error) != NULL)
+ fail("Large error code not rejected");
+#endif
+}
+END_TEST
+
+/* Test the version information is consistent */
+
+/* Since we are working in XML_LChars (potentially 16-bits), we
+ * can't use the standard C library functions for character
+ * manipulation and have to roll our own.
+ */
+static int
+parse_version(const XML_LChar *version_text,
+ XML_Expat_Version *version_struct) {
+ if (! version_text)
+ return XML_FALSE;
+
+ while (*version_text != 0x00) {
+ if (*version_text >= ASCII_0 && *version_text <= ASCII_9)
+ break;
+ version_text++;
+ }
+ if (*version_text == 0x00)
+ return XML_FALSE;
+
+ /* version_struct->major = strtoul(version_text, 10, &version_text) */
+ version_struct->major = 0;
+ while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
+ version_struct->major
+ = 10 * version_struct->major + (*version_text++ - ASCII_0);
+ }
+ if (*version_text++ != ASCII_PERIOD)
+ return XML_FALSE;
+
+ /* Now for the minor version number */
+ version_struct->minor = 0;
+ while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
+ version_struct->minor
+ = 10 * version_struct->minor + (*version_text++ - ASCII_0);
+ }
+ if (*version_text++ != ASCII_PERIOD)
+ return XML_FALSE;
+
+ /* Finally the micro version number */
+ version_struct->micro = 0;
+ while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
+ version_struct->micro
+ = 10 * version_struct->micro + (*version_text++ - ASCII_0);
+ }
+ if (*version_text != 0x00)
+ return XML_FALSE;
+ return XML_TRUE;
+}
+
+static int
+versions_equal(const XML_Expat_Version *first,
+ const XML_Expat_Version *second) {
+ return (first->major == second->major && first->minor == second->minor
+ && first->micro == second->micro);
+}
+
+START_TEST(test_misc_version) {
+ XML_Expat_Version read_version = XML_ExpatVersionInfo();
+ /* Silence compiler warning with the following assignment */
+ XML_Expat_Version parsed_version = {0, 0, 0};
+ const XML_LChar *version_text = XML_ExpatVersion();
+
+ if (version_text == NULL)
+ fail("Could not obtain version text");
+ assert(version_text != NULL);
+ if (! parse_version(version_text, &parsed_version))
+ fail("Unable to parse version text");
+ if (! versions_equal(&read_version, &parsed_version))
+ fail("Version mismatch");
+
+ if (xcstrcmp(version_text, XCS("expat_2.6.0"))) /* needs bump on releases */
+ fail("XML_*_VERSION in expat.h out of sync?\n");
+}
+END_TEST
+
+/* Test feature information */
+START_TEST(test_misc_features) {
+ const XML_Feature *features = XML_GetFeatureList();
+
+ /* Prevent problems with double-freeing parsers */
+ g_parser = NULL;
+ if (features == NULL) {
+ fail("Failed to get feature information");
+ } else {
+ /* Loop through the features checking what we can */
+ while (features->feature != XML_FEATURE_END) {
+ switch (features->feature) {
+ case XML_FEATURE_SIZEOF_XML_CHAR:
+ if (features->value != sizeof(XML_Char))
+ fail("Incorrect size of XML_Char");
+ break;
+ case XML_FEATURE_SIZEOF_XML_LCHAR:
+ if (features->value != sizeof(XML_LChar))
+ fail("Incorrect size of XML_LChar");
+ break;
+ default:
+ break;
+ }
+ features++;
+ }
+ }
+}
+END_TEST
+
+/* Regression test for GitHub Issue #17: memory leak parsing attribute
+ * values with mixed bound and unbound namespaces.
+ */
+START_TEST(test_misc_attribute_leak) {
+ const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>";
+ XML_Memory_Handling_Suite memsuite
+ = {tracking_malloc, tracking_realloc, tracking_free};
+
+ g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n"));
+ expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found");
+ XML_ParserFree(g_parser);
+ /* Prevent the teardown trying to double free */
+ g_parser = NULL;
+
+ if (! tracking_report())
+ fail("Memory leak found");
+}
+END_TEST
+
+/* Test parser created for UTF-16LE is successful */
+START_TEST(test_misc_utf16le) {
+ const char text[] =
+ /* <?xml version='1.0'?><q>Hi</q> */
+ "<\0?\0x\0m\0l\0 \0"
+ "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0"
+ "<\0q\0>\0H\0i\0<\0/\0q\0>\0";
+ const XML_Char *expected = XCS("Hi");
+ CharData storage;
+
+ g_parser = XML_ParserCreate(XCS("UTF-16LE"));
+ if (g_parser == NULL)
+ fail("Parser not created");
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
+ XML_Parser parser;
+ DataIssue240 *mydata;
+ enum XML_Status result;
+ const char *const doc1 = "<doc><e1/><e><foo/></e></doc>";
+
+ parser = XML_ParserCreate(NULL);
+ XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
+ mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
+ mydata->parser = parser;
+ mydata->deep = 0;
+ XML_SetUserData(parser, mydata);
+
+ result = _XML_Parse_SINGLE_BYTES(parser, doc1, (int)strlen(doc1), 1);
+ XML_ParserFree(parser);
+ free(mydata);
+ if (result != XML_STATUS_ERROR)
+ fail("Stopping the parser did not work as expected");
+}
+END_TEST
+
+START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
+ XML_Parser parser;
+ DataIssue240 *mydata;
+ enum XML_Status result;
+ const char *const doc2 = "<doc><elem/></doc>";
+
+ parser = XML_ParserCreate(NULL);
+ XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
+ mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
+ mydata->parser = parser;
+ mydata->deep = 0;
+ XML_SetUserData(parser, mydata);
+
+ result = _XML_Parse_SINGLE_BYTES(parser, doc2, (int)strlen(doc2), 1);
+ XML_ParserFree(parser);
+ free(mydata);
+ if (result != XML_STATUS_ERROR)
+ fail("Stopping the parser did not work as expected");
+}
+END_TEST
+
+START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
+ const char *const inputOne = "<!DOCTYPE d [\n"
+ "<!ENTITY % e ']><d/>'>\n"
+ "\n"
+ "%e;";
+ const char *const inputTwo = "<!DOCTYPE d [\n"
+ "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&e1;'>\n"
+ "\n"
+ "%e2;";
+ const char *const inputThree = "<!DOCTYPE d [\n"
+ "<!ENTITY % e ']><d'>\n"
+ "\n"
+ "%e;";
+ const char *const inputIssue317 = "<!DOCTYPE doc [\n"
+ "<!ENTITY % foo ']>\n"
+ "<doc>Hell<oc (#PCDATA)*>'>\n"
+ "%foo;\n"
+ "]>\n"
+ "<doc>Hello, world</dVc>";
+
+ const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
+ size_t inputIndex = 0;
+
+ for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
+ set_subtest("%s", inputs[inputIndex]);
+ XML_Parser parser;
+ enum XML_Status parseResult;
+ int setParamEntityResult;
+ XML_Size lineNumber;
+ XML_Size columnNumber;
+ const char *const input = inputs[inputIndex];
+
+ parser = XML_ParserCreate(NULL);
+ setParamEntityResult
+ = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ if (setParamEntityResult != 1)
+ fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
+
+ parseResult = _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0);
+ if (parseResult != XML_STATUS_ERROR) {
+ parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1);
+ if (parseResult != XML_STATUS_ERROR) {
+ fail("Parsing was expected to fail but succeeded.");
+ }
+ }
+
+ if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
+ fail("Error code does not match XML_ERROR_INVALID_TOKEN");
+
+ lineNumber = XML_GetCurrentLineNumber(parser);
+ if (lineNumber != 4)
+ fail("XML_GetCurrentLineNumber does not work as expected.");
+
+ columnNumber = XML_GetCurrentColumnNumber(parser);
+ if (columnNumber != 0)
+ fail("XML_GetCurrentColumnNumber does not work as expected.");
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+START_TEST(test_misc_tag_mismatch_reset_leak) {
+#ifdef XML_NS
+ const char *const text = "<open xmlns='https://namespace1.test'></close>";
+ XML_Parser parser = XML_ParserCreateNS(NULL, XCS('\n'));
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Call to parse was expected to fail");
+ if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH)
+ fail("Call to parse was expected to fail from a closing tag mismatch");
+
+ XML_ParserReset(parser, NULL);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Call to parse was expected to fail");
+ if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH)
+ fail("Call to parse was expected to fail from a closing tag mismatch");
+
+ XML_ParserFree(parser);
+#endif
+}
+END_TEST
+
+START_TEST(test_misc_create_external_entity_parser_with_null_context) {
+ // With XML_DTD undefined, the only supported case of external entities
+ // is pattern "<!ENTITY entity123 SYSTEM 'filename123'>". A NULL context
+ // was causing a segfault through a null pointer dereference in function
+ // setContext, previously.
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
+#ifdef XML_DTD
+ assert_true(ext_parser != NULL);
+ XML_ParserFree(ext_parser);
+#else
+ assert_true(ext_parser == NULL);
+#endif /* XML_DTD */
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_misc_general_entities_support) {
+ const char *const doc
+ = "<!DOCTYPE r [\n"
+ "<!ENTITY e1 'v1'>\n"
+ "<!ENTITY e2 SYSTEM 'v2'>\n"
+ "]>\n"
+ "<r a1='[&e1;]'>[&e1;][&e2;][&amp;&apos;&gt;&lt;&quot;]</r>";
+
+ CharData storage;
+ CharData_Init(&storage);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_SetUserData(parser, &storage);
+ XML_SetStartElementHandler(parser, accumulate_start_element);
+ XML_SetExternalEntityRefHandler(parser,
+ external_entity_failer__if_not_xml_ge);
+ XML_SetEntityDeclHandler(parser, accumulate_entity_decl);
+ XML_SetCharacterDataHandler(parser, accumulate_char_data);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
+ != XML_STATUS_OK) {
+ xml_failure(parser);
+ }
+
+ XML_ParserFree(parser);
+
+ CharData_CheckXMLChars(&storage,
+ /* clang-format off */
+#if XML_GE == 1
+ XCS("e1=v1\n")
+ XCS("e2=(null)\n")
+ XCS("(r(a1=[v1]))\n")
+ XCS("[v1][][&'><\"]")
+#else
+ XCS("e1=&amp;e1;\n")
+ XCS("e2=(null)\n")
+ XCS("(r(a1=[&e1;]))\n")
+ XCS("[&e1;][&e2;][&'><\"]")
+#endif
+ );
+ /* clang-format on */
+}
+END_TEST
+
+static void XMLCALL
+resumable_stopping_character_handler(void *userData, const XML_Char *s,
+ int len) {
+ UNUSED_P(s);
+ UNUSED_P(len);
+ XML_Parser parser = (XML_Parser)userData;
+ XML_StopParser(parser, XML_TRUE);
+}
+
+// NOTE: This test needs active LeakSanitizer to be of actual use
+START_TEST(test_misc_char_handler_stop_without_leak) {
+ const char *const data
+ = "<!DOCTYPE t1[<!ENTITY e1 'angle<'><!ENTITY e2 '&e1;'>]><t1>&e2;";
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ XML_SetUserData(parser, parser);
+ XML_SetCharacterDataHandler(parser, resumable_stopping_character_handler);
+ _XML_Parse_SINGLE_BYTES(parser, data, (int)strlen(data), XML_FALSE);
+ XML_ParserFree(parser);
+}
+END_TEST
+
+void
+make_miscellaneous_test_case(Suite *s) {
+ TCase *tc_misc = tcase_create("miscellaneous tests");
+
+ suite_add_tcase(s, tc_misc);
+ tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
+
+ tcase_add_test(tc_misc, test_misc_alloc_create_parser);
+ tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding);
+ tcase_add_test(tc_misc, test_misc_null_parser);
+ tcase_add_test(tc_misc, test_misc_error_string);
+ tcase_add_test(tc_misc, test_misc_version);
+ tcase_add_test(tc_misc, test_misc_features);
+ tcase_add_test(tc_misc, test_misc_attribute_leak);
+ tcase_add_test(tc_misc, test_misc_utf16le);
+ tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_1);
+ tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2);
+ tcase_add_test__ifdef_xml_dtd(
+ tc_misc, test_misc_deny_internal_entity_closing_doctype_issue_317);
+ tcase_add_test(tc_misc, test_misc_tag_mismatch_reset_leak);
+ tcase_add_test(tc_misc,
+ test_misc_create_external_entity_parser_with_null_context);
+ tcase_add_test(tc_misc, test_misc_general_entities_support);
+ tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak);
+}
diff --git a/contrib/expat/tests/misc_tests.h b/contrib/expat/tests/misc_tests.h
new file mode 100644
index 000000000000..3d9c4b8a4065
--- /dev/null
+++ b/contrib/expat/tests/misc_tests.h
@@ -0,0 +1,56 @@
+/* Tests in the "miscellaneous" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_MISC_TESTS_H
+# define XML_MISC_TESTS_H
+
+extern void make_miscellaneous_test_case(Suite *s);
+
+#endif /* XML_MISC_TESTS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/misc_tests_cxx.cpp b/contrib/expat/tests/misc_tests_cxx.cpp
new file mode 100644
index 000000000000..0b84c1b1f4d6
--- /dev/null
+++ b/contrib/expat/tests/misc_tests_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "misc_tests.c"
diff --git a/contrib/expat/tests/ns_tests.c b/contrib/expat/tests/ns_tests.c
new file mode 100644
index 000000000000..411e1d3c974a
--- /dev/null
+++ b/contrib/expat/tests/ns_tests.c
@@ -0,0 +1,754 @@
+/* Tests in the "namespace" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "expat_config.h"
+
+#include <string.h>
+
+#include "expat.h"
+#include "internal.h"
+#include "minicheck.h"
+#include "common.h"
+#include "dummy.h"
+#include "handlers.h"
+#include "ns_tests.h"
+
+static void
+namespace_setup(void) {
+ g_parser = XML_ParserCreateNS(NULL, XCS(' '));
+ if (g_parser == NULL)
+ fail("Parser not created.");
+}
+
+static void
+namespace_teardown(void) {
+ basic_teardown();
+}
+
+START_TEST(test_return_ns_triplet) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>";
+ const char *epilog = "</foo:e>";
+ const XML_Char *elemstr[]
+ = {XCS("http://example.org/ e foo"), XCS("http://example.org/ a bar")};
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ XML_SetNamespaceDeclHandler(g_parser, dummy_start_namespace_decl_handler,
+ dummy_end_namespace_decl_handler);
+ g_triplet_start_flag = XML_FALSE;
+ g_triplet_end_flag = XML_FALSE;
+ init_dummy_handlers();
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Check that unsetting "return triplets" fails while still parsing */
+ XML_SetReturnNSTriplet(g_parser, XML_FALSE);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (! g_triplet_start_flag)
+ fail("triplet_start_checker not invoked");
+ if (! g_triplet_end_flag)
+ fail("triplet_end_checker not invoked");
+ if (get_dummy_handler_flags()
+ != (DUMMY_START_NS_DECL_HANDLER_FLAG | DUMMY_END_NS_DECL_HANDLER_FLAG))
+ fail("Namespace handlers not called");
+}
+END_TEST
+
+/* Test that the parsing status is correctly reset by XML_ParserReset().
+ * We use test_return_ns_triplet() for our example parse to improve
+ * coverage of tidying up code executed.
+ */
+START_TEST(test_ns_parser_reset) {
+ XML_ParsingStatus status;
+
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_INITIALIZED)
+ fail("parsing status doesn't start INITIALIZED");
+ test_return_ns_triplet();
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_FINISHED)
+ fail("parsing status doesn't end FINISHED");
+ XML_ParserReset(g_parser, NULL);
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_INITIALIZED)
+ fail("parsing status doesn't reset to INITIALIZED");
+}
+END_TEST
+
+static void
+run_ns_tagname_overwrite_test(const char *text, const XML_Char *result) {
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetElementHandler(g_parser, overwrite_start_checker,
+ overwrite_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, result);
+}
+
+/* Regression test for SF bug #566334. */
+START_TEST(test_ns_tagname_overwrite) {
+ const char *text = "<n:e xmlns:n='http://example.org/'>\n"
+ " <n:f n:attr='foo'/>\n"
+ " <n:g n:attr2='bar'/>\n"
+ "</n:e>";
+ const XML_Char *result = XCS("start http://example.org/ e\n")
+ XCS("start http://example.org/ f\n")
+ XCS("attribute http://example.org/ attr\n")
+ XCS("end http://example.org/ f\n")
+ XCS("start http://example.org/ g\n")
+ XCS("attribute http://example.org/ attr2\n")
+ XCS("end http://example.org/ g\n")
+ XCS("end http://example.org/ e\n");
+ run_ns_tagname_overwrite_test(text, result);
+}
+END_TEST
+
+/* Regression test for SF bug #566334. */
+START_TEST(test_ns_tagname_overwrite_triplet) {
+ const char *text = "<n:e xmlns:n='http://example.org/'>\n"
+ " <n:f n:attr='foo'/>\n"
+ " <n:g n:attr2='bar'/>\n"
+ "</n:e>";
+ const XML_Char *result = XCS("start http://example.org/ e n\n")
+ XCS("start http://example.org/ f n\n")
+ XCS("attribute http://example.org/ attr n\n")
+ XCS("end http://example.org/ f n\n")
+ XCS("start http://example.org/ g n\n")
+ XCS("attribute http://example.org/ attr2 n\n")
+ XCS("end http://example.org/ g n\n")
+ XCS("end http://example.org/ e n\n");
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ run_ns_tagname_overwrite_test(text, result);
+}
+END_TEST
+
+/* Regression test for SF bug #620343. */
+START_TEST(test_start_ns_clears_start_element) {
+ /* This needs to use separate start/end tags; using the empty tag
+ syntax doesn't cause the problematic path through Expat to be
+ taken.
+ */
+ const char *text = "<e xmlns='http://example.org/'></e>";
+
+ XML_SetStartElementHandler(g_parser, start_element_fail);
+ XML_SetStartNamespaceDeclHandler(g_parser, start_ns_clearing_start_element);
+ XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
+ XML_UseParserAsHandlerArg(g_parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #616863. */
+START_TEST(test_default_ns_from_ext_subset_and_ext_ge) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/ns1'>\n"
+ "&en;\n"
+ "</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_handler);
+ /* We actually need to set this handler to tickle this bug. */
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetUserData(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test #1 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_1) {
+ const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
+ " <e xmlns:prefix=''/>\n"
+ "</doc>";
+
+ expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
+ "Did not report re-setting namespace"
+ " URI with prefix to ''.");
+}
+END_TEST
+
+/* Regression test #2 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_2) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<docelem xmlns:pre=''/>";
+
+ expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
+ "Did not report setting namespace URI with prefix to ''.");
+}
+END_TEST
+
+/* Regression test #3 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_3) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ELEMENT doc EMPTY>\n"
+ " <!ATTLIST doc\n"
+ " xmlns:prefix CDATA ''>\n"
+ "]>\n"
+ "<doc/>";
+
+ expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
+ "Didn't report attr default setting NS w/ prefix to ''.");
+}
+END_TEST
+
+/* Regression test #4 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_4) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ELEMENT prefix:doc EMPTY>\n"
+ " <!ATTLIST prefix:doc\n"
+ " xmlns:prefix CDATA 'http://example.org/'>\n"
+ "]>\n"
+ "<prefix:doc/>";
+ /* Packaged info expected by the end element handler;
+ the weird structuring lets us reuse the triplet_end_checker()
+ function also used for another test. */
+ const XML_Char *elemstr[] = {XCS("http://example.org/ doc prefix")};
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetEndElementHandler(g_parser, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test with non-xmlns prefix */
+START_TEST(test_ns_unbound_prefix) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ELEMENT prefix:doc EMPTY>\n"
+ " <!ATTLIST prefix:doc\n"
+ " notxmlns:prefix CDATA 'http://example.org/'>\n"
+ "]>\n"
+ "<prefix:doc/>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Unbound prefix incorrectly passed");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_UNBOUND_PREFIX)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_ns_default_with_empty_uri) {
+ const char *text = "<doc xmlns='http://example.org/'>\n"
+ " <e xmlns=''/>\n"
+ "</doc>";
+ /* Add some handlers to exercise extra code paths */
+ XML_SetStartNamespaceDeclHandler(g_parser,
+ dummy_start_namespace_decl_handler);
+ XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #692964: two prefixes for one namespace. */
+START_TEST(test_ns_duplicate_attrs_diff_prefixes) {
+ const char *text = "<doc xmlns:a='http://example.org/a'\n"
+ " xmlns:b='http://example.org/a'\n"
+ " a:a='v' b:a='v' />";
+ expect_failure(text, XML_ERROR_DUPLICATE_ATTRIBUTE,
+ "did not report multiple attributes with same URI+name");
+}
+END_TEST
+
+START_TEST(test_ns_duplicate_hashes) {
+ /* The hash of an attribute is calculated as the hash of its URI
+ * concatenated with a space followed by its name (after the
+ * colon). We wish to generate attributes with the same hash
+ * value modulo the attribute table size so that we can check that
+ * the attribute hash table works correctly. The attribute hash
+ * table size will be the smallest power of two greater than the
+ * number of attributes, but at least eight. There is
+ * unfortunately no programmatic way of getting the hash or the
+ * table size at user level, but the test code coverage percentage
+ * will drop if the hashes cease to point to the same row.
+ *
+ * The cunning plan is to have few enough attributes to have a
+ * reliable table size of 8, and have the single letter attribute
+ * names be 8 characters apart, producing a hash which will be the
+ * same modulo 8.
+ */
+ const char *text = "<doc xmlns:a='http://example.org/a'\n"
+ " a:a='v' a:i='w' />";
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #695401: unbound prefix. */
+START_TEST(test_ns_unbound_prefix_on_attribute) {
+ const char *text = "<doc a:attr=''/>";
+ expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
+ "did not report unbound prefix on attribute");
+}
+END_TEST
+
+/* Regression test for SF bug #695401: unbound prefix. */
+START_TEST(test_ns_unbound_prefix_on_element) {
+ const char *text = "<a:doc/>";
+ expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
+ "did not report unbound prefix on element");
+}
+END_TEST
+
+/* Test that long element names with namespaces are handled correctly */
+START_TEST(test_ns_long_element) {
+ const char *text
+ = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
+ " xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</foo:thisisalongenoughelementnametotriggerareallocation>";
+ const XML_Char *elemstr[]
+ = {XCS("http://example.org/")
+ XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
+ XCS("http://example.org/ a bar")};
+
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test mixed population of prefixed and unprefixed attributes */
+START_TEST(test_ns_mixed_prefix_atts) {
+ const char *text = "<e a='12' bar:b='13'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</e>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test having a long namespaced element name inside a short one.
+ * This exercises some internal buffer reallocation that is shared
+ * across elements with the same namespace URI.
+ */
+START_TEST(test_ns_extend_uri_buffer) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/'>"
+ " <foo:thisisalongenoughnametotriggerallocationaction"
+ " foo:a='12' />"
+ "</foo:e>";
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that xmlns is correctly rejected as an attribute in the xmlns
+ * namespace, but not in other namespaces
+ */
+START_TEST(test_ns_reserved_attributes) {
+ const char *text1
+ = "<foo:e xmlns:foo='http://example.org/' xmlns:xmlns='12' />";
+ const char *text2
+ = "<foo:e xmlns:foo='http://example.org/' foo:xmlns='12' />";
+ expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XMLNS,
+ "xmlns not rejected as an attribute");
+ XML_ParserReset(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test more reserved attributes */
+START_TEST(test_ns_reserved_attributes_2) {
+ const char *text1 = "<foo:e xmlns:foo='http://example.org/'"
+ " xmlns:xml='http://example.org/' />";
+ const char *text2
+ = "<foo:e xmlns:foo='http://www.w3.org/XML/1998/namespace' />";
+ const char *text3 = "<foo:e xmlns:foo='http://www.w3.org/2000/xmlns/' />";
+
+ expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML,
+ "xml not rejected as an attribute");
+ XML_ParserReset(g_parser, NULL);
+ expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI,
+ "Use of w3.org URL not faulted");
+ XML_ParserReset(g_parser, NULL);
+ expect_failure(text3, XML_ERROR_RESERVED_NAMESPACE_URI,
+ "Use of w3.org xmlns URL not faulted");
+}
+END_TEST
+
+/* Test string pool handling of namespace names of 2048 characters */
+/* Exercises a particular string pool growth path */
+START_TEST(test_ns_extremely_long_prefix) {
+ /* C99 compilers are only required to support 4095-character
+ * strings, so the following needs to be split in two to be safe
+ * for all compilers.
+ */
+ const char *text1
+ = "<doc "
+ /* 64 character on each line */
+ /* ...gives a total length of 2048 */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":a='12'";
+ const char *text2
+ = " xmlns:"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "='foo'\n>"
+ "</doc>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test unknown encoding handlers in namespace setup */
+START_TEST(test_ns_unknown_encoding_success) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<foo:e xmlns:foo='http://example.org/'>Hi</foo:e>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ run_character_check(text, XCS("Hi"));
+}
+END_TEST
+
+/* Test that too many colons are rejected */
+START_TEST(test_ns_double_colon) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' foo:a:b='bar' />";
+ const enum XML_Status status
+ = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+#ifdef XML_NS
+ if ((status == XML_STATUS_OK)
+ || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
+ fail("Double colon in attribute name not faulted"
+ " (despite active namespace support)");
+ }
+#else
+ if (status != XML_STATUS_OK) {
+ fail("Double colon in attribute name faulted"
+ " (despite inactive namespace support");
+ }
+#endif
+}
+END_TEST
+
+START_TEST(test_ns_double_colon_element) {
+ const char *text = "<foo:bar:e xmlns:foo='http://example.org/' />";
+ const enum XML_Status status
+ = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+#ifdef XML_NS
+ if ((status == XML_STATUS_OK)
+ || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
+ fail("Double colon in element name not faulted"
+ " (despite active namespace support)");
+ }
+#else
+ if (status != XML_STATUS_OK) {
+ fail("Double colon in element name faulted"
+ " (despite inactive namespace support");
+ }
+#endif
+}
+END_TEST
+
+/* Test that non-name characters after a colon are rejected */
+START_TEST(test_ns_bad_attr_leafname) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' foo:?ar='baz' />";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character in leafname not faulted");
+}
+END_TEST
+
+START_TEST(test_ns_bad_element_leafname) {
+ const char *text = "<foo:?oc xmlns:foo='http://example.org/' />";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character in element leafname not faulted");
+}
+END_TEST
+
+/* Test high-byte-set UTF-16 characters are valid in a leafname */
+START_TEST(test_ns_utf16_leafname) {
+ const char text[] =
+ /* <n:e xmlns:n='URI' n:{KHO KHWAI}='a' />
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ */
+ "<\0n\0:\0e\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0 \0"
+ "n\0:\0\x04\x0e=\0'\0a\0'\0 \0/\0>\0";
+ const XML_Char *expected = XCS("a");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ns_utf16_element_leafname) {
+ const char text[] =
+ /* <n:{KHO KHWAI} xmlns:n='URI'/>
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ */
+ "\0<\0n\0:\x0e\x04\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0/\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("URI \x0e04");
+#else
+ const XML_Char *expected = XCS("URI \xe0\xb8\x84");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, start_element_event_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ns_utf16_doctype) {
+ const char text[] =
+ /* <!DOCTYPE foo:{KHO KHWAI} [ <!ENTITY bar 'baz'> ]>\n
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0f\0o\0o\0:\x0e\x04\0 "
+ "\0[\0 \0<\0!\0E\0N\0T\0I\0T\0Y\0 \0b\0a\0r\0 \0'\0b\0a\0z\0'\0>\0 "
+ "\0]\0>\0\n"
+ /* <foo:{KHO KHWAI} xmlns:foo='URI'>&bar;</foo:{KHO KHWAI}> */
+ "\0<\0f\0o\0o\0:\x0e\x04\0 "
+ "\0x\0m\0l\0n\0s\0:\0f\0o\0o\0=\0'\0U\0R\0I\0'\0>"
+ "\0&\0b\0a\0r\0;"
+ "\0<\0/\0f\0o\0o\0:\x0e\x04\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("URI \x0e04");
+#else
+ const XML_Char *expected = XCS("URI \xe0\xb8\x84");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, start_element_event_handler);
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ns_invalid_doctype) {
+ const char *text = "<!DOCTYPE foo:!bad [ <!ENTITY bar 'baz' ]>\n"
+ "<foo:!bad>&bar;</foo:!bad>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character in document local name not faulted");
+}
+END_TEST
+
+START_TEST(test_ns_double_colon_doctype) {
+ const char *text = "<!DOCTYPE foo:a:doc [ <!ENTITY bar 'baz' ]>\n"
+ "<foo:a:doc>&bar;</foo:a:doc>";
+
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Double colon in document name not faulted");
+}
+END_TEST
+
+START_TEST(test_ns_separator_in_uri) {
+ struct test_case {
+ enum XML_Status expectedStatus;
+ const char *doc;
+ XML_Char namesep;
+ };
+ struct test_case cases[] = {
+ {XML_STATUS_OK, "<doc xmlns='one_two' />", XCS('\n')},
+ {XML_STATUS_ERROR, "<doc xmlns='one&#x0A;two' />", XCS('\n')},
+ {XML_STATUS_OK, "<doc xmlns='one:two' />", XCS(':')},
+ };
+
+ size_t i = 0;
+ size_t failCount = 0;
+ for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ set_subtest("%s", cases[i].doc);
+ XML_Parser parser = XML_ParserCreateNS(NULL, cases[i].namesep);
+ XML_SetElementHandler(parser, dummy_start_element, dummy_end_element);
+ if (_XML_Parse_SINGLE_BYTES(parser, cases[i].doc, (int)strlen(cases[i].doc),
+ /*isFinal*/ XML_TRUE)
+ != cases[i].expectedStatus) {
+ failCount++;
+ }
+ XML_ParserFree(parser);
+ }
+
+ if (failCount) {
+ fail("Namespace separator handling is broken");
+ }
+}
+END_TEST
+
+void
+make_namespace_test_case(Suite *s) {
+ TCase *tc_namespace = tcase_create("XML namespaces");
+
+ suite_add_tcase(s, tc_namespace);
+ tcase_add_checked_fixture(tc_namespace, namespace_setup, namespace_teardown);
+ tcase_add_test(tc_namespace, test_return_ns_triplet);
+ tcase_add_test(tc_namespace, test_ns_parser_reset);
+ tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
+ tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
+ tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
+ tcase_add_test__ifdef_xml_dtd(tc_namespace,
+ test_default_ns_from_ext_subset_and_ext_ge);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
+ tcase_add_test(tc_namespace, test_ns_unbound_prefix);
+ tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
+ tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
+ tcase_add_test(tc_namespace, test_ns_duplicate_hashes);
+ tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
+ tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
+ tcase_add_test(tc_namespace, test_ns_long_element);
+ tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts);
+ tcase_add_test(tc_namespace, test_ns_extend_uri_buffer);
+ tcase_add_test(tc_namespace, test_ns_reserved_attributes);
+ tcase_add_test(tc_namespace, test_ns_reserved_attributes_2);
+ tcase_add_test(tc_namespace, test_ns_extremely_long_prefix);
+ tcase_add_test(tc_namespace, test_ns_unknown_encoding_success);
+ tcase_add_test(tc_namespace, test_ns_double_colon);
+ tcase_add_test(tc_namespace, test_ns_double_colon_element);
+ tcase_add_test(tc_namespace, test_ns_bad_attr_leafname);
+ tcase_add_test(tc_namespace, test_ns_bad_element_leafname);
+ tcase_add_test(tc_namespace, test_ns_utf16_leafname);
+ tcase_add_test(tc_namespace, test_ns_utf16_element_leafname);
+ tcase_add_test__if_xml_ge(tc_namespace, test_ns_utf16_doctype);
+ tcase_add_test(tc_namespace, test_ns_invalid_doctype);
+ tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
+ tcase_add_test(tc_namespace, test_ns_separator_in_uri);
+}
diff --git a/contrib/expat/tests/ns_tests.h b/contrib/expat/tests/ns_tests.h
new file mode 100644
index 000000000000..acb0db786a40
--- /dev/null
+++ b/contrib/expat/tests/ns_tests.h
@@ -0,0 +1,56 @@
+/* Tests in the "namespace" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_NS_TESTS_H
+# define XML_NS_TESTS_H
+
+extern void make_namespace_test_case(Suite *s);
+
+#endif /* XML_NS_TESTS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/ns_tests_cxx.cpp b/contrib/expat/tests/ns_tests_cxx.cpp
new file mode 100644
index 000000000000..b2fe187bb8b4
--- /dev/null
+++ b/contrib/expat/tests/ns_tests_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "ns_tests.c"
diff --git a/contrib/expat/tests/nsalloc_tests.c b/contrib/expat/tests/nsalloc_tests.c
new file mode 100644
index 000000000000..ec88586af1d4
--- /dev/null
+++ b/contrib/expat/tests/nsalloc_tests.c
@@ -0,0 +1,1537 @@
+/* Tests in the "namespace allocation" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
+#endif
+
+#include <string.h>
+#include <assert.h>
+
+#include "expat.h"
+#include "common.h"
+#include "minicheck.h"
+#include "dummy.h"
+#include "handlers.h"
+#include "nsalloc_tests.h"
+
+static void
+nsalloc_setup(void) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
+ XML_Char ns_sep[2] = {' ', '\0'};
+
+ /* Ensure the parser creation will go through */
+ g_allocation_count = ALLOC_ALWAYS_SUCCEED;
+ g_reallocation_count = REALLOC_ALWAYS_SUCCEED;
+ g_parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep);
+ if (g_parser == NULL)
+ fail("Parser not created");
+}
+
+static void
+nsalloc_teardown(void) {
+ basic_teardown();
+}
+
+/* Test the effects of allocation failure in simple namespace parsing.
+ * Based on test_ns_default_with_empty_uri()
+ */
+START_TEST(test_nsalloc_xmlns) {
+ const char *text = "<doc xmlns='http://example.org/'>\n"
+ " <e xmlns=''/>\n"
+ "</doc>";
+ unsigned int i;
+ const unsigned int max_alloc_count = 30;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ /* Exercise more code paths with a default handler */
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* Resetting the parser is insufficient, because some memory
+ * allocations are cached within the parser. Instead we use
+ * the teardown and setup routines to ensure that we have the
+ * right sort of parser back in our hands.
+ */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at maximum allocation count");
+}
+END_TEST
+
+/* Test XML_ParseBuffer interface with namespace and a dicky allocator */
+START_TEST(test_nsalloc_parse_buffer) {
+ const char *text = "<doc>Hello</doc>";
+ void *buffer;
+
+ /* Try a parse before the start of the world */
+ /* (Exercises new code path) */
+ if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR)
+ fail("Pre-init XML_ParseBuffer not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_BUFFER)
+ fail("Pre-init XML_ParseBuffer faulted for wrong reason");
+
+ buffer = XML_GetBuffer(g_parser, 1 /* any small number greater than 0 */);
+ if (buffer == NULL)
+ fail("Could not acquire parse buffer");
+
+ g_allocation_count = 0;
+ if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR)
+ fail("Pre-init XML_ParseBuffer not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_MEMORY)
+ fail("Pre-init XML_ParseBuffer faulted for wrong reason");
+
+ /* Now with actual memory allocation */
+ g_allocation_count = ALLOC_ALWAYS_SUCCEED;
+ if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_OK)
+ xml_failure(g_parser);
+
+ /* Check that resuming an unsuspended parser is faulted */
+ if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
+ fail("Resuming unsuspended parser not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NOT_SUSPENDED)
+ xml_failure(g_parser);
+
+ /* Get the parser into suspended state */
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ g_resumable = XML_TRUE;
+ buffer = XML_GetBuffer(g_parser, (int)strlen(text));
+ if (buffer == NULL)
+ fail("Could not acquire parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Suspended XML_ParseBuffer not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
+ fail("Suspended XML_GetBuffer not faulted");
+
+ /* Get it going again and complete the world */
+ XML_SetCharacterDataHandler(g_parser, NULL);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Post-finishing XML_ParseBuffer not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
+ xml_failure(g_parser);
+ if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
+ fail("Post-finishing XML_GetBuffer not faulted");
+}
+END_TEST
+
+/* Check handling of long prefix names (pool growth) */
+START_TEST(test_nsalloc_long_prefix) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Check handling of long uri names (pool growth) */
+START_TEST(test_nsalloc_long_uri) {
+ const char *text
+ = "<foo:e xmlns:foo='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "' bar:a='12'\n"
+ "xmlns:bar='http://example.org/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "'>"
+ "</foo:e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Test handling of long attribute names with prefixes */
+START_TEST(test_nsalloc_long_attr) {
+ const char *text
+ = "<foo:e xmlns:foo='http://example.org/' bar:"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='12'\n"
+ "xmlns:bar='http://example.org/'>"
+ "</foo:e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Test handling of an attribute name with a long namespace prefix */
+START_TEST(test_nsalloc_long_attr_prefix) {
+ const char *text
+ = "<foo:e xmlns:foo='http://example.org/' "
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":a='12'\n"
+ "xmlns:"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>"
+ "</foo:e>";
+ const XML_Char *elemstr[] = {
+ /* clang-format off */
+ XCS("http://example.org/ e foo"),
+ XCS("http://example.org/ a ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ /* clang-format on */
+ };
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Test attribute handling in the face of a dodgy reallocator */
+START_TEST(test_nsalloc_realloc_attributes) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</foo:e>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+/* Test long element names with namespaces under a failing allocator */
+START_TEST(test_nsalloc_long_element) {
+ const char *text
+ = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
+ " xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</foo:thisisalongenoughelementnametotriggerareallocation>";
+ const XML_Char *elemstr[]
+ = {XCS("http://example.org/")
+ XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
+ XCS("http://example.org/ a bar")};
+ int i;
+ const int max_alloc_count = 30;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+/* Test the effects of reallocation failure when reassigning a
+ * binding.
+ *
+ * XML_ParserReset does not free the BINDING structures used by a
+ * parser, but instead adds them to an internal free list to be reused
+ * as necessary. Likewise the URI buffers allocated for the binding
+ * aren't freed, but kept attached to their existing binding. If the
+ * new binding has a longer URI, it will need reallocation. This test
+ * provokes that reallocation, and tests the control path if it fails.
+ */
+START_TEST(test_nsalloc_realloc_binding_uri) {
+ const char *first = "<doc xmlns='http://example.org/'>\n"
+ " <e xmlns='' />\n"
+ "</doc>";
+ const char *second
+ = "<doc xmlns='http://example.org/long/enough/URI/to/reallocate/'>\n"
+ " <e xmlns='' />\n"
+ "</doc>";
+ unsigned i;
+ const unsigned max_realloc_count = 10;
+
+ /* First, do a full parse that will leave bindings around */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, first, (int)strlen(first), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Now repeat with a longer URI and a duff reallocator */
+ for (i = 0; i < max_realloc_count; i++) {
+ XML_ParserReset(g_parser, NULL);
+ g_reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, second, (int)strlen(second), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocation");
+ else if (i == max_realloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+/* Check handling of long prefix names (pool growth) */
+START_TEST(test_nsalloc_realloc_long_prefix) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo>";
+ int i;
+ const int max_realloc_count = 12;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+/* Check handling of even long prefix names (different code path) */
+START_TEST(test_nsalloc_realloc_longer_prefix) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "Q:foo xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "Q='http://example.org/'>"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "Q:foo>";
+ int i;
+ const int max_realloc_count = 12;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_namespace) {
+ const char *text1
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":e xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>\n";
+ const char *text2
+ = "<"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":f "
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":attr='foo'/>\n"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ != XML_STATUS_ERROR
+ && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
+ XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Using a slightly shorter namespace name provokes allocations in
+ * slightly different places in the code.
+ */
+START_TEST(test_nsalloc_less_long_namespace) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":e xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ "='http://example.org/'>\n"
+ "<"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":f "
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":att='foo'/>\n"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_context) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ATTLIST doc baz ID #REQUIRED>\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
+ "' baz='2'>\n"
+ "&en;"
+ "</doc>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 70;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* This function is void; it will throw a fail() on error, so if it
+ * returns normally it must have succeeded.
+ */
+static void
+context_realloc_test(const char *text) {
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_realloc_count = 6;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+
+START_TEST(test_nsalloc_realloc_long_context) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
+}
+END_TEST
+
+START_TEST(test_nsalloc_realloc_long_context_2) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJK"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
+}
+END_TEST
+
+START_TEST(test_nsalloc_realloc_long_context_3) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGH"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
+}
+END_TEST
+
+START_TEST(test_nsalloc_realloc_long_context_4) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
+}
+END_TEST
+
+START_TEST(test_nsalloc_realloc_long_context_5) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABC"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
+}
+END_TEST
+
+START_TEST(test_nsalloc_realloc_long_context_6) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
+}
+END_TEST
+
+START_TEST(test_nsalloc_realloc_long_context_7) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLM"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
+}
+END_TEST
+
+START_TEST(test_nsalloc_realloc_long_ge_name) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY "
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/baz'>\n"
+ "&"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ";"
+ "</doc>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT el EMPTY>"}, {XCS("bar"), "<el/>"}, {NULL, NULL}};
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+/* Test that when a namespace is passed through the context mechanism
+ * to an external entity parser, the parsers handle reallocation
+ * failures correctly. The prefix is exactly the right length to
+ * provoke particular uncommon code paths.
+ */
+START_TEST(test_nsalloc_realloc_long_context_in_dtd) {
+ const char *text1
+ = "<!DOCTYPE "
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":doc [\n"
+ " <!ENTITY First SYSTEM 'foo/First'>\n"
+ "]>\n"
+ "<"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":doc xmlns:"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "='foo/Second'>&First;";
+ const char *text2
+ = "</"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":doc>";
+ ExtOption options[] = {{XCS("foo/First"), "Hello world"}, {NULL, NULL}};
+ int i;
+ const int max_realloc_count = 20;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ g_reallocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ != XML_STATUS_ERROR
+ && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
+ XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_default_in_ext) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST e a1 CDATA '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>\n"
+ " <!ENTITY x SYSTEM 'foo'>\n"
+ "]>\n"
+ "<doc>&x;</doc>";
+ ExtOption options[] = {{XCS("foo"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 50;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_systemid_in_ext) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"},
+ {/* clang-format off */
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"),
+ /* clang-format on */
+ "<e/>"},
+ {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 55;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Test the effects of allocation failure on parsing an element in a
+ * namespace. Based on test_nsalloc_long_context.
+ */
+START_TEST(test_nsalloc_prefixed_element) {
+ const char *text = "<!DOCTYPE pfx:element SYSTEM 'foo' [\n"
+ " <!ATTLIST pfx:element baz ID #REQUIRED>\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<pfx:element xmlns:pfx='http://example.org/' baz='2'>\n"
+ "&en;"
+ "</pfx:element>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 70;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Success despite failing allocator");
+ else if (i == max_alloc_count)
+ fail("Failed even at full allocation count");
+}
+END_TEST
+
+void
+make_nsalloc_test_case(Suite *s) {
+ TCase *tc_nsalloc = tcase_create("namespace allocation tests");
+
+ suite_add_tcase(s, tc_nsalloc);
+ tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown);
+
+ tcase_add_test(tc_nsalloc, test_nsalloc_xmlns);
+ tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_uri);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_attr);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_element);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_binding_uri);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_longer_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_namespace);
+ tcase_add_test(tc_nsalloc, test_nsalloc_less_long_namespace);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_context);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_2);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_3);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_4);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_5);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_6);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_7);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_ge_name);
+ tcase_add_test__if_xml_ge(tc_nsalloc,
+ test_nsalloc_realloc_long_context_in_dtd);
+ tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_long_default_in_ext);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
+ tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
+}
diff --git a/contrib/expat/tests/nsalloc_tests.h b/contrib/expat/tests/nsalloc_tests.h
new file mode 100644
index 000000000000..026a2a21a950
--- /dev/null
+++ b/contrib/expat/tests/nsalloc_tests.h
@@ -0,0 +1,56 @@
+/* Tests in the "namespace allocation" test case for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_NSALLOC_TESTS_H
+# define XML_NSALLOC_TESTS_H
+
+extern void make_nsalloc_test_case(Suite *s);
+
+#endif /* XML_NSALLOC_TESTS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/expat/tests/nsalloc_tests_cxx.cpp b/contrib/expat/tests/nsalloc_tests_cxx.cpp
new file mode 100644
index 000000000000..9ba75d1c5368
--- /dev/null
+++ b/contrib/expat/tests/nsalloc_tests_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "nsalloc_tests.c"
diff --git a/contrib/expat/tests/runtests.c b/contrib/expat/tests/runtests.c
index b7411e925900..ecb1c36be584 100644
--- a/contrib/expat/tests/runtests.c
+++ b/contrib/expat/tests/runtests.c
@@ -6,8 +6,20 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,11539 +42,38 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#if defined(NDEBUG)
-# undef NDEBUG /* because test suite relies on assert(...) at the moment */
-#endif
-
-#ifdef HAVE_EXPAT_CONFIG_H
-# include <expat_config.h>
-#endif
+#include "expat_config.h"
-#include <assert.h>
-#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <stddef.h> /* ptrdiff_t */
-#include <ctype.h>
-#include <limits.h>
-
-#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
-/* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
-# if defined(_WIN64)
-typedef __int64 intptr_t;
-# else
-typedef __int32 intptr_t;
-# endif
-typedef unsigned __int64 uint64_t;
-#else
-# include <stdint.h> /* intptr_t uint64_t */
-#endif
-
-#if ! defined(__cplusplus)
-# if defined(_MSC_VER) && (_MSC_VER <= 1700)
-/* for vs2012/11.0/1700 and earlier Visual Studio compilers */
-# define bool int
-# define false 0
-# define true 1
-# else
-# include <stdbool.h>
-# endif
-#endif
#include "expat.h"
-#include "chardata.h"
-#include "structdata.h"
-#include "internal.h" /* for UNUSED_P only */
+#include "internal.h"
#include "minicheck.h"
-#include "memcheck.h"
-#include "siphash.h"
-#include "ascii.h" /* for ASCII_xxx */
-
-#ifdef XML_LARGE_SIZE
-# define XML_FMT_INT_MOD "ll"
-#else
-# define XML_FMT_INT_MOD "l"
-#endif
-
-#ifdef XML_UNICODE_WCHAR_T
-# define XML_FMT_CHAR "lc"
-# define XML_FMT_STR "ls"
-# include <wchar.h>
-# define xcstrlen(s) wcslen(s)
-# define xcstrcmp(s, t) wcscmp((s), (t))
-# define xcstrncmp(s, t, n) wcsncmp((s), (t), (n))
-# define XCS(s) _XCS(s)
-# define _XCS(s) L##s
-#else
-# ifdef XML_UNICODE
-# error "No support for UTF-16 character without wchar_t in tests"
-# else
-# define XML_FMT_CHAR "c"
-# define XML_FMT_STR "s"
-# define xcstrlen(s) strlen(s)
-# define xcstrcmp(s, t) strcmp((s), (t))
-# define xcstrncmp(s, t, n) strncmp((s), (t), (n))
-# define XCS(s) s
-# endif /* XML_UNICODE */
-#endif /* XML_UNICODE_WCHAR_T */
-
-static XML_Parser g_parser = NULL;
-
-static void
-basic_setup(void) {
- g_parser = XML_ParserCreate(NULL);
- if (g_parser == NULL)
- fail("Parser not created.");
-}
-
-static void
-basic_teardown(void) {
- if (g_parser != NULL) {
- XML_ParserFree(g_parser);
- g_parser = NULL;
- }
-}
-
-/* Generate a failure using the parser state to create an error message;
- this should be used when the parser reports an error we weren't
- expecting.
-*/
-static void
-_xml_failure(XML_Parser parser, const char *file, int line) {
- char buffer[1024];
- enum XML_Error err = XML_GetErrorCode(parser);
- sprintf(buffer,
- " %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
- "u, offset %" XML_FMT_INT_MOD "u)\n reported from %s, line %d\n",
- err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser), file, line);
- _fail_unless(0, file, line, buffer);
-}
-
-static enum XML_Status
-_XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
- int isFinal) {
- enum XML_Status res = XML_STATUS_ERROR;
- int offset = 0;
-
- if (len == 0) {
- return XML_Parse(parser, s, len, isFinal);
- }
-
- for (; offset < len; offset++) {
- const int innerIsFinal = (offset == len - 1) && isFinal;
- const char c = s[offset]; /* to help out-of-bounds detection */
- res = XML_Parse(parser, &c, sizeof(char), innerIsFinal);
- if (res != XML_STATUS_OK) {
- return res;
- }
- }
- return res;
-}
-
-#define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
-
-static void
-_expect_failure(const char *text, enum XML_Error errorCode,
- const char *errorMessage, const char *file, int lineno) {
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- /* Hackish use of _fail_unless() macro, but let's us report
- the right filename and line number. */
- _fail_unless(0, file, lineno, errorMessage);
- if (XML_GetErrorCode(g_parser) != errorCode)
- _xml_failure(g_parser, file, lineno);
-}
-
-#define expect_failure(text, errorCode, errorMessage) \
- _expect_failure((text), (errorCode), (errorMessage), __FILE__, __LINE__)
-
-/* Dummy handlers for when we need to set a handler to tickle a bug,
- but it doesn't need to do anything.
-*/
-static unsigned long dummy_handler_flags = 0;
-
-#define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
-#define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
-#define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
-#define DUMMY_NOTATION_DECL_HANDLER_FLAG (1UL << 3)
-#define DUMMY_ELEMENT_DECL_HANDLER_FLAG (1UL << 4)
-#define DUMMY_ATTLIST_DECL_HANDLER_FLAG (1UL << 5)
-#define DUMMY_COMMENT_HANDLER_FLAG (1UL << 6)
-#define DUMMY_PI_HANDLER_FLAG (1UL << 7)
-#define DUMMY_START_ELEMENT_HANDLER_FLAG (1UL << 8)
-#define DUMMY_START_CDATA_HANDLER_FLAG (1UL << 9)
-#define DUMMY_END_CDATA_HANDLER_FLAG (1UL << 10)
-#define DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG (1UL << 11)
-#define DUMMY_START_NS_DECL_HANDLER_FLAG (1UL << 12)
-#define DUMMY_END_NS_DECL_HANDLER_FLAG (1UL << 13)
-#define DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG (1UL << 14)
-#define DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG (1UL << 15)
-#define DUMMY_SKIP_HANDLER_FLAG (1UL << 16)
-#define DUMMY_DEFAULT_HANDLER_FLAG (1UL << 17)
-
-static void XMLCALL
-dummy_xdecl_handler(void *userData, const XML_Char *version,
- const XML_Char *encoding, int standalone) {
- UNUSED_P(userData);
- UNUSED_P(version);
- UNUSED_P(encoding);
- UNUSED_P(standalone);
-}
-
-static void XMLCALL
-dummy_start_doctype_handler(void *userData, const XML_Char *doctypeName,
- const XML_Char *sysid, const XML_Char *pubid,
- int has_internal_subset) {
- UNUSED_P(userData);
- UNUSED_P(doctypeName);
- UNUSED_P(sysid);
- UNUSED_P(pubid);
- UNUSED_P(has_internal_subset);
- dummy_handler_flags |= DUMMY_START_DOCTYPE_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_end_doctype_handler(void *userData) {
- UNUSED_P(userData);
- dummy_handler_flags |= DUMMY_END_DOCTYPE_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_entity_decl_handler(void *userData, const XML_Char *entityName,
- int is_parameter_entity, const XML_Char *value,
- int value_length, const XML_Char *base,
- const XML_Char *systemId, const XML_Char *publicId,
- const XML_Char *notationName) {
- UNUSED_P(userData);
- UNUSED_P(entityName);
- UNUSED_P(is_parameter_entity);
- UNUSED_P(value);
- UNUSED_P(value_length);
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- UNUSED_P(notationName);
- dummy_handler_flags |= DUMMY_ENTITY_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_notation_decl_handler(void *userData, const XML_Char *notationName,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- UNUSED_P(userData);
- UNUSED_P(notationName);
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- dummy_handler_flags |= DUMMY_NOTATION_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_element_decl_handler(void *userData, const XML_Char *name,
- XML_Content *model) {
- UNUSED_P(userData);
- UNUSED_P(name);
- /* The content model must be freed by the handler. Unfortunately
- * we cannot pass the parser as the userData because this is used
- * with other handlers that require other userData.
- */
- XML_FreeContentModel(g_parser, model);
- dummy_handler_flags |= DUMMY_ELEMENT_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_attlist_decl_handler(void *userData, const XML_Char *elname,
- const XML_Char *attname, const XML_Char *att_type,
- const XML_Char *dflt, int isrequired) {
- UNUSED_P(userData);
- UNUSED_P(elname);
- UNUSED_P(attname);
- UNUSED_P(att_type);
- UNUSED_P(dflt);
- UNUSED_P(isrequired);
- dummy_handler_flags |= DUMMY_ATTLIST_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_comment_handler(void *userData, const XML_Char *data) {
- UNUSED_P(userData);
- UNUSED_P(data);
- dummy_handler_flags |= DUMMY_COMMENT_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data) {
- UNUSED_P(userData);
- UNUSED_P(target);
- UNUSED_P(data);
- dummy_handler_flags |= DUMMY_PI_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_start_element(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- UNUSED_P(userData);
- UNUSED_P(name);
- UNUSED_P(atts);
- dummy_handler_flags |= DUMMY_START_ELEMENT_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_end_element(void *userData, const XML_Char *name) {
- UNUSED_P(userData);
- UNUSED_P(name);
-}
-
-static void XMLCALL
-dummy_start_cdata_handler(void *userData) {
- UNUSED_P(userData);
- dummy_handler_flags |= DUMMY_START_CDATA_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_end_cdata_handler(void *userData) {
- UNUSED_P(userData);
- dummy_handler_flags |= DUMMY_END_CDATA_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_cdata_handler(void *userData, const XML_Char *s, int len) {
- UNUSED_P(userData);
- UNUSED_P(s);
- UNUSED_P(len);
-}
-
-static void XMLCALL
-dummy_start_namespace_decl_handler(void *userData, const XML_Char *prefix,
- const XML_Char *uri) {
- UNUSED_P(userData);
- UNUSED_P(prefix);
- UNUSED_P(uri);
- dummy_handler_flags |= DUMMY_START_NS_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_end_namespace_decl_handler(void *userData, const XML_Char *prefix) {
- UNUSED_P(userData);
- UNUSED_P(prefix);
- dummy_handler_flags |= DUMMY_END_NS_DECL_HANDLER_FLAG;
-}
-
-/* This handler is obsolete, but while the code exists we should
- * ensure that dealing with the handler is covered by tests.
- */
-static void XMLCALL
-dummy_unparsed_entity_decl_handler(void *userData, const XML_Char *entityName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName) {
- UNUSED_P(userData);
- UNUSED_P(entityName);
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- UNUSED_P(notationName);
- dummy_handler_flags |= DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_default_handler(void *userData, const XML_Char *s, int len) {
- UNUSED_P(userData);
- UNUSED_P(s);
- UNUSED_P(len);
-}
-
-static void XMLCALL
-dummy_start_doctype_decl_handler(void *userData, const XML_Char *doctypeName,
- const XML_Char *sysid, const XML_Char *pubid,
- int has_internal_subset) {
- UNUSED_P(userData);
- UNUSED_P(doctypeName);
- UNUSED_P(sysid);
- UNUSED_P(pubid);
- UNUSED_P(has_internal_subset);
- dummy_handler_flags |= DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_end_doctype_decl_handler(void *userData) {
- UNUSED_P(userData);
- dummy_handler_flags |= DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG;
-}
-
-static void XMLCALL
-dummy_skip_handler(void *userData, const XML_Char *entityName,
- int is_parameter_entity) {
- UNUSED_P(userData);
- UNUSED_P(entityName);
- UNUSED_P(is_parameter_entity);
- dummy_handler_flags |= DUMMY_SKIP_HANDLER_FLAG;
-}
-
-/* Useful external entity handler */
-typedef struct ExtOption {
- const XML_Char *system_id;
- const char *parse_text;
-} ExtOption;
-
-static int XMLCALL
-external_entity_optioner(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- ExtOption *options = (ExtOption *)XML_GetUserData(parser);
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(publicId);
- while (options->parse_text != NULL) {
- if (! xcstrcmp(systemId, options->system_id)) {
- enum XML_Status rc;
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- return XML_STATUS_ERROR;
- rc = _XML_Parse_SINGLE_BYTES(ext_parser, options->parse_text,
- (int)strlen(options->parse_text), XML_TRUE);
- XML_ParserFree(ext_parser);
- return rc;
- }
- options++;
- }
- fail("No suitable option found");
- return XML_STATUS_ERROR;
-}
-
-/*
- * Parameter entity evaluation support.
- */
-#define ENTITY_MATCH_FAIL (-1)
-#define ENTITY_MATCH_NOT_FOUND (0)
-#define ENTITY_MATCH_SUCCESS (1)
-static const XML_Char *entity_name_to_match = NULL;
-static const XML_Char *entity_value_to_match = NULL;
-static int entity_match_flag = ENTITY_MATCH_NOT_FOUND;
-
-static void XMLCALL
-param_entity_match_handler(void *userData, const XML_Char *entityName,
- int is_parameter_entity, const XML_Char *value,
- int value_length, const XML_Char *base,
- const XML_Char *systemId, const XML_Char *publicId,
- const XML_Char *notationName) {
- UNUSED_P(userData);
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- UNUSED_P(notationName);
- if (! is_parameter_entity || entity_name_to_match == NULL
- || entity_value_to_match == NULL) {
- return;
- }
- if (! xcstrcmp(entityName, entity_name_to_match)) {
- /* The cast here is safe because we control the horizontal and
- * the vertical, and we therefore know our strings are never
- * going to overflow an int.
- */
- if (value_length != (int)xcstrlen(entity_value_to_match)
- || xcstrncmp(value, entity_value_to_match, value_length)) {
- entity_match_flag = ENTITY_MATCH_FAIL;
- } else {
- entity_match_flag = ENTITY_MATCH_SUCCESS;
- }
- }
- /* Else leave the match flag alone */
-}
-
-/*
- * Character & encoding tests.
- */
-
-START_TEST(test_nul_byte) {
- char text[] = "<doc>\0</doc>";
-
- /* test that a NUL byte (in US-ASCII data) is an error */
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_OK)
- fail("Parser did not report error on NUL-byte.");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_u0000_char) {
- /* test that a NUL byte (in US-ASCII data) is an error */
- expect_failure("<doc>&#0;</doc>", XML_ERROR_BAD_CHAR_REF,
- "Parser did not report error on NUL-byte.");
-}
-END_TEST
-
-START_TEST(test_siphash_self) {
- if (! sip24_valid())
- fail("SipHash self-test failed");
-}
-END_TEST
-
-START_TEST(test_siphash_spec) {
- /* https://131002.net/siphash/siphash.pdf (page 19, "Test values") */
- const char message[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
- "\x0a\x0b\x0c\x0d\x0e";
- const size_t len = sizeof(message) - 1;
- const uint64_t expected = _SIP_ULL(0xa129ca61U, 0x49be45e5U);
- struct siphash state;
- struct sipkey key;
-
- sip_tokey(&key, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
- "\x0a\x0b\x0c\x0d\x0e\x0f");
- sip24_init(&state, &key);
-
- /* Cover spread across calls */
- sip24_update(&state, message, 4);
- sip24_update(&state, message + 4, len - 4);
-
- /* Cover null length */
- sip24_update(&state, message, 0);
-
- if (sip24_final(&state) != expected)
- fail("sip24_final failed spec test\n");
-
- /* Cover wrapper */
- if (siphash24(message, len, &key) != expected)
- fail("siphash24 failed spec test\n");
-}
-END_TEST
-
-START_TEST(test_bom_utf8) {
- /* This test is really just making sure we don't core on a UTF-8 BOM. */
- const char *text = "\357\273\277<e/>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_bom_utf16_be) {
- char text[] = "\376\377\0<\0e\0/\0>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_bom_utf16_le) {
- char text[] = "\377\376<\0e\0/\0>\0";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Parse whole buffer at once to exercise a different code path */
-START_TEST(test_nobom_utf16_le) {
- char text[] = " \0<\0e\0/\0>\0";
-
- if (XML_Parse(g_parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-static void XMLCALL
-accumulate_characters(void *userData, const XML_Char *s, int len) {
- CharData_AppendXMLChars((CharData *)userData, s, len);
-}
-
-static void XMLCALL
-accumulate_attribute(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- CharData *storage = (CharData *)userData;
- UNUSED_P(name);
- /* Check there are attributes to deal with */
- if (atts == NULL)
- return;
-
- while (storage->count < 0 && atts[0] != NULL) {
- /* "accumulate" the value of the first attribute we see */
- CharData_AppendXMLChars(storage, atts[1], -1);
- atts += 2;
- }
-}
-
-static void
-_run_character_check(const char *text, const XML_Char *expected,
- const char *file, int line) {
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- _xml_failure(g_parser, file, line);
- CharData_CheckXMLChars(&storage, expected);
-}
-
-#define run_character_check(text, expected) \
- _run_character_check(text, expected, __FILE__, __LINE__)
-
-static void
-_run_attribute_check(const char *text, const XML_Char *expected,
- const char *file, int line) {
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetStartElementHandler(g_parser, accumulate_attribute);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- _xml_failure(g_parser, file, line);
- CharData_CheckXMLChars(&storage, expected);
-}
-
-#define run_attribute_check(text, expected) \
- _run_attribute_check(text, expected, __FILE__, __LINE__)
-
-typedef struct ExtTest {
- const char *parse_text;
- const XML_Char *encoding;
- CharData *storage;
-} ExtTest;
-
-static void XMLCALL
-ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
- ExtTest *test_data = (ExtTest *)userData;
- accumulate_characters(test_data->storage, s, len);
-}
-
-static void
-_run_ext_character_check(const char *text, ExtTest *test_data,
- const XML_Char *expected, const char *file, int line) {
- CharData *const storage = (CharData *)malloc(sizeof(CharData));
-
- CharData_Init(storage);
- test_data->storage = storage;
- XML_SetUserData(g_parser, test_data);
- XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- _xml_failure(g_parser, file, line);
- CharData_CheckXMLChars(storage, expected);
-
- free(storage);
-}
-
-#define run_ext_character_check(text, test_data, expected) \
- _run_ext_character_check(text, test_data, expected, __FILE__, __LINE__)
-
-/* Regression test for SF bug #491986. */
-START_TEST(test_danish_latin1) {
- const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
-#ifdef XML_UNICODE
- const XML_Char *expected
- = XCS("J\x00f8rgen \x00e6\x00f8\x00e5\x00c6\x00d8\x00c5");
-#else
- const XML_Char *expected
- = XCS("J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
-#endif
- run_character_check(text, expected);
-}
-END_TEST
-
-/* Regression test for SF bug #514281. */
-START_TEST(test_french_charref_hexidecimal) {
- const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
-#else
- const XML_Char *expected
- = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
-#endif
- run_character_check(text, expected);
-}
-END_TEST
-
-START_TEST(test_french_charref_decimal) {
- const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
-#else
- const XML_Char *expected
- = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
-#endif
- run_character_check(text, expected);
-}
-END_TEST
-
-START_TEST(test_french_latin1) {
- const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
-#else
- const XML_Char *expected
- = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
-#endif
- run_character_check(text, expected);
-}
-END_TEST
-
-START_TEST(test_french_utf8) {
- const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<doc>\xC3\xA9</doc>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e9");
-#else
- const XML_Char *expected = XCS("\xC3\xA9");
-#endif
- run_character_check(text, expected);
-}
-END_TEST
-
-/* Regression test for SF bug #600479.
- XXX There should be a test that exercises all legal XML Unicode
- characters as PCDATA and attribute value content, and XML Name
- characters as part of element and attribute names.
-*/
-START_TEST(test_utf8_false_rejection) {
- const char *text = "<doc>\xEF\xBA\xBF</doc>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\xfebf");
-#else
- const XML_Char *expected = XCS("\xEF\xBA\xBF");
-#endif
- run_character_check(text, expected);
-}
-END_TEST
-
-/* Regression test for SF bug #477667.
- This test assures that any 8-bit character followed by a 7-bit
- character will not be mistakenly interpreted as a valid UTF-8
- sequence.
-*/
-START_TEST(test_illegal_utf8) {
- char text[100];
- int i;
-
- for (i = 128; i <= 255; ++i) {
- sprintf(text, "<e>%ccd</e>", i);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK) {
- sprintf(text, "expected token error for '%c' (ordinal %d) in UTF-8 text",
- i, i);
- fail(text);
- } else if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
- xml_failure(g_parser);
- /* Reset the parser since we use the same parser repeatedly. */
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-/* Examples, not masks: */
-#define UTF8_LEAD_1 "\x7f" /* 0b01111111 */
-#define UTF8_LEAD_2 "\xdf" /* 0b11011111 */
-#define UTF8_LEAD_3 "\xef" /* 0b11101111 */
-#define UTF8_LEAD_4 "\xf7" /* 0b11110111 */
-#define UTF8_FOLLOW "\xbf" /* 0b10111111 */
-
-START_TEST(test_utf8_auto_align) {
- struct TestCase {
- ptrdiff_t expectedMovementInChars;
- const char *input;
- };
-
- struct TestCase cases[] = {
- {00, ""},
-
- {00, UTF8_LEAD_1},
-
- {-1, UTF8_LEAD_2},
- {00, UTF8_LEAD_2 UTF8_FOLLOW},
-
- {-1, UTF8_LEAD_3},
- {-2, UTF8_LEAD_3 UTF8_FOLLOW},
- {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW},
-
- {-1, UTF8_LEAD_4},
- {-2, UTF8_LEAD_4 UTF8_FOLLOW},
- {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW},
- {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW},
- };
-
- size_t i = 0;
- bool success = true;
- for (; i < sizeof(cases) / sizeof(*cases); i++) {
- const char *fromLim = cases[i].input + strlen(cases[i].input);
- const char *const fromLimInitially = fromLim;
- ptrdiff_t actualMovementInChars;
-
- _INTERNAL_trim_to_complete_utf8_characters(cases[i].input, &fromLim);
-
- actualMovementInChars = (fromLim - fromLimInitially);
- if (actualMovementInChars != cases[i].expectedMovementInChars) {
- size_t j = 0;
- success = false;
- printf("[-] UTF-8 case %2u: Expected movement by %2d chars"
- ", actually moved by %2d chars: \"",
- (unsigned)(i + 1), (int)cases[i].expectedMovementInChars,
- (int)actualMovementInChars);
- for (; j < strlen(cases[i].input); j++) {
- printf("\\x%02x", (unsigned char)cases[i].input[j]);
- }
- printf("\"\n");
- }
- }
-
- if (! success) {
- fail("UTF-8 auto-alignment is not bullet-proof\n");
- }
-}
-END_TEST
-
-START_TEST(test_utf16) {
- /* <?xml version="1.0" encoding="UTF-16"?>
- * <doc a='123'>some {A} text</doc>
- *
- * where {A} is U+FF21, FULLWIDTH LATIN CAPITAL LETTER A
- */
- char text[]
- = "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
- "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
- "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
- "\000'\000?\000>\000\n"
- "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'\000>"
- "\000s\000o\000m\000e\000 \xff\x21\000 \000t\000e\000x\000t\000"
- "<\000/\000d\000o\000c\000>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("some \xff21 text");
-#else
- const XML_Char *expected = XCS("some \357\274\241 text");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_utf16_le_epilog_newline) {
- unsigned int first_chunk_bytes = 17;
- char text[] = "\xFF\xFE" /* BOM */
- "<\000e\000/\000>\000" /* document element */
- "\r\000\n\000\r\000\n\000"; /* epilog */
-
- if (first_chunk_bytes >= sizeof(text) - 1)
- fail("bad value of first_chunk_bytes");
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, first_chunk_bytes, XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- else {
- enum XML_Status rc;
- rc = _XML_Parse_SINGLE_BYTES(g_parser, text + first_chunk_bytes,
- sizeof(text) - first_chunk_bytes - 1,
- XML_TRUE);
- if (rc == XML_STATUS_ERROR)
- xml_failure(g_parser);
- }
-}
-END_TEST
-
-/* Test that an outright lie in the encoding is faulted */
-START_TEST(test_not_utf16) {
- const char *text = "<?xml version='1.0' encoding='utf-16'?>"
- "<doc>Hi</doc>";
-
- /* Use a handler to provoke the appropriate code paths */
- XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
- expect_failure(text, XML_ERROR_INCORRECT_ENCODING,
- "UTF-16 declared in UTF-8 not faulted");
-}
-END_TEST
-
-/* Test that an unknown encoding is rejected */
-START_TEST(test_bad_encoding) {
- const char *text = "<doc>Hi</doc>";
-
- if (! XML_SetEncoding(g_parser, XCS("unknown-encoding")))
- fail("XML_SetEncoding failed");
- expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
- "Unknown encoding not faulted");
-}
-END_TEST
-
-/* Regression test for SF bug #481609, #774028. */
-START_TEST(test_latin1_umlauts) {
- const char *text
- = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<e a='\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; >'\n"
- " >\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; ></e>";
-#ifdef XML_UNICODE
- /* Expected results in UTF-16 */
- const XML_Char *expected = XCS("\x00e4 \x00f6 \x00fc ")
- XCS("\x00e4 \x00f6 \x00fc ") XCS("\x00e4 \x00f6 \x00fc >");
-#else
- /* Expected results in UTF-8 */
- const XML_Char *expected = XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ")
- XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC >");
-#endif
-
- run_character_check(text, expected);
- XML_ParserReset(g_parser, NULL);
- run_attribute_check(text, expected);
- /* Repeat with a default handler */
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandler(g_parser, dummy_default_handler);
- run_character_check(text, expected);
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandler(g_parser, dummy_default_handler);
- run_attribute_check(text, expected);
-}
-END_TEST
-
-/* Test that an element name with a 4-byte UTF-8 character is rejected */
-START_TEST(test_long_utf8_character) {
- const char *text
- = "<?xml version='1.0' encoding='utf-8'?>\n"
- /* 0xf0 0x90 0x80 0x80 = U+10000, the first Linear B character */
- "<do\xf0\x90\x80\x80/>";
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "4-byte UTF-8 character in element name not faulted");
-}
-END_TEST
-
-/* Test that a long latin-1 attribute (too long to convert in one go)
- * is correctly converted
- */
-START_TEST(test_long_latin1_attribute) {
- const char *text
- = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<doc att='"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- /* Last character splits across a buffer boundary */
- "\xe4'>\n</doc>";
-
- const XML_Char *expected =
- /* 64 characters per line */
- /* clang-format off */
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO")
- /* clang-format on */
-#ifdef XML_UNICODE
- XCS("\x00e4");
-#else
- XCS("\xc3\xa4");
-#endif
-
- run_attribute_check(text, expected);
-}
-END_TEST
-
-/* Test that a long ASCII attribute (too long to convert in one go)
- * is correctly converted
- */
-START_TEST(test_long_ascii_attribute) {
- const char *text
- = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<doc att='"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "01234'>\n</doc>";
- const XML_Char *expected =
- /* 64 characters per line */
- /* clang-format off */
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("01234");
- /* clang-format on */
-
- run_attribute_check(text, expected);
-}
-END_TEST
-
-/* Regression test #1 for SF bug #653180. */
-START_TEST(test_line_number_after_parse) {
- const char *text = "<tag>\n"
- "\n"
- "\n</tag>";
- XML_Size lineno;
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- lineno = XML_GetCurrentLineNumber(g_parser);
- if (lineno != 4) {
- char buffer[100];
- sprintf(buffer, "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
- fail(buffer);
- }
-}
-END_TEST
-
-/* Regression test #2 for SF bug #653180. */
-START_TEST(test_column_number_after_parse) {
- const char *text = "<tag></tag>";
- XML_Size colno;
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- colno = XML_GetCurrentColumnNumber(g_parser);
- if (colno != 11) {
- char buffer[100];
- sprintf(buffer, "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
- fail(buffer);
- }
-}
-END_TEST
-
-#define STRUCT_START_TAG 0
-#define STRUCT_END_TAG 1
-static void XMLCALL
-start_element_event_handler2(void *userData, const XML_Char *name,
- const XML_Char **attr) {
- StructData *storage = (StructData *)userData;
- UNUSED_P(attr);
- StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
- XML_GetCurrentLineNumber(g_parser), STRUCT_START_TAG);
-}
-
-static void XMLCALL
-end_element_event_handler2(void *userData, const XML_Char *name) {
- StructData *storage = (StructData *)userData;
- StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
- XML_GetCurrentLineNumber(g_parser), STRUCT_END_TAG);
-}
-
-/* Regression test #3 for SF bug #653180. */
-START_TEST(test_line_and_column_numbers_inside_handlers) {
- const char *text = "<a>\n" /* Unix end-of-line */
- " <b>\r\n" /* Windows end-of-line */
- " <c/>\r" /* Mac OS end-of-line */
- " </b>\n"
- " <d>\n"
- " <f/>\n"
- " </d>\n"
- "</a>";
- const StructDataEntry expected[]
- = {{XCS("a"), 0, 1, STRUCT_START_TAG}, {XCS("b"), 2, 2, STRUCT_START_TAG},
- {XCS("c"), 4, 3, STRUCT_START_TAG}, {XCS("c"), 8, 3, STRUCT_END_TAG},
- {XCS("b"), 2, 4, STRUCT_END_TAG}, {XCS("d"), 2, 5, STRUCT_START_TAG},
- {XCS("f"), 4, 6, STRUCT_START_TAG}, {XCS("f"), 8, 6, STRUCT_END_TAG},
- {XCS("d"), 2, 7, STRUCT_END_TAG}, {XCS("a"), 0, 8, STRUCT_END_TAG}};
- const int expected_count = sizeof(expected) / sizeof(StructDataEntry);
- StructData storage;
-
- StructData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetStartElementHandler(g_parser, start_element_event_handler2);
- XML_SetEndElementHandler(g_parser, end_element_event_handler2);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-
- StructData_CheckItems(&storage, expected, expected_count);
- StructData_Dispose(&storage);
-}
-END_TEST
-
-/* Regression test #4 for SF bug #653180. */
-START_TEST(test_line_number_after_error) {
- const char *text = "<a>\n"
- " <b>\n"
- " </a>"; /* missing </b> */
- XML_Size lineno;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- != XML_STATUS_ERROR)
- fail("Expected a parse error");
-
- lineno = XML_GetCurrentLineNumber(g_parser);
- if (lineno != 3) {
- char buffer[100];
- sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
- fail(buffer);
- }
-}
-END_TEST
-
-/* Regression test #5 for SF bug #653180. */
-START_TEST(test_column_number_after_error) {
- const char *text = "<a>\n"
- " <b>\n"
- " </a>"; /* missing </b> */
- XML_Size colno;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- != XML_STATUS_ERROR)
- fail("Expected a parse error");
-
- colno = XML_GetCurrentColumnNumber(g_parser);
- if (colno != 4) {
- char buffer[100];
- sprintf(buffer, "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
- fail(buffer);
- }
-}
-END_TEST
-
-/* Regression test for SF bug #478332. */
-START_TEST(test_really_long_lines) {
- /* This parses an input line longer than INIT_DATA_BUF_SIZE
- characters long (defined to be 1024 in xmlparse.c). We take a
- really cheesy approach to building the input buffer, because
- this avoids writing bugs in buffer-filling code.
- */
- const char *text
- = "<e>"
- /* 64 chars */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- /* until we have at least 1024 characters on the line: */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "</e>";
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test cdata processing across a buffer boundary */
-START_TEST(test_really_long_encoded_lines) {
- /* As above, except that we want to provoke an output buffer
- * overflow with a non-trivial encoding. For this we need to pass
- * the whole cdata in one go, not byte-by-byte.
- */
- void *buffer;
- const char *text
- = "<?xml version='1.0' encoding='iso-8859-1'?>"
- "<e>"
- /* 64 chars */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- /* until we have at least 1024 characters on the line: */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
- "</e>";
- int parse_len = (int)strlen(text);
-
- /* Need a cdata handler to provoke the code path we want to test */
- XML_SetCharacterDataHandler(g_parser, dummy_cdata_handler);
- buffer = XML_GetBuffer(g_parser, parse_len);
- if (buffer == NULL)
- fail("Could not allocate parse buffer");
- assert(buffer != NULL);
- memcpy(buffer, text, parse_len);
- if (XML_ParseBuffer(g_parser, parse_len, XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/*
- * Element event tests.
- */
-
-static void XMLCALL
-start_element_event_handler(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- UNUSED_P(atts);
- CharData_AppendXMLChars((CharData *)userData, name, -1);
-}
-
-static void XMLCALL
-end_element_event_handler(void *userData, const XML_Char *name) {
- CharData *storage = (CharData *)userData;
- CharData_AppendXMLChars(storage, XCS("/"), 1);
- CharData_AppendXMLChars(storage, name, -1);
-}
-
-START_TEST(test_end_element_events) {
- const char *text = "<a><b><c/></b><d><f/></d></a>";
- const XML_Char *expected = XCS("/c/b/f/d/a");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetEndElementHandler(g_parser, end_element_event_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/*
- * Attribute tests.
- */
-
-/* Helpers used by the following test; this checks any "attr" and "refs"
- attributes to make sure whitespace has been normalized.
-
- Return true if whitespace has been normalized in a string, using
- the rules for attribute value normalization. The 'is_cdata' flag
- is needed since CDATA attributes don't need to have multiple
- whitespace characters collapsed to a single space, while other
- attribute data types do. (Section 3.3.3 of the recommendation.)
-*/
-static int
-is_whitespace_normalized(const XML_Char *s, int is_cdata) {
- int blanks = 0;
- int at_start = 1;
- while (*s) {
- if (*s == XCS(' '))
- ++blanks;
- else if (*s == XCS('\t') || *s == XCS('\n') || *s == XCS('\r'))
- return 0;
- else {
- if (at_start) {
- at_start = 0;
- if (blanks && ! is_cdata)
- /* illegal leading blanks */
- return 0;
- } else if (blanks > 1 && ! is_cdata)
- return 0;
- blanks = 0;
- }
- ++s;
- }
- if (blanks && ! is_cdata)
- return 0;
- return 1;
-}
-
-/* Check the attribute whitespace checker: */
-static void
-testhelper_is_whitespace_normalized(void) {
- assert(is_whitespace_normalized(XCS("abc"), 0));
- assert(is_whitespace_normalized(XCS("abc"), 1));
- assert(is_whitespace_normalized(XCS("abc def ghi"), 0));
- assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
- assert(! is_whitespace_normalized(XCS(" abc def ghi"), 0));
- assert(is_whitespace_normalized(XCS(" abc def ghi"), 1));
- assert(! is_whitespace_normalized(XCS("abc def ghi"), 0));
- assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
- assert(! is_whitespace_normalized(XCS("abc def ghi "), 0));
- assert(is_whitespace_normalized(XCS("abc def ghi "), 1));
- assert(! is_whitespace_normalized(XCS(" "), 0));
- assert(is_whitespace_normalized(XCS(" "), 1));
- assert(! is_whitespace_normalized(XCS("\t"), 0));
- assert(! is_whitespace_normalized(XCS("\t"), 1));
- assert(! is_whitespace_normalized(XCS("\n"), 0));
- assert(! is_whitespace_normalized(XCS("\n"), 1));
- assert(! is_whitespace_normalized(XCS("\r"), 0));
- assert(! is_whitespace_normalized(XCS("\r"), 1));
- assert(! is_whitespace_normalized(XCS("abc\t def"), 1));
-}
-
-static void XMLCALL
-check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- int i;
- UNUSED_P(userData);
- UNUSED_P(name);
- for (i = 0; atts[i] != NULL; i += 2) {
- const XML_Char *attrname = atts[i];
- const XML_Char *value = atts[i + 1];
- if (xcstrcmp(XCS("attr"), attrname) == 0
- || xcstrcmp(XCS("ents"), attrname) == 0
- || xcstrcmp(XCS("refs"), attrname) == 0) {
- if (! is_whitespace_normalized(value, 0)) {
- char buffer[256];
- sprintf(buffer,
- "attribute value not normalized: %" XML_FMT_STR
- "='%" XML_FMT_STR "'",
- attrname, value);
- fail(buffer);
- }
- }
- }
-}
-
-START_TEST(test_attr_whitespace_normalization) {
- const char *text
- = "<!DOCTYPE doc [\n"
- " <!ATTLIST doc\n"
- " attr NMTOKENS #REQUIRED\n"
- " ents ENTITIES #REQUIRED\n"
- " refs IDREFS #REQUIRED>\n"
- "]>\n"
- "<doc attr=' a b c\t\td\te\t' refs=' id-1 \t id-2\t\t' \n"
- " ents=' ent-1 \t\r\n"
- " ent-2 ' >\n"
- " <e id='id-1'/>\n"
- " <e id='id-2'/>\n"
- "</doc>";
-
- XML_SetStartElementHandler(g_parser,
- check_attr_contains_normalized_whitespace);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/*
- * XML declaration tests.
- */
-
-START_TEST(test_xmldecl_misplaced) {
- expect_failure("\n"
- "<?xml version='1.0'?>\n"
- "<a/>",
- XML_ERROR_MISPLACED_XML_PI,
- "failed to report misplaced XML declaration");
-}
-END_TEST
-
-START_TEST(test_xmldecl_invalid) {
- expect_failure("<?xml version='1.0' \xc3\xa7?>\n<doc/>", XML_ERROR_XML_DECL,
- "Failed to report invalid XML declaration");
-}
-END_TEST
-
-START_TEST(test_xmldecl_missing_attr) {
- expect_failure("<?xml ='1.0'?>\n<doc/>\n", XML_ERROR_XML_DECL,
- "Failed to report missing XML declaration attribute");
-}
-END_TEST
-
-START_TEST(test_xmldecl_missing_value) {
- expect_failure("<?xml version='1.0' encoding='us-ascii' standalone?>\n"
- "<doc/>",
- XML_ERROR_XML_DECL,
- "Failed to report missing attribute value");
-}
-END_TEST
-
-/* Regression test for SF bug #584832. */
-static int XMLCALL
-UnknownEncodingHandler(void *data, const XML_Char *encoding,
- XML_Encoding *info) {
- UNUSED_P(data);
- if (xcstrcmp(encoding, XCS("unsupported-encoding")) == 0) {
- int i;
- for (i = 0; i < 256; ++i)
- info->map[i] = i;
- info->data = NULL;
- info->convert = NULL;
- info->release = NULL;
- return XML_STATUS_OK;
- }
- return XML_STATUS_ERROR;
-}
-
-START_TEST(test_unknown_encoding_internal_entity) {
- const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
- "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
- "<test a='&foo;'/>";
-
- XML_SetUnknownEncodingHandler(g_parser, UnknownEncodingHandler, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test unrecognised encoding handler */
-static void
-dummy_release(void *data) {
- UNUSED_P(data);
-}
-
-static int XMLCALL
-UnrecognisedEncodingHandler(void *data, const XML_Char *encoding,
- XML_Encoding *info) {
- UNUSED_P(data);
- UNUSED_P(encoding);
- info->data = NULL;
- info->convert = NULL;
- info->release = dummy_release;
- return XML_STATUS_ERROR;
-}
-
-START_TEST(test_unrecognised_encoding_internal_entity) {
- const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
- "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
- "<test a='&foo;'/>";
-
- XML_SetUnknownEncodingHandler(g_parser, UnrecognisedEncodingHandler, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Unrecognised encoding not rejected");
-}
-END_TEST
-
-/* Regression test for SF bug #620106. */
-static int XMLCALL
-external_entity_loader(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- ExtTest *test_data = (ExtTest *)XML_GetUserData(parser);
- XML_Parser extparser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (extparser == NULL)
- fail("Could not create external entity parser.");
- if (test_data->encoding != NULL) {
- if (! XML_SetEncoding(extparser, test_data->encoding))
- fail("XML_SetEncoding() ignored for external entity");
- }
- if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
- (int)strlen(test_data->parse_text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(extparser);
- return XML_STATUS_ERROR;
- }
- XML_ParserFree(extparser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ext_entity_set_encoding) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest test_data
- = {/* This text says it's an unsupported encoding, but it's really
- UTF-8, which we tell Expat using XML_SetEncoding().
- */
- "<?xml encoding='iso-8859-3'?>\xC3\xA9", XCS("utf-8"), NULL};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e9");
-#else
- const XML_Char *expected = XCS("\xc3\xa9");
-#endif
-
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- run_ext_character_check(text, &test_data, expected);
-}
-END_TEST
-
-/* Test external entities with no handler */
-START_TEST(test_ext_entity_no_handler) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
-
- XML_SetDefaultHandler(g_parser, dummy_default_handler);
- run_character_check(text, XCS(""));
-}
-END_TEST
-
-/* Test UTF-8 BOM is accepted */
-START_TEST(test_ext_entity_set_bom) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest test_data = {"\xEF\xBB\xBF" /* BOM */
- "<?xml encoding='iso-8859-3'?>"
- "\xC3\xA9",
- XCS("utf-8"), NULL};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e9");
-#else
- const XML_Char *expected = XCS("\xc3\xa9");
-#endif
-
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- run_ext_character_check(text, &test_data, expected);
-}
-END_TEST
-
-/* Test that bad encodings are faulted */
-typedef struct ext_faults {
- const char *parse_text;
- const char *fail_text;
- const XML_Char *encoding;
- enum XML_Error error;
-} ExtFaults;
-
-static int XMLCALL
-external_entity_faulter(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- XML_Parser ext_parser;
- ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (fault->encoding != NULL) {
- if (! XML_SetEncoding(ext_parser, fault->encoding))
- fail("XML_SetEncoding failed");
- }
- if (_XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
- (int)strlen(fault->parse_text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail(fault->fail_text);
- if (XML_GetErrorCode(ext_parser) != fault->error)
- xml_failure(ext_parser);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_ERROR;
-}
-
-START_TEST(test_ext_entity_bad_encoding) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtFaults fault
- = {"<?xml encoding='iso-8859-3'?>u", "Unsupported encoding not faulted",
- XCS("unknown"), XML_ERROR_UNKNOWN_ENCODING};
-
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- XML_SetUserData(g_parser, &fault);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Bad encoding should not have been accepted");
-}
-END_TEST
-
-/* Try handing an invalid encoding to an external entity parser */
-START_TEST(test_ext_entity_bad_encoding_2) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- ExtFaults fault
- = {"<!ELEMENT doc (#PCDATA)*>", "Unknown encoding not faulted",
- XCS("unknown-encoding"), XML_ERROR_UNKNOWN_ENCODING};
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- XML_SetUserData(g_parser, &fault);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Bad encoding not faulted in external entity handler");
-}
-END_TEST
-
-/* Test that no error is reported for unknown entities if we don't
- read an external subset. This was fixed in Expat 1.95.5.
-*/
-START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
- const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test that an error is reported for unknown entities if we don't
- have an external subset.
-*/
-START_TEST(test_wfc_undeclared_entity_no_external_subset) {
- expect_failure("<doc>&entity;</doc>", XML_ERROR_UNDEFINED_ENTITY,
- "Parser did not report undefined entity w/out a DTD.");
-}
-END_TEST
-
-/* Test that an error is reported for unknown entities if we don't
- read an external subset, but have been declared standalone.
-*/
-START_TEST(test_wfc_undeclared_entity_standalone) {
- const char *text
- = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
-
- expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
- "Parser did not report undefined entity (standalone).");
-}
-END_TEST
-
-/* Test that an error is reported for unknown entities if we have read
- an external subset, and standalone is true.
-*/
-START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
- const char *text
- = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &test_data);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
- "Parser did not report undefined entity (external DTD).");
-}
-END_TEST
-
-/* Test that external entity handling is not done if the parsing flag
- * is set to UNLESS_STANDALONE
- */
-START_TEST(test_entity_with_external_subset_unless_standalone) {
- const char *text
- = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ENTITY entity 'bar'>", NULL, NULL};
-
- XML_SetParamEntityParsing(g_parser,
- XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
- XML_SetUserData(g_parser, &test_data);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
- "Parser did not report undefined entity");
-}
-END_TEST
-
-/* Test that no error is reported for unknown entities if we have read
- an external subset, and standalone is false.
-*/
-START_TEST(test_wfc_undeclared_entity_with_external_subset) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- run_ext_character_check(text, &test_data, XCS(""));
-}
-END_TEST
-
-/* Test that an error is reported if our NotStandalone handler fails */
-static int XMLCALL
-reject_not_standalone_handler(void *userData) {
- UNUSED_P(userData);
- return XML_STATUS_ERROR;
-}
-
-START_TEST(test_not_standalone_handler_reject) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &test_data);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
- expect_failure(text, XML_ERROR_NOT_STANDALONE,
- "NotStandalone handler failed to reject");
-
- /* Try again but without external entity handling */
- XML_ParserReset(g_parser, NULL);
- XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
- expect_failure(text, XML_ERROR_NOT_STANDALONE,
- "NotStandalone handler failed to reject");
-}
-END_TEST
-
-/* Test that no error is reported if our NotStandalone handler succeeds */
-static int XMLCALL
-accept_not_standalone_handler(void *userData) {
- UNUSED_P(userData);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_not_standalone_handler_accept) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
- run_ext_character_check(text, &test_data, XCS(""));
-
- /* Repeat wtihout the external entity handler */
- XML_ParserReset(g_parser, NULL);
- XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
- run_character_check(text, XCS(""));
-}
-END_TEST
-
-START_TEST(test_wfc_no_recursive_entity_refs) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY entity '&#38;entity;'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
-
- expect_failure(text, XML_ERROR_RECURSIVE_ENTITY_REF,
- "Parser did not report recursive entity reference.");
-}
-END_TEST
-
-/* Test incomplete external entities are faulted */
-START_TEST(test_ext_entity_invalid_parse) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- const ExtFaults faults[]
- = {{"<", "Incomplete element declaration not faulted", NULL,
- XML_ERROR_UNCLOSED_TOKEN},
- {"<\xe2\x82", /* First two bytes of a three-byte char */
- "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
- {"<tag>\xe2\x82", "Incomplete character in CDATA not faulted", NULL,
- XML_ERROR_PARTIAL_CHAR},
- {NULL, NULL, NULL, XML_ERROR_NONE}};
- const ExtFaults *fault = faults;
-
- for (; fault->parse_text != NULL; fault++) {
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- XML_SetUserData(g_parser, (void *)fault);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Parser did not report external entity error");
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-/* Regression test for SF bug #483514. */
-START_TEST(test_dtd_default_handling) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
- "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
- "<!ELEMENT doc EMPTY>\n"
- "<!ATTLIST doc a CDATA #IMPLIED>\n"
- "<?pi in dtd?>\n"
- "<!--comment in dtd-->\n"
- "]><doc/>";
-
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
- XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
- XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
- XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
- XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
- XML_SetCommentHandler(g_parser, dummy_comment_handler);
- XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
- XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
- run_character_check(text, XCS("\n\n\n\n\n\n\n<doc/>"));
-}
-END_TEST
-
-/* Test handling of attribute declarations */
-typedef struct AttTest {
- const char *definition;
- const XML_Char *element_name;
- const XML_Char *attr_name;
- const XML_Char *attr_type;
- const XML_Char *default_value;
- int is_required;
-} AttTest;
-
-static void XMLCALL
-verify_attlist_decl_handler(void *userData, const XML_Char *element_name,
- const XML_Char *attr_name,
- const XML_Char *attr_type,
- const XML_Char *default_value, int is_required) {
- AttTest *at = (AttTest *)userData;
-
- if (xcstrcmp(element_name, at->element_name))
- fail("Unexpected element name in attribute declaration");
- if (xcstrcmp(attr_name, at->attr_name))
- fail("Unexpected attribute name in attribute declaration");
- if (xcstrcmp(attr_type, at->attr_type))
- fail("Unexpected attribute type in attribute declaration");
- if ((default_value == NULL && at->default_value != NULL)
- || (default_value != NULL && at->default_value == NULL)
- || (default_value != NULL && xcstrcmp(default_value, at->default_value)))
- fail("Unexpected default value in attribute declaration");
- if (is_required != at->is_required)
- fail("Requirement mismatch in attribute declaration");
-}
-
-START_TEST(test_dtd_attr_handling) {
- const char *prolog = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc EMPTY>\n";
- AttTest attr_data[]
- = {{"<!ATTLIST doc a ( one | two | three ) #REQUIRED>\n"
- "]>"
- "<doc a='two'/>",
- XCS("doc"), XCS("a"),
- XCS("(one|two|three)"), /* Extraneous spaces will be removed */
- NULL, XML_TRUE},
- {"<!NOTATION foo SYSTEM 'http://example.org/foo'>\n"
- "<!ATTLIST doc a NOTATION (foo) #IMPLIED>\n"
- "]>"
- "<doc/>",
- XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), NULL, XML_FALSE},
- {"<!ATTLIST doc a NOTATION (foo) 'bar'>\n"
- "]>"
- "<doc/>",
- XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), XCS("bar"), XML_FALSE},
- {"<!ATTLIST doc a CDATA '\xdb\xb2'>\n"
- "]>"
- "<doc/>",
- XCS("doc"), XCS("a"), XCS("CDATA"),
-#ifdef XML_UNICODE
- XCS("\x06f2"),
-#else
- XCS("\xdb\xb2"),
-#endif
- XML_FALSE},
- {NULL, NULL, NULL, NULL, NULL, XML_FALSE}};
- AttTest *test;
-
- for (test = attr_data; test->definition != NULL; test++) {
- XML_SetAttlistDeclHandler(g_parser, verify_attlist_decl_handler);
- XML_SetUserData(g_parser, test);
- if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)strlen(prolog),
- XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (_XML_Parse_SINGLE_BYTES(g_parser, test->definition,
- (int)strlen(test->definition), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-/* See related SF bug #673791.
- When namespace processing is enabled, setting the namespace URI for
- a prefix is not allowed; this test ensures that it *is* allowed
- when namespace processing is not enabled.
- (See Namespaces in XML, section 2.)
-*/
-START_TEST(test_empty_ns_without_namespaces) {
- const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
- " <e xmlns:prefix=''/>\n"
- "</doc>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Regression test for SF bug #824420.
- Checks that an xmlns:prefix attribute set in an attribute's default
- value isn't misinterpreted.
-*/
-START_TEST(test_ns_in_attribute_default_without_namespaces) {
- const char *text = "<!DOCTYPE e:element [\n"
- " <!ATTLIST e:element\n"
- " xmlns:e CDATA 'http://example.org/'>\n"
- " ]>\n"
- "<e:element/>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-static const char *long_character_data_text
- = "<?xml version='1.0' encoding='iso-8859-1'?><s>"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "</s>";
-
-static XML_Bool resumable = XML_FALSE;
-
-static void
-clearing_aborting_character_handler(void *userData, const XML_Char *s,
- int len) {
- UNUSED_P(userData);
- UNUSED_P(s);
- UNUSED_P(len);
- XML_StopParser(g_parser, resumable);
- XML_SetCharacterDataHandler(g_parser, NULL);
-}
-
-/* Regression test for SF bug #1515266: missing check of stopped
- parser in doContext() 'for' loop. */
-START_TEST(test_stop_parser_between_char_data_calls) {
- /* The sample data must be big enough that there are two calls to
- the character data handler from within the inner "for" loop of
- the XML_TOK_DATA_CHARS case in doContent(), and the character
- handler must stop the parser and clear the character data
- handler.
- */
- const char *text = long_character_data_text;
-
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- resumable = XML_FALSE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Regression test for SF bug #1515266: missing check of stopped
- parser in doContext() 'for' loop. */
-START_TEST(test_suspend_parser_between_char_data_calls) {
- /* The sample data must be big enough that there are two calls to
- the character data handler from within the inner "for" loop of
- the XML_TOK_DATA_CHARS case in doContent(), and the character
- handler must stop the parser and clear the character data
- handler.
- */
- const char *text = long_character_data_text;
-
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- resumable = XML_TRUE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
- if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
- xml_failure(g_parser);
- /* Try parsing directly */
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Attempt to continue parse while suspended not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
- fail("Suspended parse not faulted with correct error");
-}
-END_TEST
-
-static XML_Bool abortable = XML_FALSE;
-
-static void
-parser_stop_character_handler(void *userData, const XML_Char *s, int len) {
- UNUSED_P(userData);
- UNUSED_P(s);
- UNUSED_P(len);
- XML_StopParser(g_parser, resumable);
- XML_SetCharacterDataHandler(g_parser, NULL);
- if (! resumable) {
- /* Check that aborting an aborted parser is faulted */
- if (XML_StopParser(g_parser, XML_FALSE) != XML_STATUS_ERROR)
- fail("Aborting aborted parser not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
- xml_failure(g_parser);
- } else if (abortable) {
- /* Check that aborting a suspended parser works */
- if (XML_StopParser(g_parser, XML_FALSE) == XML_STATUS_ERROR)
- xml_failure(g_parser);
- } else {
- /* Check that suspending a suspended parser works */
- if (XML_StopParser(g_parser, XML_TRUE) != XML_STATUS_ERROR)
- fail("Suspending suspended parser not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
- xml_failure(g_parser);
- }
-}
-
-/* Test repeated calls to XML_StopParser are handled correctly */
-START_TEST(test_repeated_stop_parser_between_char_data_calls) {
- const char *text = long_character_data_text;
-
- XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
- resumable = XML_FALSE;
- abortable = XML_FALSE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Failed to double-stop parser");
-
- XML_ParserReset(g_parser, NULL);
- XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
- resumable = XML_TRUE;
- abortable = XML_FALSE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- fail("Failed to double-suspend parser");
-
- XML_ParserReset(g_parser, NULL);
- XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
- resumable = XML_TRUE;
- abortable = XML_TRUE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Failed to suspend-abort parser");
-}
-END_TEST
-
-START_TEST(test_good_cdata_ascii) {
- const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
- const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
-
- CharData storage;
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- /* Add start and end handlers for coverage */
- XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
- XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-
- /* Try again, this time with a default handler */
- XML_ParserReset(g_parser, NULL);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- XML_SetDefaultHandler(g_parser, dummy_default_handler);
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_good_cdata_utf16) {
- /* Test data is:
- * <?xml version='1.0' encoding='utf-16'?>
- * <a><![CDATA[hello]]></a>
- */
- const char text[]
- = "\0<\0?\0x\0m\0l\0"
- " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
- " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
- "1\0"
- "6\0'"
- "\0?\0>\0\n"
- "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>";
- const XML_Char *expected = XCS("hello");
-
- CharData storage;
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_good_cdata_utf16_le) {
- /* Test data is:
- * <?xml version='1.0' encoding='utf-16'?>
- * <a><![CDATA[hello]]></a>
- */
- const char text[]
- = "<\0?\0x\0m\0l\0"
- " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
- " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
- "1\0"
- "6\0'"
- "\0?\0>\0\n"
- "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>\0";
- const XML_Char *expected = XCS("hello");
-
- CharData storage;
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test UTF16 conversion of a long cdata string */
-
-/* 16 characters: handy macro to reduce visual clutter */
-#define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"
-
-START_TEST(test_long_cdata_utf16) {
- /* Test data is:
- * <?xlm version='1.0' encoding='utf-16'?>
- * <a><![CDATA[
- * ABCDEFGHIJKLMNOP
- * ]]></a>
- */
- const char text[]
- = "\0<\0?\0x\0m\0l\0 "
- "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 "
- "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>"
- "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
- /* 64 characters per line */
- /* clang-format off */
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
- A_TO_P_IN_UTF16
- /* clang-format on */
- "\0]\0]\0>\0<\0/\0a\0>";
- const XML_Char *expected =
- /* clang-format off */
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
- XCS("ABCDEFGHIJKLMNOP");
- /* clang-format on */
- CharData storage;
- void *buffer;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- buffer = XML_GetBuffer(g_parser, sizeof(text) - 1);
- if (buffer == NULL)
- fail("Could not allocate parse buffer");
- assert(buffer != NULL);
- memcpy(buffer, text, sizeof(text) - 1);
- if (XML_ParseBuffer(g_parser, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test handling of multiple unit UTF-16 characters */
-START_TEST(test_multichar_cdata_utf16) {
- /* Test data is:
- * <?xml version='1.0' encoding='utf-16'?>
- * <a><![CDATA[{MINIM}{CROTCHET}]]></a>
- *
- * where {MINIM} is U+1d15e (a minim or half-note)
- * UTF-16: 0xd834 0xdd5e
- * UTF-8: 0xf0 0x9d 0x85 0x9e
- * and {CROTCHET} is U+1d15f (a crotchet or quarter-note)
- * UTF-16: 0xd834 0xdd5f
- * UTF-8: 0xf0 0x9d 0x85 0x9f
- */
- const char text[] = "\0<\0?\0x\0m\0l\0"
- " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
- " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
- "1\0"
- "6\0'"
- "\0?\0>\0\n"
- "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
- "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f"
- "\0]\0]\0>\0<\0/\0a\0>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\xd834\xdd5e\xd834\xdd5f");
-#else
- const XML_Char *expected = XCS("\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test that an element name with a UTF-16 surrogate pair is rejected */
-START_TEST(test_utf16_bad_surrogate_pair) {
- /* Test data is:
- * <?xml version='1.0' encoding='utf-16'?>
- * <a><![CDATA[{BADLINB}]]></a>
- *
- * where {BADLINB} is U+10000 (the first Linear B character)
- * with the UTF-16 surrogate pair in the wrong order, i.e.
- * 0xdc00 0xd800
- */
- const char text[] = "\0<\0?\0x\0m\0l\0"
- " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
- " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
- "1\0"
- "6\0'"
- "\0?\0>\0\n"
- "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
- "\xdc\x00\xd8\x00"
- "\0]\0]\0>\0<\0/\0a\0>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Reversed UTF-16 surrogate pair not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_bad_cdata) {
- struct CaseData {
- const char *text;
- enum XML_Error expectedError;
- };
-
- struct CaseData cases[]
- = {{"<a><", XML_ERROR_UNCLOSED_TOKEN},
- {"<a><!", XML_ERROR_UNCLOSED_TOKEN},
- {"<a><![", XML_ERROR_UNCLOSED_TOKEN},
- {"<a><![C", XML_ERROR_UNCLOSED_TOKEN},
- {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN},
- {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN},
- {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN},
- {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN},
-
- {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION},
- {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION},
- {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION},
-
- {"<a><!<a/>", XML_ERROR_INVALID_TOKEN},
- {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
- {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
- {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN},
- {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN},
- {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN},
- {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN},
-
- {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
- {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
- {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}};
-
- size_t i = 0;
- for (; i < sizeof(cases) / sizeof(struct CaseData); i++) {
- const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES(
- g_parser, cases[i].text, (int)strlen(cases[i].text), XML_TRUE);
- const enum XML_Error actualError = XML_GetErrorCode(g_parser);
-
- assert(actualStatus == XML_STATUS_ERROR);
-
- if (actualError != cases[i].expectedError) {
- char message[100];
- sprintf(message,
- "Expected error %d but got error %d for case %u: \"%s\"\n",
- cases[i].expectedError, actualError, (unsigned int)i + 1,
- cases[i].text);
- fail(message);
- }
-
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-/* Test failures in UTF-16 CDATA */
-START_TEST(test_bad_cdata_utf16) {
- struct CaseData {
- size_t text_bytes;
- const char *text;
- enum XML_Error expected_error;
- };
-
- const char prolog[] = "\0<\0?\0x\0m\0l\0"
- " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
- " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
- "1\0"
- "6\0'"
- "\0?\0>\0\n"
- "\0<\0a\0>";
- struct CaseData cases[] = {
- {1, "\0", XML_ERROR_UNCLOSED_TOKEN},
- {2, "\0<", XML_ERROR_UNCLOSED_TOKEN},
- {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN},
- {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN},
- {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN},
- {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN},
- {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN},
- {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN},
- {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN},
- {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN},
- {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN},
- {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN},
- {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN},
- {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN},
- {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN},
- {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN},
- {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN},
- {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", XML_ERROR_UNCLOSED_CDATA_SECTION},
- {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", XML_ERROR_UNCLOSED_CDATA_SECTION},
- {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", XML_ERROR_UNCLOSED_CDATA_SECTION},
- /* Now add a four-byte UTF-16 character */
- {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8",
- XML_ERROR_UNCLOSED_CDATA_SECTION},
- {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", XML_ERROR_PARTIAL_CHAR},
- {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd",
- XML_ERROR_PARTIAL_CHAR},
- {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e",
- XML_ERROR_UNCLOSED_CDATA_SECTION}};
- size_t i;
-
- for (i = 0; i < sizeof(cases) / sizeof(struct CaseData); i++) {
- enum XML_Status actual_status;
- enum XML_Error actual_error;
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)sizeof(prolog) - 1,
- XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- actual_status = _XML_Parse_SINGLE_BYTES(g_parser, cases[i].text,
- (int)cases[i].text_bytes, XML_TRUE);
- assert(actual_status == XML_STATUS_ERROR);
- actual_error = XML_GetErrorCode(g_parser);
- if (actual_error != cases[i].expected_error) {
- char message[1024];
-
- sprintf(message,
- "Expected error %d (%" XML_FMT_STR "), got %d (%" XML_FMT_STR
- ") for case %lu\n",
- cases[i].expected_error, XML_ErrorString(cases[i].expected_error),
- actual_error, XML_ErrorString(actual_error),
- (long unsigned)(i + 1));
- fail(message);
- }
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-static const char *long_cdata_text
- = "<s><![CDATA["
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "]]></s>";
-
-/* Test stopping the parser in cdata handler */
-START_TEST(test_stop_parser_between_cdata_calls) {
- const char *text = long_cdata_text;
-
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- resumable = XML_FALSE;
- expect_failure(text, XML_ERROR_ABORTED, "Parse not aborted in CDATA handler");
-}
-END_TEST
-
-/* Test suspending the parser in cdata handler */
-START_TEST(test_suspend_parser_between_cdata_calls) {
- const char *text = long_cdata_text;
- enum XML_Status result;
-
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- resumable = XML_TRUE;
- result = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
- if (result != XML_STATUS_SUSPENDED) {
- if (result == XML_STATUS_ERROR)
- xml_failure(g_parser);
- fail("Parse not suspended in CDATA handler");
- }
- if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test memory allocation functions */
-START_TEST(test_memory_allocation) {
- char *buffer = (char *)XML_MemMalloc(g_parser, 256);
- char *p;
-
- if (buffer == NULL) {
- fail("Allocation failed");
- } else {
- /* Try writing to memory; some OSes try to cheat! */
- buffer[0] = 'T';
- buffer[1] = 'E';
- buffer[2] = 'S';
- buffer[3] = 'T';
- buffer[4] = '\0';
- if (strcmp(buffer, "TEST") != 0) {
- fail("Memory not writable");
- } else {
- p = (char *)XML_MemRealloc(g_parser, buffer, 512);
- if (p == NULL) {
- fail("Reallocation failed");
- } else {
- /* Write again, just to be sure */
- buffer = p;
- buffer[0] = 'V';
- if (strcmp(buffer, "VEST") != 0) {
- fail("Reallocated memory not writable");
- }
- }
- }
- XML_MemFree(g_parser, buffer);
- }
-}
-END_TEST
-
-static void XMLCALL
-record_default_handler(void *userData, const XML_Char *s, int len) {
- UNUSED_P(s);
- UNUSED_P(len);
- CharData_AppendXMLChars((CharData *)userData, XCS("D"), 1);
-}
-
-static void XMLCALL
-record_cdata_handler(void *userData, const XML_Char *s, int len) {
- UNUSED_P(s);
- UNUSED_P(len);
- CharData_AppendXMLChars((CharData *)userData, XCS("C"), 1);
- XML_DefaultCurrent(g_parser);
-}
-
-static void XMLCALL
-record_cdata_nodefault_handler(void *userData, const XML_Char *s, int len) {
- UNUSED_P(s);
- UNUSED_P(len);
- CharData_AppendXMLChars((CharData *)userData, XCS("c"), 1);
-}
-
-static void XMLCALL
-record_skip_handler(void *userData, const XML_Char *entityName,
- int is_parameter_entity) {
- UNUSED_P(entityName);
- CharData_AppendXMLChars((CharData *)userData,
- is_parameter_entity ? XCS("E") : XCS("e"), 1);
-}
-
-/* Test XML_DefaultCurrent() passes handling on correctly */
-START_TEST(test_default_current) {
- const char *text = "<doc>hell]</doc>";
- const char *entity_text = "<!DOCTYPE doc [\n"
- "<!ENTITY entity '&#37;'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
- CharData storage;
-
- XML_SetDefaultHandler(g_parser, record_default_handler);
- XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, XCS("DCDCDCDCDCDD"));
-
- /* Again, without the defaulting */
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandler(g_parser, record_default_handler);
- XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, XCS("DcccccD"));
-
- /* Now with an internal entity to complicate matters */
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandler(g_parser, record_default_handler);
- XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
- XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- /* The default handler suppresses the entity */
- CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDDD"));
-
- /* Again, with a skip handler */
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandler(g_parser, record_default_handler);
- XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
- XML_SetSkippedEntityHandler(g_parser, record_skip_handler);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
- XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- /* The default handler suppresses the entity */
- CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDeD"));
-
- /* This time, allow the entity through */
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
- XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
- XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDCDD"));
-
- /* Finally, without passing the cdata to the default handler */
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
- XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
- XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDcD"));
-}
-END_TEST
-
-/* Test DTD element parsing code paths */
-START_TEST(test_dtd_elements) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc (chapter)>\n"
- "<!ELEMENT chapter (#PCDATA)>\n"
- "]>\n"
- "<doc><chapter>Wombats are go</chapter></doc>";
-
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test foreign DTD handling */
-START_TEST(test_set_foreign_dtd) {
- const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
- const char *text2 = "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
-
- /* Check hash salt is passed through too */
- XML_SetHashSalt(g_parser, 0x12345678);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &test_data);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- /* Add a default handler to exercise more code paths */
- XML_SetDefaultHandler(g_parser, dummy_default_handler);
- if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
- fail("Could not set foreign DTD");
- if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-
- /* Ensure that trying to set the DTD after parsing has started
- * is faulted, even if it's the same setting.
- */
- if (XML_UseForeignDTD(g_parser, XML_TRUE)
- != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
- fail("Failed to reject late foreign DTD setting");
- /* Ditto for the hash salt */
- if (XML_SetHashSalt(g_parser, 0x23456789))
- fail("Failed to reject late hash salt change");
-
- /* Now finish the parse */
- if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test foreign DTD handling with a failing NotStandalone handler */
-START_TEST(test_foreign_dtd_not_standalone) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &test_data);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
- if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
- fail("Could not set foreign DTD");
- expect_failure(text, XML_ERROR_NOT_STANDALONE,
- "NotStandalonehandler failed to reject");
-}
-END_TEST
-
-/* Test invalid character in a foreign DTD is faulted */
-START_TEST(test_invalid_foreign_dtd) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<doc>&entity;</doc>";
- ExtFaults test_data
- = {"$", "Dollar not faulted", NULL, XML_ERROR_INVALID_TOKEN};
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &test_data);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- XML_UseForeignDTD(g_parser, XML_TRUE);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Bad DTD should not have been accepted");
-}
-END_TEST
-
-/* Test foreign DTD use with a doctype */
-START_TEST(test_foreign_dtd_with_doctype) {
- const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n";
- const char *text2 = "<doc>&entity;</doc>";
- ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
-
- /* Check hash salt is passed through too */
- XML_SetHashSalt(g_parser, 0x12345678);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &test_data);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- /* Add a default handler to exercise more code paths */
- XML_SetDefaultHandler(g_parser, dummy_default_handler);
- if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
- fail("Could not set foreign DTD");
- if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-
- /* Ensure that trying to set the DTD after parsing has started
- * is faulted, even if it's the same setting.
- */
- if (XML_UseForeignDTD(g_parser, XML_TRUE)
- != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
- fail("Failed to reject late foreign DTD setting");
- /* Ditto for the hash salt */
- if (XML_SetHashSalt(g_parser, 0x23456789))
- fail("Failed to reject late hash salt change");
-
- /* Now finish the parse */
- if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test XML_UseForeignDTD with no external subset present */
-static int XMLCALL
-external_entity_null_loader(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- UNUSED_P(parser);
- UNUSED_P(context);
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_foreign_dtd_without_external_subset) {
- const char *text = "<!DOCTYPE doc [<!ENTITY foo 'bar'>]>\n"
- "<doc>&foo;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, NULL);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
- XML_UseForeignDTD(g_parser, XML_TRUE);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_empty_foreign_dtd) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<doc>&entity;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
- XML_UseForeignDTD(g_parser, XML_TRUE);
- expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
- "Undefined entity not faulted");
-}
-END_TEST
-
-/* Test XML Base is set and unset appropriately */
-START_TEST(test_set_base) {
- const XML_Char *old_base;
- const XML_Char *new_base = XCS("/local/file/name.xml");
-
- old_base = XML_GetBase(g_parser);
- if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK)
- fail("Unable to set base");
- if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0)
- fail("Base setting not correct");
- if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK)
- fail("Unable to NULL base");
- if (XML_GetBase(g_parser) != NULL)
- fail("Base setting not nulled");
- XML_SetBase(g_parser, old_base);
-}
-END_TEST
-
-/* Test attribute counts, indexing, etc */
-typedef struct attrInfo {
- const XML_Char *name;
- const XML_Char *value;
-} AttrInfo;
-
-typedef struct elementInfo {
- const XML_Char *name;
- int attr_count;
- const XML_Char *id_name;
- AttrInfo *attributes;
-} ElementInfo;
-
-static void XMLCALL
-counting_start_element_handler(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- ElementInfo *info = (ElementInfo *)userData;
- AttrInfo *attr;
- int count, id, i;
-
- while (info->name != NULL) {
- if (! xcstrcmp(name, info->name))
- break;
- info++;
- }
- if (info->name == NULL)
- fail("Element not recognised");
- /* The attribute count is twice what you might expect. It is a
- * count of items in atts, an array which contains alternating
- * attribute names and attribute values. For the naive user this
- * is possibly a little unexpected, but it is what the
- * documentation in expat.h tells us to expect.
- */
- count = XML_GetSpecifiedAttributeCount(g_parser);
- if (info->attr_count * 2 != count) {
- fail("Not got expected attribute count");
- return;
- }
- id = XML_GetIdAttributeIndex(g_parser);
- if (id == -1 && info->id_name != NULL) {
- fail("ID not present");
- return;
- }
- if (id != -1 && xcstrcmp(atts[id], info->id_name)) {
- fail("ID does not have the correct name");
- return;
- }
- for (i = 0; i < info->attr_count; i++) {
- attr = info->attributes;
- while (attr->name != NULL) {
- if (! xcstrcmp(atts[0], attr->name))
- break;
- attr++;
- }
- if (attr->name == NULL) {
- fail("Attribute not recognised");
- return;
- }
- if (xcstrcmp(atts[1], attr->value)) {
- fail("Attribute has wrong value");
- return;
- }
- /* Remember, two entries in atts per attribute (see above) */
- atts += 2;
- }
-}
-
-START_TEST(test_attributes) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc (tag)>\n"
- "<!ATTLIST doc id ID #REQUIRED>\n"
- "]>"
- "<doc a='1' id='one' b='2'>"
- "<tag c='3'/>"
- "</doc>";
- AttrInfo doc_info[] = {{XCS("a"), XCS("1")},
- {XCS("b"), XCS("2")},
- {XCS("id"), XCS("one")},
- {NULL, NULL}};
- AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL},
- {XCS("tag"), 1, NULL, NULL},
- {NULL, 0, NULL, NULL}};
- info[0].attributes = doc_info;
- info[1].attributes = tag_info;
-
- XML_SetStartElementHandler(g_parser, counting_start_element_handler);
- XML_SetUserData(g_parser, info);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test reset works correctly in the middle of processing an internal
- * entity. Exercises some obscure code in XML_ParserReset().
- */
-START_TEST(test_reset_in_entity) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ENTITY wombat 'wom'>\n"
- "<!ENTITY entity 'hi &wom; there'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
- XML_ParsingStatus status;
-
- resumable = XML_TRUE;
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- XML_GetParsingStatus(g_parser, &status);
- if (status.parsing != XML_SUSPENDED)
- fail("Parsing status not SUSPENDED");
- XML_ParserReset(g_parser, NULL);
- XML_GetParsingStatus(g_parser, &status);
- if (status.parsing != XML_INITIALIZED)
- fail("Parsing status doesn't reset to INITIALIZED");
-}
-END_TEST
-
-/* Test that resume correctly passes through parse errors */
-START_TEST(test_resume_invalid_parse) {
- const char *text = "<doc>Hello</doc"; /* Missing closing wedge */
-
- resumable = XML_TRUE;
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (XML_ResumeParser(g_parser) == XML_STATUS_OK)
- fail("Resumed invalid parse not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_UNCLOSED_TOKEN)
- fail("Invalid parse not correctly faulted");
-}
-END_TEST
-
-/* Test that re-suspended parses are correctly passed through */
-START_TEST(test_resume_resuspended) {
- const char *text = "<doc>Hello<meep/>world</doc>";
-
- resumable = XML_TRUE;
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- resumable = XML_TRUE;
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
- fail("Resumption not suspended");
- /* This one should succeed and finish up */
- if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test that CDATA shows up correctly through a default handler */
-START_TEST(test_cdata_default) {
- const char *text = "<doc><![CDATA[Hello\nworld]]></doc>";
- const XML_Char *expected = XCS("<doc><![CDATA[Hello\nworld]]></doc>");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetDefaultHandler(g_parser, accumulate_characters);
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test resetting a subordinate parser does exactly nothing */
-static int XMLCALL
-external_entity_resetter(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<!ELEMENT doc (#PCDATA)*>";
- XML_Parser ext_parser;
- XML_ParsingStatus status;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_GetParsingStatus(ext_parser, &status);
- if (status.parsing != XML_INITIALIZED) {
- fail("Parsing status is not INITIALIZED");
- return XML_STATUS_ERROR;
- }
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(parser);
- return XML_STATUS_ERROR;
- }
- XML_GetParsingStatus(ext_parser, &status);
- if (status.parsing != XML_FINISHED) {
- fail("Parsing status is not FINISHED");
- return XML_STATUS_ERROR;
- }
- /* Check we can't parse here */
- if (XML_Parse(ext_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Parsing when finished not faulted");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_FINISHED)
- fail("Parsing when finished faulted with wrong code");
- XML_ParserReset(ext_parser, NULL);
- XML_GetParsingStatus(ext_parser, &status);
- if (status.parsing != XML_FINISHED) {
- fail("Parsing status not still FINISHED");
- return XML_STATUS_ERROR;
- }
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_subordinate_reset) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_resetter);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test suspending a subordinate parser */
-
-static void XMLCALL
-entity_suspending_decl_handler(void *userData, const XML_Char *name,
- XML_Content *model) {
- XML_Parser ext_parser = (XML_Parser)userData;
-
- UNUSED_P(name);
- if (XML_StopParser(ext_parser, XML_TRUE) != XML_STATUS_ERROR)
- fail("Attempting to suspend a subordinate parser not faulted");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_SUSPEND_PE)
- fail("Suspending subordinate parser get wrong code");
- XML_SetElementDeclHandler(ext_parser, NULL);
- XML_FreeContentModel(g_parser, model);
-}
-
-static int XMLCALL
-external_entity_suspender(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<!ELEMENT doc (#PCDATA)*>";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_SetElementDeclHandler(ext_parser, entity_suspending_decl_handler);
- XML_SetUserData(ext_parser, ext_parser);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(ext_parser);
- return XML_STATUS_ERROR;
- }
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_subordinate_suspend) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_suspender);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test suspending a subordinate parser from an XML declaration */
-/* Increases code coverage of the tests */
-static void XMLCALL
-entity_suspending_xdecl_handler(void *userData, const XML_Char *version,
- const XML_Char *encoding, int standalone) {
- XML_Parser ext_parser = (XML_Parser)userData;
-
- UNUSED_P(version);
- UNUSED_P(encoding);
- UNUSED_P(standalone);
- XML_StopParser(ext_parser, resumable);
- XML_SetXmlDeclHandler(ext_parser, NULL);
-}
-
-static int XMLCALL
-external_entity_suspend_xmldecl(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>";
- XML_Parser ext_parser;
- XML_ParsingStatus status;
- enum XML_Status rc;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
- XML_SetUserData(ext_parser, ext_parser);
- rc = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
- XML_GetParsingStatus(ext_parser, &status);
- if (resumable) {
- if (rc == XML_STATUS_ERROR)
- xml_failure(ext_parser);
- if (status.parsing != XML_SUSPENDED)
- fail("Ext Parsing status not SUSPENDED");
- } else {
- if (rc != XML_STATUS_ERROR)
- fail("Ext parsing not aborted");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
- xml_failure(ext_parser);
- if (status.parsing != XML_FINISHED)
- fail("Ext Parsing status not FINISHED");
- }
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_subordinate_xdecl_suspend) {
- const char *text
- = "<!DOCTYPE doc [\n"
- " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
- resumable = XML_TRUE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_subordinate_xdecl_abort) {
- const char *text
- = "<!DOCTYPE doc [\n"
- " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
- resumable = XML_FALSE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test external entity fault handling with suspension */
-static int XMLCALL
-external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId) {
- XML_Parser ext_parser;
- ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
- void *buffer;
- int parse_len = (int)strlen(fault->parse_text);
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
- XML_SetUserData(ext_parser, ext_parser);
- resumable = XML_TRUE;
- buffer = XML_GetBuffer(ext_parser, parse_len);
- if (buffer == NULL)
- fail("Could not allocate parse buffer");
- assert(buffer != NULL);
- memcpy(buffer, fault->parse_text, parse_len);
- if (XML_ParseBuffer(ext_parser, parse_len, XML_FALSE) != XML_STATUS_SUSPENDED)
- fail("XML declaration did not suspend");
- if (XML_ResumeParser(ext_parser) != XML_STATUS_OK)
- xml_failure(ext_parser);
- if (XML_ParseBuffer(ext_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
- fail(fault->fail_text);
- if (XML_GetErrorCode(ext_parser) != fault->error)
- xml_failure(ext_parser);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_ERROR;
-}
-
-START_TEST(test_ext_entity_invalid_suspended_parse) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtFaults faults[]
- = {{"<?xml version='1.0' encoding='us-ascii'?><",
- "Incomplete element declaration not faulted", NULL,
- XML_ERROR_UNCLOSED_TOKEN},
- {/* First two bytes of a three-byte char */
- "<?xml version='1.0' encoding='utf-8'?>\xe2\x82",
- "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
- {NULL, NULL, NULL, XML_ERROR_NONE}};
- ExtFaults *fault;
-
- for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser,
- external_entity_suspending_faulter);
- XML_SetUserData(g_parser, fault);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Parser did not report external entity error");
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-/* Test setting an explicit encoding */
-START_TEST(test_explicit_encoding) {
- const char *text1 = "<doc>Hello ";
- const char *text2 = " World</doc>";
-
- /* Just check that we can set the encoding to NULL before starting */
- if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
- fail("Failed to initialise encoding to NULL");
- /* Say we are UTF-8 */
- if (XML_SetEncoding(g_parser, XCS("utf-8")) != XML_STATUS_OK)
- fail("Failed to set explicit encoding");
- if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- /* Try to switch encodings mid-parse */
- if (XML_SetEncoding(g_parser, XCS("us-ascii")) != XML_STATUS_ERROR)
- fail("Allowed encoding change");
- if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- /* Try now the parse is over */
- if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
- fail("Failed to unset encoding");
-}
-END_TEST
-
-/* Test handling of trailing CR (rather than newline) */
-static void XMLCALL
-cr_cdata_handler(void *userData, const XML_Char *s, int len) {
- int *pfound = (int *)userData;
-
- /* Internal processing turns the CR into a newline for the
- * character data handler, but not for the default handler
- */
- if (len == 1 && (*s == XCS('\n') || *s == XCS('\r')))
- *pfound = 1;
-}
-
-START_TEST(test_trailing_cr) {
- const char *text = "<doc>\r";
- int found_cr;
-
- /* Try with a character handler, for code coverage */
- XML_SetCharacterDataHandler(g_parser, cr_cdata_handler);
- XML_SetUserData(g_parser, &found_cr);
- found_cr = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- fail("Failed to fault unclosed doc");
- if (found_cr == 0)
- fail("Did not catch the carriage return");
- XML_ParserReset(g_parser, NULL);
-
- /* Now with a default handler instead */
- XML_SetDefaultHandler(g_parser, cr_cdata_handler);
- XML_SetUserData(g_parser, &found_cr);
- found_cr = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- fail("Failed to fault unclosed doc");
- if (found_cr == 0)
- fail("Did not catch default carriage return");
-}
-END_TEST
-
-/* Test trailing CR in an external entity parse */
-static int XMLCALL
-external_entity_cr_catcher(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "\r";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(ext_parser);
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-static int XMLCALL
-external_entity_bad_cr_catcher(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<tag>\r";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- fail("Async entity error not caught");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
- xml_failure(ext_parser);
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ext_entity_trailing_cr) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- int found_cr;
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_cr_catcher);
- XML_SetUserData(g_parser, &found_cr);
- found_cr = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_OK)
- xml_failure(g_parser);
- if (found_cr == 0)
- fail("No carriage return found");
- XML_ParserReset(g_parser, NULL);
-
- /* Try again with a different trailing CR */
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_bad_cr_catcher);
- XML_SetUserData(g_parser, &found_cr);
- found_cr = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_OK)
- xml_failure(g_parser);
- if (found_cr == 0)
- fail("No carriage return found");
-}
-END_TEST
-
-/* Test handling of trailing square bracket */
-static void XMLCALL
-rsqb_handler(void *userData, const XML_Char *s, int len) {
- int *pfound = (int *)userData;
-
- if (len == 1 && *s == XCS(']'))
- *pfound = 1;
-}
-
-START_TEST(test_trailing_rsqb) {
- const char *text8 = "<doc>]";
- const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000";
- int found_rsqb;
- int text8_len = (int)strlen(text8);
-
- XML_SetCharacterDataHandler(g_parser, rsqb_handler);
- XML_SetUserData(g_parser, &found_rsqb);
- found_rsqb = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text8, text8_len, XML_TRUE)
- == XML_STATUS_OK)
- fail("Failed to fault unclosed doc");
- if (found_rsqb == 0)
- fail("Did not catch the right square bracket");
-
- /* Try again with a different encoding */
- XML_ParserReset(g_parser, NULL);
- XML_SetCharacterDataHandler(g_parser, rsqb_handler);
- XML_SetUserData(g_parser, &found_rsqb);
- found_rsqb = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
- XML_TRUE)
- == XML_STATUS_OK)
- fail("Failed to fault unclosed doc");
- if (found_rsqb == 0)
- fail("Did not catch the right square bracket");
-
- /* And finally with a default handler */
- XML_ParserReset(g_parser, NULL);
- XML_SetDefaultHandler(g_parser, rsqb_handler);
- XML_SetUserData(g_parser, &found_rsqb);
- found_rsqb = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
- XML_TRUE)
- == XML_STATUS_OK)
- fail("Failed to fault unclosed doc");
- if (found_rsqb == 0)
- fail("Did not catch the right square bracket");
-}
-END_TEST
-
-/* Test trailing right square bracket in an external entity parse */
-static int XMLCALL
-external_entity_rsqb_catcher(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<tag>]";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_SetCharacterDataHandler(ext_parser, rsqb_handler);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Async entity error not caught");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
- xml_failure(ext_parser);
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ext_entity_trailing_rsqb) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- int found_rsqb;
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_rsqb_catcher);
- XML_SetUserData(g_parser, &found_rsqb);
- found_rsqb = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_OK)
- xml_failure(g_parser);
- if (found_rsqb == 0)
- fail("No right square bracket found");
-}
-END_TEST
-
-/* Test CDATA handling in an external entity */
-static int XMLCALL
-external_entity_good_cdata_ascii(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
- const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
- CharData storage;
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- CharData_Init(&storage);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- XML_SetUserData(ext_parser, &storage);
- XML_SetCharacterDataHandler(ext_parser, accumulate_characters);
-
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(ext_parser);
- CharData_CheckXMLChars(&storage, expected);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ext_entity_good_cdata) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_good_cdata_ascii);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_OK)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test user parameter settings */
-/* Variable holding the expected handler userData */
-static void *handler_data = NULL;
-/* Count of the number of times the comment handler has been invoked */
-static int comment_count = 0;
-/* Count of the number of skipped entities */
-static int skip_count = 0;
-/* Count of the number of times the XML declaration handler is invoked */
-static int xdecl_count = 0;
-
-static void XMLCALL
-xml_decl_handler(void *userData, const XML_Char *version,
- const XML_Char *encoding, int standalone) {
- UNUSED_P(version);
- UNUSED_P(encoding);
- if (userData != handler_data)
- fail("User data (xml decl) not correctly set");
- if (standalone != -1)
- fail("Standalone not flagged as not present in XML decl");
- xdecl_count++;
-}
-
-static void XMLCALL
-param_check_skip_handler(void *userData, const XML_Char *entityName,
- int is_parameter_entity) {
- UNUSED_P(entityName);
- UNUSED_P(is_parameter_entity);
- if (userData != handler_data)
- fail("User data (skip) not correctly set");
- skip_count++;
-}
-
-static void XMLCALL
-data_check_comment_handler(void *userData, const XML_Char *data) {
- UNUSED_P(data);
- /* Check that the userData passed through is what we expect */
- if (userData != handler_data)
- fail("User data (parser) not correctly set");
- /* Check that the user data in the parser is appropriate */
- if (XML_GetUserData(userData) != (void *)1)
- fail("User data in parser not correctly set");
- comment_count++;
-}
-
-static int XMLCALL
-external_entity_param_checker(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<!-- Subordinate parser -->\n"
- "<!ELEMENT doc (#PCDATA)*>";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- handler_data = ext_parser;
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(parser);
- return XML_STATUS_ERROR;
- }
- handler_data = parser;
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_user_parameters) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!-- Primary parse -->\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;";
- const char *epilog = "<!-- Back to primary parser -->\n"
- "</doc>";
-
- comment_count = 0;
- skip_count = 0;
- xdecl_count = 0;
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetXmlDeclHandler(g_parser, xml_decl_handler);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_param_checker);
- XML_SetCommentHandler(g_parser, data_check_comment_handler);
- XML_SetSkippedEntityHandler(g_parser, param_check_skip_handler);
- XML_UseParserAsHandlerArg(g_parser);
- XML_SetUserData(g_parser, (void *)1);
- handler_data = g_parser;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (comment_count != 2)
- fail("Comment handler not invoked enough times");
- /* Ensure we can't change policy mid-parse */
- if (XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_NEVER))
- fail("Changed param entity parsing policy while parsing");
- if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (comment_count != 3)
- fail("Comment handler not invoked enough times");
- if (skip_count != 1)
- fail("Skip handler not invoked enough times");
- if (xdecl_count != 1)
- fail("XML declaration handler not invoked");
-}
-END_TEST
-
-/* Test that an explicit external entity handler argument replaces
- * the parser as the first argument.
- *
- * We do not call the first parameter to the external entity handler
- * 'parser' for once, since the first time the handler is called it
- * will actually be a text string. We need to be able to access the
- * global 'parser' variable to create our external entity parser from,
- * since there are code paths we need to ensure get executed.
- */
-static int XMLCALL
-external_entity_ref_param_checker(XML_Parser parameter, const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<!ELEMENT doc (#PCDATA)*>";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- if ((void *)parameter != handler_data)
- fail("External entity ref handler parameter not correct");
-
- /* Here we use the global 'parser' variable */
- ext_parser = XML_ExternalEntityParserCreate(g_parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(ext_parser);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ext_entity_ref_parameter) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
- /* Set a handler arg that is not NULL and not parser (which is
- * what NULL would cause to be passed.
- */
- XML_SetExternalEntityRefHandlerArg(g_parser, (void *)text);
- handler_data = (void *)text;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-
- /* Now try again with unset args */
- XML_ParserReset(g_parser, NULL);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
- XML_SetExternalEntityRefHandlerArg(g_parser, NULL);
- handler_data = (void *)g_parser;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test the parsing of an empty string */
-START_TEST(test_empty_parse) {
- const char *text = "<doc></doc>";
- const char *partial = "<doc>";
-
- if (XML_Parse(g_parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR)
- fail("Parsing empty string faulted");
- if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
- fail("Parsing final empty string not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_ELEMENTS)
- fail("Parsing final empty string faulted for wrong reason");
-
- /* Now try with valid text before the empty end */
- XML_ParserReset(g_parser, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (XML_Parse(g_parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR)
- fail("Parsing final empty string faulted");
-
- /* Now try with invalid text before the empty end */
- XML_ParserReset(g_parser, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, partial, (int)strlen(partial),
- XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
- fail("Parsing final incomplete empty string not faulted");
-}
-END_TEST
-
-/* Test odd corners of the XML_GetBuffer interface */
-static enum XML_Status
-get_feature(enum XML_FeatureEnum feature_id, long *presult) {
- const XML_Feature *feature = XML_GetFeatureList();
-
- if (feature == NULL)
- return XML_STATUS_ERROR;
- for (; feature->feature != XML_FEATURE_END; feature++) {
- if (feature->feature == feature_id) {
- *presult = feature->value;
- return XML_STATUS_OK;
- }
- }
- return XML_STATUS_ERROR;
-}
-
-/* Having an element name longer than 1024 characters exercises some
- * of the pool allocation code in the parser that otherwise does not
- * get executed. The count at the end of the line is the number of
- * characters (bytes) in the element name by that point.x
- */
-static const char *get_buffer_test_text
- = "<documentwitharidiculouslylongelementnametotease" /* 0x030 */
- "aparticularcorneroftheallocationinXML_GetBuffers" /* 0x060 */
- "othatwecanimprovethecoverageyetagain012345678901" /* 0x090 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0c0 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0f0 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x120 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x150 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x180 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1b0 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1e0 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x210 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x240 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x270 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2a0 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2d0 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x300 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x330 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x360 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x390 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3c0 */
- "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3f0 */
- "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */
-
-/* Test odd corners of the XML_GetBuffer interface */
-START_TEST(test_get_buffer_1) {
- const char *text = get_buffer_test_text;
- void *buffer;
- long context_bytes;
-
- /* Attempt to allocate a negative length buffer */
- if (XML_GetBuffer(g_parser, -12) != NULL)
- fail("Negative length buffer not failed");
-
- /* Now get a small buffer and extend it past valid length */
- buffer = XML_GetBuffer(g_parser, 1536);
- if (buffer == NULL)
- fail("1.5K buffer failed");
- assert(buffer != NULL);
- memcpy(buffer, text, strlen(text));
- if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (XML_GetBuffer(g_parser, INT_MAX) != NULL)
- fail("INT_MAX buffer not failed");
-
- /* Now try extending it a more reasonable but still too large
- * amount. The allocator in XML_GetBuffer() doubles the buffer
- * size until it exceeds the requested amount or INT_MAX. If it
- * exceeds INT_MAX, it rejects the request, so we want a request
- * between INT_MAX and INT_MAX/2. A gap of 1K seems comfortable,
- * with an extra byte just to ensure that the request is off any
- * boundary. The request will be inflated internally by
- * XML_CONTEXT_BYTES (if defined), so we subtract that from our
- * request.
- */
- if (get_feature(XML_FEATURE_CONTEXT_BYTES, &context_bytes) != XML_STATUS_OK)
- context_bytes = 0;
- if (XML_GetBuffer(g_parser, INT_MAX - (context_bytes + 1025)) != NULL)
- fail("INT_MAX- buffer not failed");
-
- /* Now try extending it a carefully crafted amount */
- if (XML_GetBuffer(g_parser, 1000) == NULL)
- fail("1000 buffer failed");
-}
-END_TEST
-
-/* Test more corners of the XML_GetBuffer interface */
-START_TEST(test_get_buffer_2) {
- const char *text = get_buffer_test_text;
- void *buffer;
-
- /* Now get a decent buffer */
- buffer = XML_GetBuffer(g_parser, 1536);
- if (buffer == NULL)
- fail("1.5K buffer failed");
- assert(buffer != NULL);
- memcpy(buffer, text, strlen(text));
- if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-
- /* Extend it, to catch a different code path */
- if (XML_GetBuffer(g_parser, 1024) == NULL)
- fail("1024 buffer failed");
-}
-END_TEST
-
-/* Test position information macros */
-START_TEST(test_byte_info_at_end) {
- const char *text = "<doc></doc>";
-
- if (XML_GetCurrentByteIndex(g_parser) != -1
- || XML_GetCurrentByteCount(g_parser) != 0)
- fail("Byte index/count incorrect at start of parse");
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- /* At end, the count will be zero and the index the end of string */
- if (XML_GetCurrentByteCount(g_parser) != 0)
- fail("Terminal byte count incorrect");
- if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text))
- fail("Terminal byte index incorrect");
-}
-END_TEST
-
-/* Test position information from errors */
-#define PRE_ERROR_STR "<doc></"
-#define POST_ERROR_STR "wombat></doc>"
-START_TEST(test_byte_info_at_error) {
- const char *text = PRE_ERROR_STR POST_ERROR_STR;
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- fail("Syntax error not faulted");
- if (XML_GetCurrentByteCount(g_parser) != 0)
- fail("Error byte count incorrect");
- if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR))
- fail("Error byte index incorrect");
-}
-END_TEST
-#undef PRE_ERROR_STR
-#undef POST_ERROR_STR
-
-/* Test position information in handler */
-typedef struct ByteTestData {
- int start_element_len;
- int cdata_len;
- int total_string_len;
-} ByteTestData;
-
-static void
-byte_character_handler(void *userData, const XML_Char *s, int len) {
-#ifdef XML_CONTEXT_BYTES
- int offset, size;
- const char *buffer;
- ByteTestData *data = (ByteTestData *)userData;
-
- UNUSED_P(s);
- buffer = XML_GetInputContext(g_parser, &offset, &size);
- if (buffer == NULL)
- fail("Failed to get context buffer");
- if (offset != data->start_element_len)
- fail("Context offset in unexpected position");
- if (len != data->cdata_len)
- fail("CDATA length reported incorrectly");
- if (size != data->total_string_len)
- fail("Context size is not full buffer");
- if (XML_GetCurrentByteIndex(g_parser) != offset)
- fail("Character byte index incorrect");
- if (XML_GetCurrentByteCount(g_parser) != len)
- fail("Character byte count incorrect");
-#else
- UNUSED_P(s);
- UNUSED_P(userData);
- UNUSED_P(len);
-#endif
-}
-
-#define START_ELEMENT "<e>"
-#define CDATA_TEXT "Hello"
-#define END_ELEMENT "</e>"
-START_TEST(test_byte_info_at_cdata) {
- const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT;
- int offset, size;
- ByteTestData data;
-
- /* Check initial context is empty */
- if (XML_GetInputContext(g_parser, &offset, &size) != NULL)
- fail("Unexpected context at start of parse");
-
- data.start_element_len = (int)strlen(START_ELEMENT);
- data.cdata_len = (int)strlen(CDATA_TEXT);
- data.total_string_len = (int)strlen(text);
- XML_SetCharacterDataHandler(g_parser, byte_character_handler);
- XML_SetUserData(g_parser, &data);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
- xml_failure(g_parser);
-}
-END_TEST
-#undef START_ELEMENT
-#undef CDATA_TEXT
-#undef END_ELEMENT
-
-/* Test predefined entities are correctly recognised */
-START_TEST(test_predefined_entities) {
- const char *text = "<doc>&lt;&gt;&amp;&quot;&apos;</doc>";
- const XML_Char *expected = XCS("<doc>&lt;&gt;&amp;&quot;&apos;</doc>");
- const XML_Char *result = XCS("<>&\"'");
- CharData storage;
-
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- /* run_character_check uses XML_SetCharacterDataHandler(), which
- * unfortunately heads off a code path that we need to exercise.
- */
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- /* The default handler doesn't translate the entities */
- CharData_CheckXMLChars(&storage, expected);
-
- /* Now try again and check the translation */
- XML_ParserReset(g_parser, NULL);
- run_character_check(text, result);
-}
-END_TEST
-
-/* Regression test that an invalid tag in an external parameter
- * reference in an external DTD is correctly faulted.
- *
- * Only a few specific tags are legal in DTDs ignoring comments and
- * processing instructions, all of which begin with an exclamation
- * mark. "<el/>" is not one of them, so the parser should raise an
- * error on encountering it.
- */
-static int XMLCALL
-external_entity_param(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text1 = "<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
- "<!ENTITY % e2 '%e1;'>\n"
- "%e1;\n";
- const char *text2 = "<!ELEMENT el EMPTY>\n"
- "<el/>\n";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(publicId);
- if (systemId == NULL)
- return XML_STATUS_OK;
-
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
-
- if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Inner DTD with invalid tag not rejected");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
- xml_failure(ext_parser);
- } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Invalid tag in external param not rejected");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_SYNTAX)
- xml_failure(ext_parser);
- } else {
- fail("Unknown system ID");
- }
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_ERROR;
-}
-
-START_TEST(test_invalid_tag_in_dtd) {
- const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
- "<doc></doc>\n";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_param);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Invalid tag IN DTD external param not rejected");
-}
-END_TEST
-
-/* Test entities not quite the predefined ones are not mis-recognised */
-START_TEST(test_not_predefined_entities) {
- const char *text[] = {"<doc>&pt;</doc>", "<doc>&amo;</doc>",
- "<doc>&quid;</doc>", "<doc>&apod;</doc>", NULL};
- int i = 0;
-
- while (text[i] != NULL) {
- expect_failure(text[i], XML_ERROR_UNDEFINED_ENTITY,
- "Undefined entity not rejected");
- XML_ParserReset(g_parser, NULL);
- i++;
- }
-}
-END_TEST
-
-/* Test conditional inclusion (IGNORE) */
-static int XMLCALL
-external_entity_load_ignore(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(parser);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ignore_section) {
- const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc><e>&entity;</e></doc>";
- const XML_Char *expected
- = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&entity;");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &storage);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore);
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
- XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetStartElementHandler(g_parser, dummy_start_element);
- XML_SetEndElementHandler(g_parser, dummy_end_element);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-static int XMLCALL
-external_entity_load_ignore_utf16(XML_Parser parser, const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId) {
- const char text[] =
- /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
- "<\0!\0[\0I\0G\0N\0O\0R\0E\0[\0"
- "<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 \0"
- "(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>\0";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(parser);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ignore_section_utf16) {
- const char text[] =
- /* <!DOCTYPE d SYSTEM 's'> */
- "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
- "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n\0"
- /* <d><e>&en;</e></d> */
- "<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>\0";
- const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &storage);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore_utf16);
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
- XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetStartElementHandler(g_parser, dummy_start_element);
- XML_SetEndElementHandler(g_parser, dummy_end_element);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-static int XMLCALL
-external_entity_load_ignore_utf16_be(XML_Parser parser, const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId) {
- const char text[] =
- /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
- "\0<\0!\0[\0I\0G\0N\0O\0R\0E\0["
- "\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 "
- "\0(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(parser);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ignore_section_utf16_be) {
- const char text[] =
- /* <!DOCTYPE d SYSTEM 's'> */
- "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
- "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n"
- /* <d><e>&en;</e></d> */
- "\0<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>";
- const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &storage);
- XML_SetExternalEntityRefHandler(g_parser,
- external_entity_load_ignore_utf16_be);
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
- XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetStartElementHandler(g_parser, dummy_start_element);
- XML_SetEndElementHandler(g_parser, dummy_end_element);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test mis-formatted conditional exclusion */
-START_TEST(test_bad_ignore_section) {
- const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc><e>&entity;</e></doc>";
- ExtFaults faults[]
- = {{"<![IGNORE[<!ELEM", "Broken-off declaration not faulted", NULL,
- XML_ERROR_SYNTAX},
- {"<![IGNORE[\x01]]>", "Invalid XML character not faulted", NULL,
- XML_ERROR_INVALID_TOKEN},
- {/* FIrst two bytes of a three-byte char */
- "<![IGNORE[\xe2\x82", "Partial XML character not faulted", NULL,
- XML_ERROR_PARTIAL_CHAR},
- {NULL, NULL, NULL, XML_ERROR_NONE}};
- ExtFaults *fault;
-
- for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- XML_SetUserData(g_parser, fault);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Incomplete IGNORE section not failed");
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-/* Test recursive parsing */
-static int XMLCALL
-external_entity_valuer(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text1 = "<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
- "<!ENTITY % e2 '%e1;'>\n"
- "%e1;\n";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(publicId);
- if (systemId == NULL)
- return XML_STATUS_OK;
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(ext_parser);
- } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
- ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
- enum XML_Status status;
- enum XML_Error error;
-
- status = _XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
- (int)strlen(fault->parse_text), XML_TRUE);
- if (fault->error == XML_ERROR_NONE) {
- if (status == XML_STATUS_ERROR)
- xml_failure(ext_parser);
- } else {
- if (status != XML_STATUS_ERROR)
- fail(fault->fail_text);
- error = XML_GetErrorCode(ext_parser);
- if (error != fault->error
- && (fault->error != XML_ERROR_XML_DECL
- || error != XML_ERROR_TEXT_DECL))
- xml_failure(ext_parser);
- }
- }
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_external_entity_values) {
- const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
- "<doc></doc>\n";
- ExtFaults data_004_2[] = {
- {"<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, XML_ERROR_NONE},
- {"<!ATTLIST $doc a1 CDATA 'value'>", "Invalid token not faulted", NULL,
- XML_ERROR_INVALID_TOKEN},
- {"'wombat", "Unterminated string not faulted", NULL,
- XML_ERROR_UNCLOSED_TOKEN},
- {"\xe2\x82", "Partial UTF-8 character not faulted", NULL,
- XML_ERROR_PARTIAL_CHAR},
- {"<?xml version='1.0' encoding='utf-8'?>\n", NULL, NULL, XML_ERROR_NONE},
- {"<?xml?>", "Malformed XML declaration not faulted", NULL,
- XML_ERROR_XML_DECL},
- {/* UTF-8 BOM */
- "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL,
- XML_ERROR_NONE},
- {"<?xml version='1.0' encoding='utf-8'?>\n$",
- "Invalid token after text declaration not faulted", NULL,
- XML_ERROR_INVALID_TOKEN},
- {"<?xml version='1.0' encoding='utf-8'?>\n'wombat",
- "Unterminated string after text decl not faulted", NULL,
- XML_ERROR_UNCLOSED_TOKEN},
- {"<?xml version='1.0' encoding='utf-8'?>\n\xe2\x82",
- "Partial UTF-8 character after text decl not faulted", NULL,
- XML_ERROR_PARTIAL_CHAR},
- {"%e1;", "Recursive parameter entity not faulted", NULL,
- XML_ERROR_RECURSIVE_ENTITY_REF},
- {NULL, NULL, NULL, XML_ERROR_NONE}};
- int i;
-
- for (i = 0; data_004_2[i].parse_text != NULL; i++) {
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_valuer);
- XML_SetUserData(g_parser, &data_004_2[i]);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- XML_ParserReset(g_parser, NULL);
- }
-}
-END_TEST
-
-/* Test the recursive parse interacts with a not standalone handler */
-static int XMLCALL
-external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text1 = "<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % e1 SYSTEM 'bar'>\n"
- "%e1;\n";
- const char *text2 = "<!ATTLIST doc a1 CDATA 'value'>";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(publicId);
- if (systemId == NULL)
- return XML_STATUS_OK;
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("foo"))) {
- XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Expected not standalone rejection");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_NOT_STANDALONE)
- xml_failure(ext_parser);
- XML_SetNotStandaloneHandler(ext_parser, NULL);
- XML_ParserFree(ext_parser);
- return XML_STATUS_ERROR;
- } else if (! xcstrcmp(systemId, XCS("bar"))) {
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(ext_parser);
- }
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ext_entity_not_standalone) {
- const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc></doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_not_standalone);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Standalone rejection not caught");
-}
-END_TEST
-
-static int XMLCALL
-external_entity_value_aborter(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text1 = "<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
- "<!ENTITY % e2 '%e1;'>\n"
- "%e1;\n";
- const char *text2 = "<?xml version='1.0' encoding='utf-8'?>";
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(publicId);
- if (systemId == NULL)
- return XML_STATUS_OK;
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(ext_parser);
- }
- if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
- XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
- XML_SetUserData(ext_parser, ext_parser);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Aborted parse not faulted");
- if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
- xml_failure(ext_parser);
- }
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_ext_entity_value_abort) {
- const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
- "<doc></doc>\n";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_value_aborter);
- resumable = XML_FALSE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_bad_public_doctype) {
- const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<!DOCTYPE doc PUBLIC '{BadName}' 'test'>\n"
- "<doc></doc>";
-
- /* Setting a handler provokes a particular code path */
- XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
- dummy_end_doctype_handler);
- expect_failure(text, XML_ERROR_PUBLICID, "Bad Public ID not failed");
-}
-END_TEST
-
-/* Test based on ibm/valid/P32/ibm32v04.xml */
-START_TEST(test_attribute_enum_value) {
- const char *text = "<?xml version='1.0' standalone='no'?>\n"
- "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
- "<animal>This is a \n <a/> \n\nyellow tiger</animal>";
- ExtTest dtd_data
- = {"<!ELEMENT animal (#PCDATA|a)*>\n"
- "<!ELEMENT a EMPTY>\n"
- "<!ATTLIST animal xml:space (default|preserve) 'preserve'>",
- NULL, NULL};
- const XML_Char *expected = XCS("This is a \n \n\nyellow tiger");
-
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- XML_SetUserData(g_parser, &dtd_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- /* An attribute list handler provokes a different code path */
- XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
- run_ext_character_check(text, &dtd_data, expected);
-}
-END_TEST
-
-/* Slightly bizarrely, the library seems to silently ignore entity
- * definitions for predefined entities, even when they are wrong. The
- * language of the XML 1.0 spec is somewhat unhelpful as to what ought
- * to happen, so this is currently treated as acceptable.
- */
-START_TEST(test_predefined_entity_redefinition) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ENTITY apos 'foo'>\n"
- "]>\n"
- "<doc>&apos;</doc>";
- run_character_check(text, XCS("'"));
-}
-END_TEST
-
-/* Test that the parser stops processing the DTD after an unresolved
- * parameter entity is encountered.
- */
-START_TEST(test_dtd_stop_processing) {
- const char *text = "<!DOCTYPE doc [\n"
- "%foo;\n"
- "<!ENTITY bar 'bas'>\n"
- "]><doc/>";
-
- XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (dummy_handler_flags != 0)
- fail("DTD processing still going after undefined PE");
-}
-END_TEST
-
-/* Test public notations with no system ID */
-START_TEST(test_public_notation_no_sysid) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!NOTATION note PUBLIC 'foo'>\n"
- "<!ELEMENT doc EMPTY>\n"
- "]>\n<doc/>";
-
- dummy_handler_flags = 0;
- XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
- fail("Notation declaration handler not called");
-}
-END_TEST
-
-static void XMLCALL
-record_element_start_handler(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- UNUSED_P(atts);
- CharData_AppendXMLChars((CharData *)userData, name, (int)xcstrlen(name));
-}
-
-START_TEST(test_nested_groups) {
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc "
- /* Sixteen elements per line */
- "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
- "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
- "))))))))))))))))))))))))))))))))>\n"
- "<!ELEMENT e EMPTY>"
- "]>\n"
- "<doc><e/></doc>";
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetStartElementHandler(g_parser, record_element_start_handler);
- XML_SetUserData(g_parser, &storage);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, XCS("doce"));
- if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
- fail("Element handler not fired");
-}
-END_TEST
-
-START_TEST(test_group_choice) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc (a|b|c)+>\n"
- "<!ELEMENT a EMPTY>\n"
- "<!ELEMENT b (#PCDATA)>\n"
- "<!ELEMENT c ANY>\n"
- "]>\n"
- "<doc>\n"
- "<a/>\n"
- "<b attr='foo'>This is a foo</b>\n"
- "<c></c>\n"
- "</doc>\n";
-
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
- fail("Element handler flag not raised");
-}
-END_TEST
-
-static int XMLCALL
-external_entity_public(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text1 = (const char *)XML_GetUserData(parser);
- const char *text2 = "<!ATTLIST doc a CDATA 'value'>";
- const char *text = NULL;
- XML_Parser ext_parser;
- int parse_res;
-
- UNUSED_P(base);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- return XML_STATUS_ERROR;
- if (systemId != NULL && ! xcstrcmp(systemId, XCS("http://example.org/"))) {
- text = text1;
- } else if (publicId != NULL && ! xcstrcmp(publicId, XCS("foo"))) {
- text = text2;
- } else
- fail("Unexpected parameters to external entity parser");
- assert(text != NULL);
- parse_res
- = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
- XML_ParserFree(ext_parser);
- return parse_res;
-}
-
-START_TEST(test_standalone_parameter_entity) {
- const char *text = "<?xml version='1.0' standalone='yes'?>\n"
- "<!DOCTYPE doc SYSTEM 'http://example.org/' [\n"
- "<!ENTITY % entity '<!ELEMENT doc (#PCDATA)>'>\n"
- "%entity;\n"
- "]>\n"
- "<doc></doc>";
- char dtd_data[] = "<!ENTITY % e1 'foo'>\n";
-
- XML_SetUserData(g_parser, dtd_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test skipping of parameter entity in an external DTD */
-/* Derived from ibm/invalid/P69/ibm69i01.xml */
-START_TEST(test_skipped_parameter_entity) {
- const char *text = "<?xml version='1.0'?>\n"
- "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
- "<!ELEMENT root (#PCDATA|a)* >\n"
- "]>\n"
- "<root></root>";
- ExtTest dtd_data = {"%pe2;", NULL, NULL};
-
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- XML_SetUserData(g_parser, &dtd_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetSkippedEntityHandler(g_parser, dummy_skip_handler);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (dummy_handler_flags != DUMMY_SKIP_HANDLER_FLAG)
- fail("Skip handler not executed");
-}
-END_TEST
-
-/* Test recursive parameter entity definition rejected in external DTD */
-START_TEST(test_recursive_external_parameter_entity) {
- const char *text = "<?xml version='1.0'?>\n"
- "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
- "<!ELEMENT root (#PCDATA|a)* >\n"
- "]>\n"
- "<root></root>";
- ExtFaults dtd_data = {"<!ENTITY % pe2 '&#37;pe2;'>\n%pe2;",
- "Recursive external parameter entity not faulted", NULL,
- XML_ERROR_RECURSIVE_ENTITY_REF};
-
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- XML_SetUserData(g_parser, &dtd_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Recursive external parameter not spotted");
-}
-END_TEST
-
-/* Test undefined parameter entity in external entity handler */
-static int XMLCALL
-external_entity_devaluer(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = "<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % e1 SYSTEM 'bar'>\n"
- "%e1;\n";
- XML_Parser ext_parser;
- intptr_t clear_handler = (intptr_t)XML_GetUserData(parser);
-
- UNUSED_P(base);
- UNUSED_P(publicId);
- if (systemId == NULL || ! xcstrcmp(systemId, XCS("bar")))
- return XML_STATUS_OK;
- if (xcstrcmp(systemId, XCS("foo")))
- fail("Unexpected system ID");
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could note create external entity parser");
- if (clear_handler)
- XML_SetExternalEntityRefHandler(ext_parser, NULL);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(ext_parser);
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_undefined_ext_entity_in_external_dtd) {
- const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc></doc>\n";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
- XML_SetUserData(g_parser, (void *)(intptr_t)XML_FALSE);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-
- /* Now repeat without the external entity ref handler invoking
- * another copy of itself.
- */
- XML_ParserReset(g_parser, NULL);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
- XML_SetUserData(g_parser, (void *)(intptr_t)XML_TRUE);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-static void XMLCALL
-aborting_xdecl_handler(void *userData, const XML_Char *version,
- const XML_Char *encoding, int standalone) {
- UNUSED_P(userData);
- UNUSED_P(version);
- UNUSED_P(encoding);
- UNUSED_P(standalone);
- XML_StopParser(g_parser, resumable);
- XML_SetXmlDeclHandler(g_parser, NULL);
-}
-
-/* Test suspending the parse on receiving an XML declaration works */
-START_TEST(test_suspend_xdecl) {
- const char *text = long_character_data_text;
-
- XML_SetXmlDeclHandler(g_parser, aborting_xdecl_handler);
- resumable = XML_TRUE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
- if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
- xml_failure(g_parser);
- /* Attempt to start a new parse while suspended */
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Attempt to parse while suspended not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
- fail("Suspended parse not faulted with correct error");
-}
-END_TEST
-
-/* Test aborting the parse in an epilog works */
-static void XMLCALL
-selective_aborting_default_handler(void *userData, const XML_Char *s, int len) {
- const XML_Char *match = (const XML_Char *)userData;
-
- if (match == NULL
- || (xcstrlen(match) == (unsigned)len && ! xcstrncmp(match, s, len))) {
- XML_StopParser(g_parser, resumable);
- XML_SetDefaultHandler(g_parser, NULL);
- }
-}
-
-START_TEST(test_abort_epilog) {
- const char *text = "<doc></doc>\n\r\n";
- XML_Char match[] = XCS("\r");
-
- XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
- XML_SetUserData(g_parser, match);
- resumable = XML_FALSE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Abort not triggered");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test a different code path for abort in the epilog */
-START_TEST(test_abort_epilog_2) {
- const char *text = "<doc></doc>\n";
- XML_Char match[] = XCS("\n");
-
- XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
- XML_SetUserData(g_parser, match);
- resumable = XML_FALSE;
- expect_failure(text, XML_ERROR_ABORTED, "Abort not triggered");
-}
-END_TEST
-
-/* Test suspension from the epilog */
-START_TEST(test_suspend_epilog) {
- const char *text = "<doc></doc>\n";
- XML_Char match[] = XCS("\n");
-
- XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
- XML_SetUserData(g_parser, match);
- resumable = XML_TRUE;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
-}
-END_TEST
-
-static void XMLCALL
-suspending_end_handler(void *userData, const XML_Char *s) {
- UNUSED_P(s);
- XML_StopParser((XML_Parser)userData, 1);
-}
-
-START_TEST(test_suspend_in_sole_empty_tag) {
- const char *text = "<doc/>";
- enum XML_Status rc;
-
- XML_SetEndElementHandler(g_parser, suspending_end_handler);
- XML_SetUserData(g_parser, g_parser);
- rc = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
- if (rc == XML_STATUS_ERROR)
- xml_failure(g_parser);
- else if (rc != XML_STATUS_SUSPENDED)
- fail("Suspend not triggered");
- rc = XML_ResumeParser(g_parser);
- if (rc == XML_STATUS_ERROR)
- xml_failure(g_parser);
- else if (rc != XML_STATUS_OK)
- fail("Resume failed");
-}
-END_TEST
-
-START_TEST(test_unfinished_epilog) {
- const char *text = "<doc></doc><";
-
- expect_failure(text, XML_ERROR_UNCLOSED_TOKEN,
- "Incomplete epilog entry not faulted");
-}
-END_TEST
-
-START_TEST(test_partial_char_in_epilog) {
- const char *text = "<doc></doc>\xe2\x82";
-
- /* First check that no fault is raised if the parse is not finished */
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- /* Now check that it is faulted once we finish */
- if (XML_ParseBuffer(g_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
- fail("Partial character in epilog not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_PARTIAL_CHAR)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_hash_collision) {
- /* For full coverage of the lookup routine, we need to ensure a
- * hash collision even though we can only tell that we have one
- * through breakpoint debugging or coverage statistics. The
- * following will cause a hash collision on machines with a 64-bit
- * long type; others will have to experiment. The full coverage
- * tests invoked from qa.sh usually provide a hash collision, but
- * not always. This is an attempt to provide insurance.
- */
-#define COLLIDING_HASH_SALT (unsigned long)_SIP_ULL(0xffffffffU, 0xff99fc90U)
- const char *text
- = "<doc>\n"
- "<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n"
- "<b1></b1><b2 attr='foo'>This is a foo</b2><b3></b3><b4></b4>\n"
- "<b5></b5><b6></b6><b7></b7><b8></b8>\n"
- "<c1/><c2/><c3/><c4/><c5/><c6/><c7/><c8/>\n"
- "<d1/><d2/><d3/><d4/><d5/><d6/><d7/>\n"
- "<d8>This triggers the table growth and collides with b2</d8>\n"
- "</doc>\n";
-
- XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-#undef COLLIDING_HASH_SALT
-
-/* Test resuming a parse suspended in entity substitution */
-static void XMLCALL
-start_element_suspender(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- UNUSED_P(userData);
- UNUSED_P(atts);
- if (! xcstrcmp(name, XCS("suspend")))
- XML_StopParser(g_parser, XML_TRUE);
- if (! xcstrcmp(name, XCS("abort")))
- XML_StopParser(g_parser, XML_FALSE);
-}
-
-START_TEST(test_suspend_resume_internal_entity) {
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!ENTITY foo '<suspend>Hi<suspend>Ho</suspend></suspend>'>\n"
- "]>\n"
- "<doc>&foo;</doc>\n";
- const XML_Char *expected1 = XCS("Hi");
- const XML_Char *expected2 = XCS("HiHo");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetStartElementHandler(g_parser, start_element_suspender);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- XML_SetUserData(g_parser, &storage);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, XCS(""));
- if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected1);
- if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected2);
-}
-END_TEST
-
-/* Test syntax error is caught at parse resumption */
-START_TEST(test_resume_entity_with_syntax_error) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ENTITY foo '<suspend>Hi</wombat>'>\n"
- "]>\n"
- "<doc>&foo;</doc>\n";
-
- XML_SetStartElementHandler(g_parser, start_element_suspender);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
- if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
- fail("Syntax error in entity not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_TAG_MISMATCH)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test suspending and resuming in a parameter entity substitution */
-static void XMLCALL
-element_decl_suspender(void *userData, const XML_Char *name,
- XML_Content *model) {
- UNUSED_P(userData);
- UNUSED_P(name);
- XML_StopParser(g_parser, XML_TRUE);
- XML_FreeContentModel(g_parser, model);
-}
-
-START_TEST(test_suspend_resume_parameter_entity) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ENTITY % foo '<!ELEMENT doc (#PCDATA)*>'>\n"
- "%foo;\n"
- "]>\n"
- "<doc>Hello, world</doc>";
- const XML_Char *expected = XCS("Hello, world");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetElementDeclHandler(g_parser, element_decl_suspender);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- XML_SetUserData(g_parser, &storage);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, XCS(""));
- if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test attempting to use parser after an error is faulted */
-START_TEST(test_restart_on_error) {
- const char *text = "<$doc><doc></doc>";
-
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Invalid tag name not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
- xml_failure(g_parser);
- if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
- fail("Restarting invalid parse not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test that angle brackets in an attribute default value are faulted */
-START_TEST(test_reject_lt_in_attribute_value) {
- const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '<bar>'>]>\n"
- "<doc></doc>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Bad attribute default not faulted");
-}
-END_TEST
-
-START_TEST(test_reject_unfinished_param_in_att_value) {
- const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '&foo'>]>\n"
- "<doc></doc>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Bad attribute default not faulted");
-}
-END_TEST
-
-START_TEST(test_trailing_cr_in_att_value) {
- const char *text = "<doc a='value\r'/>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
+#include "common.h"
-/* Try parsing a general entity within a parameter entity in a
- * standalone internal DTD. Covers a corner case in the parser.
- */
-START_TEST(test_standalone_internal_entity) {
- const char *text = "<?xml version='1.0' standalone='yes' ?>\n"
- "<!DOCTYPE doc [\n"
- " <!ELEMENT doc (#PCDATA)>\n"
- " <!ENTITY % pe '<!ATTLIST doc att2 CDATA \"&ge;\">'>\n"
- " <!ENTITY ge 'AttDefaultValue'>\n"
- " %pe;\n"
- "]>\n"
- "<doc att2='any'/>";
+#include "basic_tests.h"
+#include "ns_tests.h"
+#include "misc_tests.h"
+#include "alloc_tests.h"
+#include "nsalloc_tests.h"
+#include "acc_tests.h"
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test that a reference to an unknown external entity is skipped */
-START_TEST(test_skipped_external_entity) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
- "<doc></doc>\n";
- ExtTest test_data = {"<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % e2 '%e1;'>\n",
- NULL, NULL};
-
- XML_SetUserData(g_parser, &test_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test a different form of unknown external entity */
-typedef struct ext_hdlr_data {
- const char *parse_text;
- XML_ExternalEntityRefHandler handler;
-} ExtHdlrData;
-
-static int XMLCALL
-external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser);
- XML_Parser ext_parser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser.");
- /* Use the requested entity parser for further externals */
- XML_SetExternalEntityRefHandler(ext_parser, test_data->handler);
- if (_XML_Parse_SINGLE_BYTES(ext_parser, test_data->parse_text,
- (int)strlen(test_data->parse_text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(ext_parser);
- }
-
- XML_ParserFree(ext_parser);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_skipped_null_loaded_ext_entity) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
- "<doc />";
- ExtHdlrData test_data
- = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
- "<!ENTITY % pe2 '%pe1;'>\n"
- "%pe2;\n",
- external_entity_null_loader};
-
- XML_SetUserData(g_parser, &test_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_skipped_unloaded_ext_entity) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
- "<doc />";
- ExtHdlrData test_data
- = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
- "<!ENTITY % pe2 '%pe1;'>\n"
- "%pe2;\n",
- NULL};
-
- XML_SetUserData(g_parser, &test_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test that a parameter entity value ending with a carriage return
- * has it translated internally into a newline.
- */
-START_TEST(test_param_entity_with_trailing_cr) {
-#define PARAM_ENTITY_NAME "pe"
-#define PARAM_ENTITY_CORE_VALUE "<!ATTLIST doc att CDATA \"default\">"
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
- "<doc/>";
- ExtTest test_data
- = {"<!ENTITY % " PARAM_ENTITY_NAME " '" PARAM_ENTITY_CORE_VALUE "\r'>\n"
- "%" PARAM_ENTITY_NAME ";\n",
- NULL, NULL};
-
- XML_SetUserData(g_parser, &test_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
- XML_SetEntityDeclHandler(g_parser, param_entity_match_handler);
- entity_name_to_match = XCS(PARAM_ENTITY_NAME);
- entity_value_to_match = XCS(PARAM_ENTITY_CORE_VALUE) XCS("\n");
- entity_match_flag = ENTITY_MATCH_NOT_FOUND;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (entity_match_flag == ENTITY_MATCH_FAIL)
- fail("Parameter entity CR->NEWLINE conversion failed");
- else if (entity_match_flag == ENTITY_MATCH_NOT_FOUND)
- fail("Parameter entity not parsed");
-}
-#undef PARAM_ENTITY_NAME
-#undef PARAM_ENTITY_CORE_VALUE
-END_TEST
-
-START_TEST(test_invalid_character_entity) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY entity '&#x110000;'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
-
- expect_failure(text, XML_ERROR_BAD_CHAR_REF,
- "Out of range character reference not faulted");
-}
-END_TEST
-
-START_TEST(test_invalid_character_entity_2) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY entity '&#xg0;'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Out of range character reference not faulted");
-}
-END_TEST
-
-START_TEST(test_invalid_character_entity_3) {
- const char text[] =
- /* <!DOCTYPE doc [\n */
- "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
- /* U+0E04 = KHO KHWAI
- * U+0E08 = CHO CHAN */
- /* <!ENTITY entity '&\u0e04\u0e08;'>\n */
- "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0n\0t\0i\0t\0y\0 "
- "\0'\0&\x0e\x04\x0e\x08\0;\0'\0>\0\n"
- /* ]>\n */
- "\0]\0>\0\n"
- /* <doc>&entity;</doc> */
- "\0<\0d\0o\0c\0>\0&\0e\0n\0t\0i\0t\0y\0;\0<\0/\0d\0o\0c\0>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Invalid start of entity name not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_UNDEFINED_ENTITY)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_invalid_character_entity_4) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY entity '&#1114112;'>\n" /* = &#x110000 */
- "]>\n"
- "<doc>&entity;</doc>";
-
- expect_failure(text, XML_ERROR_BAD_CHAR_REF,
- "Out of range character reference not faulted");
-}
-END_TEST
-
-/* Test that processing instructions are picked up by a default handler */
-START_TEST(test_pi_handled_in_default) {
- const char *text = "<?test processing instruction?>\n<doc/>";
- const XML_Char *expected = XCS("<?test processing instruction?>\n<doc/>");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test that comments are picked up by a default handler */
-START_TEST(test_comment_handled_in_default) {
- const char *text = "<!-- This is a comment -->\n<doc/>";
- const XML_Char *expected = XCS("<!-- This is a comment -->\n<doc/>");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test PIs that look almost but not quite like XML declarations */
-static void XMLCALL
-accumulate_pi_characters(void *userData, const XML_Char *target,
- const XML_Char *data) {
- CharData *storage = (CharData *)userData;
-
- CharData_AppendXMLChars(storage, target, -1);
- CharData_AppendXMLChars(storage, XCS(": "), 2);
- CharData_AppendXMLChars(storage, data, -1);
- CharData_AppendXMLChars(storage, XCS("\n"), 1);
-}
-
-START_TEST(test_pi_yml) {
- const char *text = "<?yml something like data?><doc/>";
- const XML_Char *expected = XCS("yml: something like data\n");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_pi_xnl) {
- const char *text = "<?xnl nothing like data?><doc/>";
- const XML_Char *expected = XCS("xnl: nothing like data\n");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_pi_xmm) {
- const char *text = "<?xmm everything like data?><doc/>";
- const XML_Char *expected = XCS("xmm: everything like data\n");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_utf16_pi) {
- const char text[] =
- /* <?{KHO KHWAI}{CHO CHAN}?>
- * where {KHO KHWAI} = U+0E04
- * and {CHO CHAN} = U+0E08
- */
- "<\0?\0\x04\x0e\x08\x0e?\0>\0"
- /* <q/> */
- "<\0q\0/\0>\0";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x0e04\x0e08: \n");
-#else
- const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_utf16_be_pi) {
- const char text[] =
- /* <?{KHO KHWAI}{CHO CHAN}?>
- * where {KHO KHWAI} = U+0E04
- * and {CHO CHAN} = U+0E08
- */
- "\0<\0?\x0e\x04\x0e\x08\0?\0>"
- /* <q/> */
- "\0<\0q\0/\0>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x0e04\x0e08: \n");
-#else
- const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test that comments can be picked up and translated */
-static void XMLCALL
-accumulate_comment(void *userData, const XML_Char *data) {
- CharData *storage = (CharData *)userData;
-
- CharData_AppendXMLChars(storage, data, -1);
-}
-
-START_TEST(test_utf16_be_comment) {
- const char text[] =
- /* <!-- Comment A --> */
- "\0<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0A\0 \0-\0-\0>\0\n"
- /* <doc/> */
- "\0<\0d\0o\0c\0/\0>";
- const XML_Char *expected = XCS(" Comment A ");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetCommentHandler(g_parser, accumulate_comment);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_utf16_le_comment) {
- const char text[] =
- /* <!-- Comment B --> */
- "<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0B\0 \0-\0-\0>\0\n\0"
- /* <doc/> */
- "<\0d\0o\0c\0/\0>\0";
- const XML_Char *expected = XCS(" Comment B ");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetCommentHandler(g_parser, accumulate_comment);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test that the unknown encoding handler with map entries that expect
- * conversion but no conversion function is faulted
- */
-static int XMLCALL
-failing_converter(void *data, const char *s) {
- UNUSED_P(data);
- UNUSED_P(s);
- /* Always claim to have failed */
- return -1;
-}
-
-static int XMLCALL
-prefix_converter(void *data, const char *s) {
- UNUSED_P(data);
- /* If the first byte is 0xff, raise an error */
- if (s[0] == (char)-1)
- return -1;
- /* Just add the low bits of the first byte to the second */
- return (s[1] + (s[0] & 0x7f)) & 0x01ff;
-}
-
-static int XMLCALL
-MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
- int i;
- int high_map = -2; /* Assume a 2-byte sequence */
-
- if (! xcstrcmp(encoding, XCS("invalid-9"))
- || ! xcstrcmp(encoding, XCS("ascii-like"))
- || ! xcstrcmp(encoding, XCS("invalid-len"))
- || ! xcstrcmp(encoding, XCS("invalid-a"))
- || ! xcstrcmp(encoding, XCS("invalid-surrogate"))
- || ! xcstrcmp(encoding, XCS("invalid-high")))
- high_map = -1;
-
- for (i = 0; i < 128; ++i)
- info->map[i] = i;
- for (; i < 256; ++i)
- info->map[i] = high_map;
-
- /* If required, put an invalid value in the ASCII entries */
- if (! xcstrcmp(encoding, XCS("invalid-9")))
- info->map[9] = 5;
- /* If required, have a top-bit set character starts a 5-byte sequence */
- if (! xcstrcmp(encoding, XCS("invalid-len")))
- info->map[0x81] = -5;
- /* If required, make a top-bit set character a valid ASCII character */
- if (! xcstrcmp(encoding, XCS("invalid-a")))
- info->map[0x82] = 'a';
- /* If required, give a top-bit set character a forbidden value,
- * what would otherwise be the first of a surrogate pair.
- */
- if (! xcstrcmp(encoding, XCS("invalid-surrogate")))
- info->map[0x83] = 0xd801;
- /* If required, give a top-bit set character too high a value */
- if (! xcstrcmp(encoding, XCS("invalid-high")))
- info->map[0x84] = 0x010101;
-
- info->data = data;
- info->release = NULL;
- if (! xcstrcmp(encoding, XCS("failing-conv")))
- info->convert = failing_converter;
- else if (! xcstrcmp(encoding, XCS("prefix-conv")))
- info->convert = prefix_converter;
- else
- info->convert = NULL;
- return XML_STATUS_OK;
-}
-
-START_TEST(test_missing_encoding_conversion_fn) {
- const char *text = "<?xml version='1.0' encoding='no-conv'?>\n"
- "<doc>\x81</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- /* MiscEncodingHandler sets up an encoding with every top-bit-set
- * character introducing a two-byte sequence. For this, it
- * requires a convert function. The above function call doesn't
- * pass one through, so when BadEncodingHandler actually gets
- * called it should supply an invalid encoding.
- */
- expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
- "Encoding with missing convert() not faulted");
-}
-END_TEST
-
-START_TEST(test_failing_encoding_conversion_fn) {
- const char *text = "<?xml version='1.0' encoding='failing-conv'?>\n"
- "<doc>\x81</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- /* BadEncodingHandler sets up an encoding with every top-bit-set
- * character introducing a two-byte sequence. For this, it
- * requires a convert function. The above function call passes
- * one that insists all possible sequences are invalid anyway.
- */
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Encoding with failing convert() not faulted");
-}
-END_TEST
-
-/* Test unknown encoding conversions */
-START_TEST(test_unknown_encoding_success) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- /* Equivalent to <eoc>Hello, world</eoc> */
- "<\x81\x64\x80oc>Hello, world</\x81\x64\x80oc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- run_character_check(text, XCS("Hello, world"));
-}
-END_TEST
-
-/* Test bad name character in unknown encoding */
-START_TEST(test_unknown_encoding_bad_name) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- "<\xff\x64oc>Hello, world</\xff\x64oc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Bad name start in unknown encoding not faulted");
-}
-END_TEST
-
-/* Test bad mid-name character in unknown encoding */
-START_TEST(test_unknown_encoding_bad_name_2) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- "<d\xffoc>Hello, world</d\xffoc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Bad name in unknown encoding not faulted");
-}
-END_TEST
-
-/* Test element name that is long enough to fill the conversion buffer
- * in an unknown encoding, finishing with an encoded character.
- */
-START_TEST(test_unknown_encoding_long_name_1) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- "<abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>"
- "Hi"
- "</abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>";
- const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- XML_SetStartElementHandler(g_parser, record_element_start_handler);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test element name that is long enough to fill the conversion buffer
- * in an unknown encoding, finishing with an simple character.
- */
-START_TEST(test_unknown_encoding_long_name_2) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- "<abcdefghabcdefghabcdefghijklmnop>"
- "Hi"
- "</abcdefghabcdefghabcdefghijklmnop>";
- const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- XML_SetStartElementHandler(g_parser, record_element_start_handler);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_invalid_unknown_encoding) {
- const char *text = "<?xml version='1.0' encoding='invalid-9'?>\n"
- "<doc>Hello world</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
- "Invalid unknown encoding not faulted");
-}
-END_TEST
-
-START_TEST(test_unknown_ascii_encoding_ok) {
- const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
- "<doc>Hello, world</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- run_character_check(text, XCS("Hello, world"));
-}
-END_TEST
-
-START_TEST(test_unknown_ascii_encoding_fail) {
- const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
- "<doc>Hello, \x80 world</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Invalid character not faulted");
-}
-END_TEST
-
-START_TEST(test_unknown_encoding_invalid_length) {
- const char *text = "<?xml version='1.0' encoding='invalid-len'?>\n"
- "<doc>Hello, world</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
- "Invalid unknown encoding not faulted");
-}
-END_TEST
-
-START_TEST(test_unknown_encoding_invalid_topbit) {
- const char *text = "<?xml version='1.0' encoding='invalid-a'?>\n"
- "<doc>Hello, world</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
- "Invalid unknown encoding not faulted");
-}
-END_TEST
-
-START_TEST(test_unknown_encoding_invalid_surrogate) {
- const char *text = "<?xml version='1.0' encoding='invalid-surrogate'?>\n"
- "<doc>Hello, \x82 world</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Invalid unknown encoding not faulted");
-}
-END_TEST
-
-START_TEST(test_unknown_encoding_invalid_high) {
- const char *text = "<?xml version='1.0' encoding='invalid-high'?>\n"
- "<doc>Hello, world</doc>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
- "Invalid unknown encoding not faulted");
-}
-END_TEST
-
-START_TEST(test_unknown_encoding_invalid_attr_value) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- "<doc attr='\xff\x30'/>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Invalid attribute valid not faulted");
-}
-END_TEST
-
-/* Test an external entity parser set to use latin-1 detects UTF-16
- * BOMs correctly.
- */
-enum ee_parse_flags { EE_PARSE_NONE = 0x00, EE_PARSE_FULL_BUFFER = 0x01 };
-
-typedef struct ExtTest2 {
- const char *parse_text;
- int parse_len;
- const XML_Char *encoding;
- CharData *storage;
- enum ee_parse_flags flags;
-} ExtTest2;
-
-static int XMLCALL
-external_entity_loader2(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser);
- XML_Parser extparser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (extparser == NULL)
- fail("Coulr not create external entity parser");
- if (test_data->encoding != NULL) {
- if (! XML_SetEncoding(extparser, test_data->encoding))
- fail("XML_SetEncoding() ignored for external entity");
- }
- if (test_data->flags & EE_PARSE_FULL_BUFFER) {
- if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
- XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(extparser);
- }
- } else if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
- test_data->parse_len, XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(extparser);
- }
-
- XML_ParserFree(extparser);
- return XML_STATUS_OK;
-}
-
-/* Test that UTF-16 BOM does not select UTF-16 given explicit encoding */
-static void XMLCALL
-ext2_accumulate_characters(void *userData, const XML_Char *s, int len) {
- ExtTest2 *test_data = (ExtTest2 *)userData;
- accumulate_characters(test_data->storage, s, len);
-}
-
-START_TEST(test_ext_entity_latin1_utf16le_bom) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest2 test_data
- = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
- /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
- * 0x4c = L and 0x20 is a space
- */
- "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00ff\x00feL ");
-#else
- /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
- const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_ext_entity_latin1_utf16be_bom) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest2 test_data
- = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
- /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
- * 0x4c = L and 0x20 is a space
- */
- "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00fe\x00ff L");
-#else
- /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
- const XML_Char *expected = XCS("\xc3\xbe\xc3\xbf L");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Parsing the full buffer rather than a byte at a time makes a
- * difference to the encoding scanning code, so repeat the above tests
- * without breaking them down by byte.
- */
-START_TEST(test_ext_entity_latin1_utf16le_bom2) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest2 test_data
- = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
- /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
- * 0x4c = L and 0x20 is a space
- */
- "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00ff\x00feL ");
-#else
- /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
- const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_ext_entity_latin1_utf16be_bom2) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest2 test_data
- = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
- /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
- * 0x4c = L and 0x20 is a space
- */
- "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00fe\x00ff L");
-#else
- /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
- const XML_Char *expected = "\xc3\xbe\xc3\xbf L";
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test little-endian UTF-16 given an explicit big-endian encoding */
-START_TEST(test_ext_entity_utf16_be) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest2 test_data
- = {"<\0e\0/\0>\0", 8, XCS("utf-16be"), NULL, EE_PARSE_NONE};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
-#else
- const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
- "\xe6\x94\x80" /* U+6500 */
- "\xe2\xbc\x80" /* U+2F00 */
- "\xe3\xb8\x80"); /* U+3E00 */
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test big-endian UTF-16 given an explicit little-endian encoding */
-START_TEST(test_ext_entity_utf16_le) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest2 test_data
- = {"\0<\0e\0/\0>", 8, XCS("utf-16le"), NULL, EE_PARSE_NONE};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
-#else
- const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
- "\xe6\x94\x80" /* U+6500 */
- "\xe2\xbc\x80" /* U+2F00 */
- "\xe3\xb8\x80"); /* U+3E00 */
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test little-endian UTF-16 given no explicit encoding.
- * The existing default encoding (UTF-8) is assumed to hold without a
- * BOM to contradict it, so the entity value will in fact provoke an
- * error because 0x00 is not a valid XML character. We parse the
- * whole buffer in one go rather than feeding it in byte by byte to
- * exercise different code paths in the initial scanning routines.
- */
-typedef struct ExtFaults2 {
- const char *parse_text;
- int parse_len;
- const char *fail_text;
- const XML_Char *encoding;
- enum XML_Error error;
-} ExtFaults2;
-
-static int XMLCALL
-external_entity_faulter2(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser);
- XML_Parser extparser;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (extparser == NULL)
- fail("Could not create external entity parser");
- if (test_data->encoding != NULL) {
- if (! XML_SetEncoding(extparser, test_data->encoding))
- fail("XML_SetEncoding() ignored for external entity");
- }
- if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
- XML_TRUE)
- != XML_STATUS_ERROR)
- fail(test_data->fail_text);
- if (XML_GetErrorCode(extparser) != test_data->error)
- xml_failure(extparser);
-
- XML_ParserFree(extparser);
- return XML_STATUS_ERROR;
-}
-
-START_TEST(test_ext_entity_utf16_unknown) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtFaults2 test_data
- = {"a\0b\0c\0", 6, "Invalid character in entity not faulted", NULL,
- XML_ERROR_INVALID_TOKEN};
-
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter2);
- XML_SetUserData(g_parser, &test_data);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Invalid character should not have been accepted");
-}
-END_TEST
-
-/* Test not-quite-UTF-8 BOM (0xEF 0xBB 0xBF) */
-START_TEST(test_ext_entity_utf8_non_bom) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtTest2 test_data
- = {"\xef\xbb\x80", /* Arabic letter DAD medial form, U+FEC0 */
- 3, NULL, NULL, EE_PARSE_NONE};
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\xfec0");
-#else
- const XML_Char *expected = XCS("\xef\xbb\x80");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test that UTF-8 in a CDATA section is correctly passed through */
-START_TEST(test_utf8_in_cdata_section) {
- const char *text = "<doc><![CDATA[one \xc3\xa9 two]]></doc>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("one \x00e9 two");
-#else
- const XML_Char *expected = XCS("one \xc3\xa9 two");
-#endif
-
- run_character_check(text, expected);
-}
-END_TEST
-
-/* Test that little-endian UTF-16 in a CDATA section is handled */
-START_TEST(test_utf8_in_cdata_section_2) {
- const char *text = "<doc><![CDATA[\xc3\xa9]\xc3\xa9two]]></doc>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e9]\x00e9two");
-#else
- const XML_Char *expected = XCS("\xc3\xa9]\xc3\xa9two");
-#endif
-
- run_character_check(text, expected);
-}
-END_TEST
-
-/* Test trailing spaces in elements are accepted */
-static void XMLCALL
-record_element_end_handler(void *userData, const XML_Char *name) {
- CharData *storage = (CharData *)userData;
-
- CharData_AppendXMLChars(storage, XCS("/"), 1);
- CharData_AppendXMLChars(storage, name, -1);
-}
-
-START_TEST(test_trailing_spaces_in_elements) {
- const char *text = "<doc >Hi</doc >";
- const XML_Char *expected = XCS("doc/doc");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetElementHandler(g_parser, record_element_start_handler,
- record_element_end_handler);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_utf16_attribute) {
- const char text[] =
- /* <d {KHO KHWAI}{CHO CHAN}='a'/>
- * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
- * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
- */
- "<\0d\0 \0\x04\x0e\x08\x0e=\0'\0a\0'\0/\0>\0";
- const XML_Char *expected = XCS("a");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetStartElementHandler(g_parser, accumulate_attribute);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_utf16_second_attr) {
- /* <d a='1' {KHO KHWAI}{CHO CHAN}='2'/>
- * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
- * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
- */
- const char text[] = "<\0d\0 \0a\0=\0'\0\x31\0'\0 \0"
- "\x04\x0e\x08\x0e=\0'\0\x32\0'\0/\0>\0";
- const XML_Char *expected = XCS("1");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetStartElementHandler(g_parser, accumulate_attribute);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_attr_after_solidus) {
- const char *text = "<doc attr1='a' / attr2='b'>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN, "Misplaced / not faulted");
-}
-END_TEST
-
-static void XMLCALL
-accumulate_entity_decl(void *userData, const XML_Char *entityName,
- int is_parameter_entity, const XML_Char *value,
- int value_length, const XML_Char *base,
- const XML_Char *systemId, const XML_Char *publicId,
- const XML_Char *notationName) {
- CharData *storage = (CharData *)userData;
-
- UNUSED_P(is_parameter_entity);
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- UNUSED_P(notationName);
- CharData_AppendXMLChars(storage, entityName, -1);
- CharData_AppendXMLChars(storage, XCS("="), 1);
- CharData_AppendXMLChars(storage, value, value_length);
- CharData_AppendXMLChars(storage, XCS("\n"), 1);
-}
-
-START_TEST(test_utf16_pe) {
- /* <!DOCTYPE doc [
- * <!ENTITY % {KHO KHWAI}{CHO CHAN} '<!ELEMENT doc (#PCDATA)>'>
- * %{KHO KHWAI}{CHO CHAN};
- * ]>
- * <doc></doc>
- *
- * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
- * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
- */
- const char text[] = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
- "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \x0e\x04\x0e\x08\0 "
- "\0'\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 "
- "\0d\0o\0c\0 \0(\0#\0P\0C\0D\0A\0T\0A\0)\0>\0'\0>\0\n"
- "\0%\x0e\x04\x0e\x08\0;\0\n"
- "\0]\0>\0\n"
- "\0<\0d\0o\0c\0>\0<\0/\0d\0o\0c\0>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x0e04\x0e08=<!ELEMENT doc (#PCDATA)>\n");
-#else
- const XML_Char *expected
- = XCS("\xe0\xb8\x84\xe0\xb8\x88=<!ELEMENT doc (#PCDATA)>\n");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetEntityDeclHandler(g_parser, accumulate_entity_decl);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test that duff attribute description keywords are rejected */
-START_TEST(test_bad_attr_desc_keyword) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ATTLIST doc attr CDATA #!IMPLIED>\n"
- "]>\n"
- "<doc />";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Bad keyword !IMPLIED not faulted");
-}
-END_TEST
-
-/* Test that an invalid attribute description keyword consisting of
- * UTF-16 characters with their top bytes non-zero are correctly
- * faulted
- */
-START_TEST(test_bad_attr_desc_keyword_utf16) {
- /* <!DOCTYPE d [
- * <!ATTLIST d a CDATA #{KHO KHWAI}{CHO CHAN}>
- * ]><d/>
- *
- * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
- * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
- */
- const char text[]
- = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
- "\0<\0!\0A\0T\0T\0L\0I\0S\0T\0 \0d\0 \0a\0 \0C\0D\0A\0T\0A\0 "
- "\0#\x0e\x04\x0e\x08\0>\0\n"
- "\0]\0>\0<\0d\0/\0>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Invalid UTF16 attribute keyword not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test that invalid syntax in a <!DOCTYPE> is rejected. Do this
- * using prefix-encoding (see above) to trigger specific code paths
- */
-START_TEST(test_bad_doctype) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- "<!DOCTYPE doc [ \x80\x44 ]><doc/>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- expect_failure(text, XML_ERROR_SYNTAX,
- "Invalid bytes in DOCTYPE not faulted");
-}
-END_TEST
-
-START_TEST(test_bad_doctype_utf16) {
- const char text[] =
- /* <!DOCTYPE doc [ \x06f2 ]><doc/>
- *
- * U+06F2 = EXTENDED ARABIC-INDIC DIGIT TWO, a valid number
- * (name character) but not a valid letter (name start character)
- */
- "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0 "
- "\x06\xf2"
- "\0 \0]\0>\0<\0d\0o\0c\0/\0>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Invalid bytes in DOCTYPE not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_bad_doctype_plus) {
- const char *text = "<!DOCTYPE 1+ [ <!ENTITY foo 'bar'> ]>\n"
- "<1+>&foo;</1+>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "'+' in document name not faulted");
-}
-END_TEST
-
-START_TEST(test_bad_doctype_star) {
- const char *text = "<!DOCTYPE 1* [ <!ENTITY foo 'bar'> ]>\n"
- "<1*>&foo;</1*>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "'*' in document name not faulted");
-}
-END_TEST
-
-START_TEST(test_bad_doctype_query) {
- const char *text = "<!DOCTYPE 1? [ <!ENTITY foo 'bar'> ]>\n"
- "<1?>&foo;</1?>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "'?' in document name not faulted");
-}
-END_TEST
-
-START_TEST(test_unknown_encoding_bad_ignore) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>"
- "<!DOCTYPE doc SYSTEM 'foo'>"
- "<doc><e>&entity;</e></doc>";
- ExtFaults fault = {"<![IGNORE[<!ELEMENT \xffG (#PCDATA)*>]]>",
- "Invalid character not faulted", XCS("prefix-conv"),
- XML_ERROR_INVALID_TOKEN};
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- XML_SetUserData(g_parser, &fault);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Bad IGNORE section with unknown encoding not failed");
-}
-END_TEST
-
-START_TEST(test_entity_in_utf16_be_attr) {
- const char text[] =
- /* <e a='&#228; &#x00E4;'></e> */
- "\0<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 "
- "\0&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e4 \x00e4");
-#else
- const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetStartElementHandler(g_parser, accumulate_attribute);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_entity_in_utf16_le_attr) {
- const char text[] =
- /* <e a='&#228; &#x00E4;'></e> */
- "<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 \0"
- "&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>\0";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("\x00e4 \x00e4");
-#else
- const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetStartElementHandler(g_parser, accumulate_attribute);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_entity_public_utf16_be) {
- const char text[] =
- /* <!DOCTYPE d [ */
- "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
- /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
- "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 "
- "\0'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n"
- /* %e; */
- "\0%\0e\0;\0\n"
- /* ]> */
- "\0]\0>\0\n"
- /* <d>&j;</d> */
- "\0<\0d\0>\0&\0j\0;\0<\0/\0d\0>";
- ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
- "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>",
- 34, NULL, NULL, EE_PARSE_NONE};
- const XML_Char *expected = XCS("baz");
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_entity_public_utf16_le) {
- const char text[] =
- /* <!DOCTYPE d [ */
- "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
- /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
- "<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 \0"
- "'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n\0"
- /* %e; */
- "%\0e\0;\0\n\0"
- /* ]> */
- "]\0>\0\n\0"
- /* <d>&j;</d> */
- "<\0d\0>\0&\0j\0;\0<\0/\0d\0>\0";
- ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
- "<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>\0",
- 34, NULL, NULL, EE_PARSE_NONE};
- const XML_Char *expected = XCS("baz");
- CharData storage;
-
- CharData_Init(&storage);
- test_data.storage = &storage;
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
- XML_SetUserData(g_parser, &test_data);
- XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-/* Test that a doctype with neither an internal nor external subset is
- * faulted
- */
-START_TEST(test_short_doctype) {
- const char *text = "<!DOCTYPE doc></doc>";
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "DOCTYPE without subset not rejected");
-}
-END_TEST
-
-START_TEST(test_short_doctype_2) {
- const char *text = "<!DOCTYPE doc PUBLIC></doc>";
- expect_failure(text, XML_ERROR_SYNTAX,
- "DOCTYPE without Public ID not rejected");
-}
-END_TEST
-
-START_TEST(test_short_doctype_3) {
- const char *text = "<!DOCTYPE doc SYSTEM></doc>";
- expect_failure(text, XML_ERROR_SYNTAX,
- "DOCTYPE without System ID not rejected");
-}
-END_TEST
-
-START_TEST(test_long_doctype) {
- const char *text = "<!DOCTYPE doc PUBLIC 'foo' 'bar' 'baz'></doc>";
- expect_failure(text, XML_ERROR_SYNTAX, "DOCTYPE with extra ID not rejected");
-}
-END_TEST
-
-START_TEST(test_bad_entity) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY foo PUBLIC>\n"
- "]>\n"
- "<doc/>";
- expect_failure(text, XML_ERROR_SYNTAX,
- "ENTITY without Public ID is not rejected");
-}
-END_TEST
-
-/* Test unquoted value is faulted */
-START_TEST(test_bad_entity_2) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY % foo bar>\n"
- "]>\n"
- "<doc/>";
- expect_failure(text, XML_ERROR_SYNTAX,
- "ENTITY without Public ID is not rejected");
-}
-END_TEST
-
-START_TEST(test_bad_entity_3) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY % foo PUBLIC>\n"
- "]>\n"
- "<doc/>";
- expect_failure(text, XML_ERROR_SYNTAX,
- "Parameter ENTITY without Public ID is not rejected");
-}
-END_TEST
-
-START_TEST(test_bad_entity_4) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY % foo SYSTEM>\n"
- "]>\n"
- "<doc/>";
- expect_failure(text, XML_ERROR_SYNTAX,
- "Parameter ENTITY without Public ID is not rejected");
-}
-END_TEST
-
-START_TEST(test_bad_notation) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!NOTATION n SYSTEM>\n"
- "]>\n"
- "<doc/>";
- expect_failure(text, XML_ERROR_SYNTAX,
- "Notation without System ID is not rejected");
-}
-END_TEST
-
-/* Test for issue #11, wrongly suppressed default handler */
-typedef struct default_check {
- const XML_Char *expected;
- const int expectedLen;
- XML_Bool seen;
-} DefaultCheck;
-
-static void XMLCALL
-checking_default_handler(void *userData, const XML_Char *s, int len) {
- DefaultCheck *data = (DefaultCheck *)userData;
- int i;
-
- for (i = 0; data[i].expected != NULL; i++) {
- if (data[i].expectedLen == len
- && ! memcmp(data[i].expected, s, len * sizeof(XML_Char))) {
- data[i].seen = XML_TRUE;
- break;
- }
- }
-}
-
-START_TEST(test_default_doctype_handler) {
- const char *text = "<!DOCTYPE doc PUBLIC 'pubname' 'test.dtd' [\n"
- " <!ENTITY foo 'bar'>\n"
- "]>\n"
- "<doc>&foo;</doc>";
- DefaultCheck test_data[] = {{XCS("'pubname'"), 9, XML_FALSE},
- {XCS("'test.dtd'"), 10, XML_FALSE},
- {NULL, 0, XML_FALSE}};
- int i;
-
- XML_SetUserData(g_parser, &test_data);
- XML_SetDefaultHandler(g_parser, checking_default_handler);
- XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- for (i = 0; test_data[i].expected != NULL; i++)
- if (! test_data[i].seen)
- fail("Default handler not run for public !DOCTYPE");
-}
-END_TEST
-
-START_TEST(test_empty_element_abort) {
- const char *text = "<abort/>";
-
- XML_SetStartElementHandler(g_parser, start_element_suspender);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Expected to error on abort");
-}
-END_TEST
-
-/*
- * Namespaces tests.
- */
-
-static void
-namespace_setup(void) {
- g_parser = XML_ParserCreateNS(NULL, XCS(' '));
- if (g_parser == NULL)
- fail("Parser not created.");
-}
-
-static void
-namespace_teardown(void) {
- basic_teardown();
-}
-
-/* Check that an element name and attribute name match the expected values.
- The expected values are passed as an array reference of string pointers
- provided as the userData argument; the first is the expected
- element name, and the second is the expected attribute name.
-*/
-static int triplet_start_flag = XML_FALSE;
-static int triplet_end_flag = XML_FALSE;
-
-static void XMLCALL
-triplet_start_checker(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- XML_Char **elemstr = (XML_Char **)userData;
- char buffer[1024];
- if (xcstrcmp(elemstr[0], name) != 0) {
- sprintf(buffer, "unexpected start string: '%" XML_FMT_STR "'", name);
- fail(buffer);
- }
- if (xcstrcmp(elemstr[1], atts[0]) != 0) {
- sprintf(buffer, "unexpected attribute string: '%" XML_FMT_STR "'", atts[0]);
- fail(buffer);
- }
- triplet_start_flag = XML_TRUE;
-}
-
-/* Check that the element name passed to the end-element handler matches
- the expected value. The expected value is passed as the first element
- in an array of strings passed as the userData argument.
-*/
-static void XMLCALL
-triplet_end_checker(void *userData, const XML_Char *name) {
- XML_Char **elemstr = (XML_Char **)userData;
- if (xcstrcmp(elemstr[0], name) != 0) {
- char buffer[1024];
- sprintf(buffer, "unexpected end string: '%" XML_FMT_STR "'", name);
- fail(buffer);
- }
- triplet_end_flag = XML_TRUE;
-}
-
-START_TEST(test_return_ns_triplet) {
- const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
- " xmlns:bar='http://example.org/'>";
- const char *epilog = "</foo:e>";
- const XML_Char *elemstr[]
- = {XCS("http://example.org/ e foo"), XCS("http://example.org/ a bar")};
- XML_SetReturnNSTriplet(g_parser, XML_TRUE);
- XML_SetUserData(g_parser, (void *)elemstr);
- XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
- XML_SetNamespaceDeclHandler(g_parser, dummy_start_namespace_decl_handler,
- dummy_end_namespace_decl_handler);
- triplet_start_flag = XML_FALSE;
- triplet_end_flag = XML_FALSE;
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (! triplet_start_flag)
- fail("triplet_start_checker not invoked");
- /* Check that unsetting "return triplets" fails while still parsing */
- XML_SetReturnNSTriplet(g_parser, XML_FALSE);
- if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (! triplet_end_flag)
- fail("triplet_end_checker not invoked");
- if (dummy_handler_flags
- != (DUMMY_START_NS_DECL_HANDLER_FLAG | DUMMY_END_NS_DECL_HANDLER_FLAG))
- fail("Namespace handlers not called");
-}
-END_TEST
-
-static void XMLCALL
-overwrite_start_checker(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- CharData *storage = (CharData *)userData;
- CharData_AppendXMLChars(storage, XCS("start "), 6);
- CharData_AppendXMLChars(storage, name, -1);
- while (*atts != NULL) {
- CharData_AppendXMLChars(storage, XCS("\nattribute "), 11);
- CharData_AppendXMLChars(storage, *atts, -1);
- atts += 2;
- }
- CharData_AppendXMLChars(storage, XCS("\n"), 1);
-}
-
-static void XMLCALL
-overwrite_end_checker(void *userData, const XML_Char *name) {
- CharData *storage = (CharData *)userData;
- CharData_AppendXMLChars(storage, XCS("end "), 4);
- CharData_AppendXMLChars(storage, name, -1);
- CharData_AppendXMLChars(storage, XCS("\n"), 1);
-}
-
-static void
-run_ns_tagname_overwrite_test(const char *text, const XML_Char *result) {
- CharData storage;
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetElementHandler(g_parser, overwrite_start_checker,
- overwrite_end_checker);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, result);
-}
-
-/* Regression test for SF bug #566334. */
-START_TEST(test_ns_tagname_overwrite) {
- const char *text = "<n:e xmlns:n='http://example.org/'>\n"
- " <n:f n:attr='foo'/>\n"
- " <n:g n:attr2='bar'/>\n"
- "</n:e>";
- const XML_Char *result = XCS("start http://example.org/ e\n")
- XCS("start http://example.org/ f\n")
- XCS("attribute http://example.org/ attr\n")
- XCS("end http://example.org/ f\n")
- XCS("start http://example.org/ g\n")
- XCS("attribute http://example.org/ attr2\n")
- XCS("end http://example.org/ g\n")
- XCS("end http://example.org/ e\n");
- run_ns_tagname_overwrite_test(text, result);
-}
-END_TEST
-
-/* Regression test for SF bug #566334. */
-START_TEST(test_ns_tagname_overwrite_triplet) {
- const char *text = "<n:e xmlns:n='http://example.org/'>\n"
- " <n:f n:attr='foo'/>\n"
- " <n:g n:attr2='bar'/>\n"
- "</n:e>";
- const XML_Char *result = XCS("start http://example.org/ e n\n")
- XCS("start http://example.org/ f n\n")
- XCS("attribute http://example.org/ attr n\n")
- XCS("end http://example.org/ f n\n")
- XCS("start http://example.org/ g n\n")
- XCS("attribute http://example.org/ attr2 n\n")
- XCS("end http://example.org/ g n\n")
- XCS("end http://example.org/ e n\n");
- XML_SetReturnNSTriplet(g_parser, XML_TRUE);
- run_ns_tagname_overwrite_test(text, result);
-}
-END_TEST
-
-/* Regression test for SF bug #620343. */
-static void XMLCALL
-start_element_fail(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- UNUSED_P(userData);
- UNUSED_P(name);
- UNUSED_P(atts);
-
- /* We should never get here. */
- fail("should never reach start_element_fail()");
-}
-
-static void XMLCALL
-start_ns_clearing_start_element(void *userData, const XML_Char *prefix,
- const XML_Char *uri) {
- UNUSED_P(prefix);
- UNUSED_P(uri);
- XML_SetStartElementHandler((XML_Parser)userData, NULL);
-}
-
-START_TEST(test_start_ns_clears_start_element) {
- /* This needs to use separate start/end tags; using the empty tag
- syntax doesn't cause the problematic path through Expat to be
- taken.
- */
- const char *text = "<e xmlns='http://example.org/'></e>";
-
- XML_SetStartElementHandler(g_parser, start_element_fail);
- XML_SetStartNamespaceDeclHandler(g_parser, start_ns_clearing_start_element);
- XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
- XML_UseParserAsHandlerArg(g_parser);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Regression test for SF bug #616863. */
-static int XMLCALL
-external_entity_handler(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
- const char *text;
- XML_Parser p2;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- if (callno == 1)
- text = ("<!ELEMENT doc (e+)>\n"
- "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
- "<!ELEMENT e EMPTY>\n");
- else
- text = ("<?xml version='1.0' encoding='us-ascii'?>"
- "<e/>");
-
- XML_SetUserData(parser, (void *)callno);
- p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (_XML_Parse_SINGLE_BYTES(p2, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(p2);
- return XML_STATUS_ERROR;
- }
- XML_ParserFree(p2);
- return XML_STATUS_OK;
-}
-
-START_TEST(test_default_ns_from_ext_subset_and_ext_ge) {
- const char *text = "<?xml version='1.0'?>\n"
- "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
- " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/ns1'>\n"
- "&en;\n"
- "</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_handler);
- /* We actually need to set this handler to tickle this bug. */
- XML_SetStartElementHandler(g_parser, dummy_start_element);
- XML_SetUserData(g_parser, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Regression test #1 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_1) {
- const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
- " <e xmlns:prefix=''/>\n"
- "</doc>";
-
- expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
- "Did not report re-setting namespace"
- " URI with prefix to ''.");
-}
-END_TEST
-
-/* Regression test #2 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_2) {
- const char *text = "<?xml version='1.0'?>\n"
- "<docelem xmlns:pre=''/>";
-
- expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
- "Did not report setting namespace URI with prefix to ''.");
-}
-END_TEST
-
-/* Regression test #3 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_3) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ELEMENT doc EMPTY>\n"
- " <!ATTLIST doc\n"
- " xmlns:prefix CDATA ''>\n"
- "]>\n"
- "<doc/>";
-
- expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
- "Didn't report attr default setting NS w/ prefix to ''.");
-}
-END_TEST
-
-/* Regression test #4 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_4) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ELEMENT prefix:doc EMPTY>\n"
- " <!ATTLIST prefix:doc\n"
- " xmlns:prefix CDATA 'http://example.org/'>\n"
- "]>\n"
- "<prefix:doc/>";
- /* Packaged info expected by the end element handler;
- the weird structuring lets us re-use the triplet_end_checker()
- function also used for another test. */
- const XML_Char *elemstr[] = {XCS("http://example.org/ doc prefix")};
- XML_SetReturnNSTriplet(g_parser, XML_TRUE);
- XML_SetUserData(g_parser, (void *)elemstr);
- XML_SetEndElementHandler(g_parser, triplet_end_checker);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test with non-xmlns prefix */
-START_TEST(test_ns_unbound_prefix) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ELEMENT prefix:doc EMPTY>\n"
- " <!ATTLIST prefix:doc\n"
- " notxmlns:prefix CDATA 'http://example.org/'>\n"
- "]>\n"
- "<prefix:doc/>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Unbound prefix incorrectly passed");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_UNBOUND_PREFIX)
- xml_failure(g_parser);
-}
-END_TEST
-
-START_TEST(test_ns_default_with_empty_uri) {
- const char *text = "<doc xmlns='http://example.org/'>\n"
- " <e xmlns=''/>\n"
- "</doc>";
- /* Add some handlers to exercise extra code paths */
- XML_SetStartNamespaceDeclHandler(g_parser,
- dummy_start_namespace_decl_handler);
- XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Regression test for SF bug #692964: two prefixes for one namespace. */
-START_TEST(test_ns_duplicate_attrs_diff_prefixes) {
- const char *text = "<doc xmlns:a='http://example.org/a'\n"
- " xmlns:b='http://example.org/a'\n"
- " a:a='v' b:a='v' />";
- expect_failure(text, XML_ERROR_DUPLICATE_ATTRIBUTE,
- "did not report multiple attributes with same URI+name");
-}
-END_TEST
-
-START_TEST(test_ns_duplicate_hashes) {
- /* The hash of an attribute is calculated as the hash of its URI
- * concatenated with a space followed by its name (after the
- * colon). We wish to generate attributes with the same hash
- * value modulo the attribute table size so that we can check that
- * the attribute hash table works correctly. The attribute hash
- * table size will be the smallest power of two greater than the
- * number of attributes, but at least eight. There is
- * unfortunately no programmatic way of getting the hash or the
- * table size at user level, but the test code coverage percentage
- * will drop if the hashes cease to point to the same row.
- *
- * The cunning plan is to have few enough attributes to have a
- * reliable table size of 8, and have the single letter attribute
- * names be 8 characters apart, producing a hash which will be the
- * same modulo 8.
- */
- const char *text = "<doc xmlns:a='http://example.org/a'\n"
- " a:a='v' a:i='w' />";
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Regression test for SF bug #695401: unbound prefix. */
-START_TEST(test_ns_unbound_prefix_on_attribute) {
- const char *text = "<doc a:attr=''/>";
- expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
- "did not report unbound prefix on attribute");
-}
-END_TEST
-
-/* Regression test for SF bug #695401: unbound prefix. */
-START_TEST(test_ns_unbound_prefix_on_element) {
- const char *text = "<a:doc/>";
- expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
- "did not report unbound prefix on element");
-}
-END_TEST
-
-/* Test that the parsing status is correctly reset by XML_ParserReset().
- * We usE test_return_ns_triplet() for our example parse to improve
- * coverage of tidying up code executed.
- */
-START_TEST(test_ns_parser_reset) {
- XML_ParsingStatus status;
-
- XML_GetParsingStatus(g_parser, &status);
- if (status.parsing != XML_INITIALIZED)
- fail("parsing status doesn't start INITIALIZED");
- test_return_ns_triplet();
- XML_GetParsingStatus(g_parser, &status);
- if (status.parsing != XML_FINISHED)
- fail("parsing status doesn't end FINISHED");
- XML_ParserReset(g_parser, NULL);
- XML_GetParsingStatus(g_parser, &status);
- if (status.parsing != XML_INITIALIZED)
- fail("parsing status doesn't reset to INITIALIZED");
-}
-END_TEST
-
-/* Test that long element names with namespaces are handled correctly */
-START_TEST(test_ns_long_element) {
- const char *text
- = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
- " xmlns:foo='http://example.org/' bar:a='12'\n"
- " xmlns:bar='http://example.org/'>"
- "</foo:thisisalongenoughelementnametotriggerareallocation>";
- const XML_Char *elemstr[]
- = {XCS("http://example.org/")
- XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
- XCS("http://example.org/ a bar")};
-
- XML_SetReturnNSTriplet(g_parser, XML_TRUE);
- XML_SetUserData(g_parser, (void *)elemstr);
- XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test mixed population of prefixed and unprefixed attributes */
-START_TEST(test_ns_mixed_prefix_atts) {
- const char *text = "<e a='12' bar:b='13'\n"
- " xmlns:bar='http://example.org/'>"
- "</e>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test having a long namespaced element name inside a short one.
- * This exercises some internal buffer reallocation that is shared
- * across elements with the same namespace URI.
- */
-START_TEST(test_ns_extend_uri_buffer) {
- const char *text = "<foo:e xmlns:foo='http://example.org/'>"
- " <foo:thisisalongenoughnametotriggerallocationaction"
- " foo:a='12' />"
- "</foo:e>";
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test that xmlns is correctly rejected as an attribute in the xmlns
- * namespace, but not in other namespaces
- */
-START_TEST(test_ns_reserved_attributes) {
- const char *text1
- = "<foo:e xmlns:foo='http://example.org/' xmlns:xmlns='12' />";
- const char *text2
- = "<foo:e xmlns:foo='http://example.org/' foo:xmlns='12' />";
- expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XMLNS,
- "xmlns not rejected as an attribute");
- XML_ParserReset(g_parser, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test more reserved attributes */
-START_TEST(test_ns_reserved_attributes_2) {
- const char *text1 = "<foo:e xmlns:foo='http://example.org/'"
- " xmlns:xml='http://example.org/' />";
- const char *text2
- = "<foo:e xmlns:foo='http://www.w3.org/XML/1998/namespace' />";
- const char *text3 = "<foo:e xmlns:foo='http://www.w3.org/2000/xmlns/' />";
-
- expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML,
- "xml not rejected as an attribute");
- XML_ParserReset(g_parser, NULL);
- expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI,
- "Use of w3.org URL not faulted");
- XML_ParserReset(g_parser, NULL);
- expect_failure(text3, XML_ERROR_RESERVED_NAMESPACE_URI,
- "Use of w3.org xmlns URL not faulted");
-}
-END_TEST
-
-/* Test string pool handling of namespace names of 2048 characters */
-/* Exercises a particular string pool growth path */
-START_TEST(test_ns_extremely_long_prefix) {
- /* C99 compilers are only required to support 4095-character
- * strings, so the following needs to be split in two to be safe
- * for all compilers.
- */
- const char *text1
- = "<doc "
- /* 64 character on each line */
- /* ...gives a total length of 2048 */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- ":a='12'";
- const char *text2
- = " xmlns:"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "='foo'\n>"
- "</doc>";
-
- if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-/* Test unknown encoding handlers in namespace setup */
-START_TEST(test_ns_unknown_encoding_success) {
- const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
- "<foo:e xmlns:foo='http://example.org/'>Hi</foo:e>";
-
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- run_character_check(text, XCS("Hi"));
-}
-END_TEST
-
-/* Test that too many colons are rejected */
-START_TEST(test_ns_double_colon) {
- const char *text = "<foo:e xmlns:foo='http://example.org/' foo:a:b='bar' />";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Double colon in attribute name not faulted");
-}
-END_TEST
-
-START_TEST(test_ns_double_colon_element) {
- const char *text = "<foo:bar:e xmlns:foo='http://example.org/' />";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Double colon in element name not faulted");
-}
-END_TEST
-
-/* Test that non-name characters after a colon are rejected */
-START_TEST(test_ns_bad_attr_leafname) {
- const char *text = "<foo:e xmlns:foo='http://example.org/' foo:?ar='baz' />";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Invalid character in leafname not faulted");
-}
-END_TEST
-
-START_TEST(test_ns_bad_element_leafname) {
- const char *text = "<foo:?oc xmlns:foo='http://example.org/' />";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Invalid character in element leafname not faulted");
-}
-END_TEST
-
-/* Test high-byte-set UTF-16 characters are valid in a leafname */
-START_TEST(test_ns_utf16_leafname) {
- const char text[] =
- /* <n:e xmlns:n='URI' n:{KHO KHWAI}='a' />
- * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
- */
- "<\0n\0:\0e\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0 \0"
- "n\0:\0\x04\x0e=\0'\0a\0'\0 \0/\0>\0";
- const XML_Char *expected = XCS("a");
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetStartElementHandler(g_parser, accumulate_attribute);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_ns_utf16_element_leafname) {
- const char text[] =
- /* <n:{KHO KHWAI} xmlns:n='URI'/>
- * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
- */
- "\0<\0n\0:\x0e\x04\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0/\0>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("URI \x0e04");
-#else
- const XML_Char *expected = XCS("URI \xe0\xb8\x84");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetStartElementHandler(g_parser, start_element_event_handler);
- XML_SetUserData(g_parser, &storage);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_ns_utf16_doctype) {
- const char text[] =
- /* <!DOCTYPE foo:{KHO KHWAI} [ <!ENTITY bar 'baz'> ]>\n
- * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
- */
- "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0f\0o\0o\0:\x0e\x04\0 "
- "\0[\0 \0<\0!\0E\0N\0T\0I\0T\0Y\0 \0b\0a\0r\0 \0'\0b\0a\0z\0'\0>\0 "
- "\0]\0>\0\n"
- /* <foo:{KHO KHWAI} xmlns:foo='URI'>&bar;</foo:{KHO KHWAI}> */
- "\0<\0f\0o\0o\0:\x0e\x04\0 "
- "\0x\0m\0l\0n\0s\0:\0f\0o\0o\0=\0'\0U\0R\0I\0'\0>"
- "\0&\0b\0a\0r\0;"
- "\0<\0/\0f\0o\0o\0:\x0e\x04\0>";
-#ifdef XML_UNICODE
- const XML_Char *expected = XCS("URI \x0e04");
-#else
- const XML_Char *expected = XCS("URI \xe0\xb8\x84");
-#endif
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetStartElementHandler(g_parser, start_element_event_handler);
- XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-START_TEST(test_ns_invalid_doctype) {
- const char *text = "<!DOCTYPE foo:!bad [ <!ENTITY bar 'baz' ]>\n"
- "<foo:!bad>&bar;</foo:!bad>";
-
- expect_failure(text, XML_ERROR_INVALID_TOKEN,
- "Invalid character in document local name not faulted");
-}
-END_TEST
-
-START_TEST(test_ns_double_colon_doctype) {
- const char *text = "<!DOCTYPE foo:a:doc [ <!ENTITY bar 'baz' ]>\n"
- "<foo:a:doc>&bar;</foo:a:doc>";
-
- expect_failure(text, XML_ERROR_SYNTAX,
- "Double colon in document name not faulted");
-}
-END_TEST
-
-/* Control variable; the number of times duff_allocator() will successfully
- * allocate */
-#define ALLOC_ALWAYS_SUCCEED (-1)
-#define REALLOC_ALWAYS_SUCCEED (-1)
-
-static intptr_t allocation_count = ALLOC_ALWAYS_SUCCEED;
-static intptr_t reallocation_count = REALLOC_ALWAYS_SUCCEED;
-
-/* Crocked allocator for allocation failure tests */
-static void *
-duff_allocator(size_t size) {
- if (allocation_count == 0)
- return NULL;
- if (allocation_count != ALLOC_ALWAYS_SUCCEED)
- allocation_count--;
- return malloc(size);
-}
-
-/* Crocked reallocator for allocation failure tests */
-static void *
-duff_reallocator(void *ptr, size_t size) {
- if (reallocation_count == 0)
- return NULL;
- if (reallocation_count != REALLOC_ALWAYS_SUCCEED)
- reallocation_count--;
- return realloc(ptr, size);
-}
-
-/* Test that a failure to allocate the parser structure fails gracefully */
-START_TEST(test_misc_alloc_create_parser) {
- XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
- unsigned int i;
- const unsigned int max_alloc_count = 10;
-
- /* Something this simple shouldn't need more than 10 allocations */
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
- if (g_parser != NULL)
- break;
- }
- if (i == 0)
- fail("Parser unexpectedly ignored failing allocator");
- else if (i == max_alloc_count)
- fail("Parser not created with max allocation count");
-}
-END_TEST
-
-/* Test memory allocation failures for a parser with an encoding */
-START_TEST(test_misc_alloc_create_parser_with_encoding) {
- XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
- unsigned int i;
- const unsigned int max_alloc_count = 10;
-
- /* Try several levels of allocation */
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- g_parser = XML_ParserCreate_MM(XCS("us-ascii"), &memsuite, NULL);
- if (g_parser != NULL)
- break;
- }
- if (i == 0)
- fail("Parser ignored failing allocator");
- else if (i == max_alloc_count)
- fail("Parser not created with max allocation count");
-}
-END_TEST
-
-/* Test that freeing a NULL parser doesn't cause an explosion.
- * (Not actually tested anywhere else)
- */
-START_TEST(test_misc_null_parser) {
- XML_ParserFree(NULL);
-}
-END_TEST
-
-/* Test that XML_ErrorString rejects out-of-range codes */
-START_TEST(test_misc_error_string) {
- if (XML_ErrorString((enum XML_Error) - 1) != NULL)
- fail("Negative error code not rejected");
- if (XML_ErrorString((enum XML_Error)100) != NULL)
- fail("Large error code not rejected");
-}
-END_TEST
-
-/* Test the version information is consistent */
-
-/* Since we are working in XML_LChars (potentially 16-bits), we
- * can't use the standard C library functions for character
- * manipulation and have to roll our own.
- */
-static int
-parse_version(const XML_LChar *version_text,
- XML_Expat_Version *version_struct) {
- if (! version_text)
- return XML_FALSE;
-
- while (*version_text != 0x00) {
- if (*version_text >= ASCII_0 && *version_text <= ASCII_9)
- break;
- version_text++;
- }
- if (*version_text == 0x00)
- return XML_FALSE;
-
- /* version_struct->major = strtoul(version_text, 10, &version_text) */
- version_struct->major = 0;
- while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
- version_struct->major
- = 10 * version_struct->major + (*version_text++ - ASCII_0);
- }
- if (*version_text++ != ASCII_PERIOD)
- return XML_FALSE;
-
- /* Now for the minor version number */
- version_struct->minor = 0;
- while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
- version_struct->minor
- = 10 * version_struct->minor + (*version_text++ - ASCII_0);
- }
- if (*version_text++ != ASCII_PERIOD)
- return XML_FALSE;
-
- /* Finally the micro version number */
- version_struct->micro = 0;
- while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
- version_struct->micro
- = 10 * version_struct->micro + (*version_text++ - ASCII_0);
- }
- if (*version_text != 0x00)
- return XML_FALSE;
- return XML_TRUE;
-}
-
-static int
-versions_equal(const XML_Expat_Version *first,
- const XML_Expat_Version *second) {
- return (first->major == second->major && first->minor == second->minor
- && first->micro == second->micro);
-}
-
-START_TEST(test_misc_version) {
- XML_Expat_Version read_version = XML_ExpatVersionInfo();
- /* Silence compiler warning with the following assignment */
- XML_Expat_Version parsed_version = {0, 0, 0};
- const XML_LChar *version_text = XML_ExpatVersion();
-
- if (version_text == NULL)
- fail("Could not obtain version text");
- assert(version_text != NULL);
- if (! parse_version(version_text, &parsed_version))
- fail("Unable to parse version text");
- if (! versions_equal(&read_version, &parsed_version))
- fail("Version mismatch");
-
-#if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T)
- if (xcstrcmp(version_text, XCS("expat_2.2.9"))) /* needs bump on releases */
- fail("XML_*_VERSION in expat.h out of sync?\n");
-#else
- /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T
- * then XML_LChar is defined as char, for some reason.
- */
- if (strcmp(version_text, "expat_2.2.5")) /* needs bump on releases */
- fail("XML_*_VERSION in expat.h out of sync?\n");
-#endif /* ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T) */
-}
-END_TEST
-
-/* Test feature information */
-START_TEST(test_misc_features) {
- const XML_Feature *features = XML_GetFeatureList();
-
- /* Prevent problems with double-freeing parsers */
- g_parser = NULL;
- if (features == NULL) {
- fail("Failed to get feature information");
- } else {
- /* Loop through the features checking what we can */
- while (features->feature != XML_FEATURE_END) {
- switch (features->feature) {
- case XML_FEATURE_SIZEOF_XML_CHAR:
- if (features->value != sizeof(XML_Char))
- fail("Incorrect size of XML_Char");
- break;
- case XML_FEATURE_SIZEOF_XML_LCHAR:
- if (features->value != sizeof(XML_LChar))
- fail("Incorrect size of XML_LChar");
- break;
- default:
- break;
- }
- features++;
- }
- }
-}
-END_TEST
-
-/* Regression test for GitHub Issue #17: memory leak parsing attribute
- * values with mixed bound and unbound namespaces.
- */
-START_TEST(test_misc_attribute_leak) {
- const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>";
- XML_Memory_Handling_Suite memsuite
- = {tracking_malloc, tracking_realloc, tracking_free};
-
- g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n"));
- expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found");
- XML_ParserFree(g_parser);
- /* Prevent the teardown trying to double free */
- g_parser = NULL;
-
- if (! tracking_report())
- fail("Memory leak found");
-}
-END_TEST
-
-/* Test parser created for UTF-16LE is successful */
-START_TEST(test_misc_utf16le) {
- const char text[] =
- /* <?xml version='1.0'?><q>Hi</q> */
- "<\0?\0x\0m\0l\0 \0"
- "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0"
- "<\0q\0>\0H\0i\0<\0/\0q\0>\0";
- const XML_Char *expected = XCS("Hi");
- CharData storage;
-
- g_parser = XML_ParserCreate(XCS("UTF-16LE"));
- if (g_parser == NULL)
- fail("Parser not created");
-
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
- CharData_CheckXMLChars(&storage, expected);
-}
-END_TEST
-
-typedef struct {
- XML_Parser parser;
- int deep;
-} DataIssue240;
-
-static void
-start_element_issue_240(void *userData, const XML_Char *name,
- const XML_Char **atts) {
- DataIssue240 *mydata = (DataIssue240 *)userData;
- UNUSED_P(name);
- UNUSED_P(atts);
- mydata->deep++;
-}
-
-static void
-end_element_issue_240(void *userData, const XML_Char *name) {
- DataIssue240 *mydata = (DataIssue240 *)userData;
-
- UNUSED_P(name);
- mydata->deep--;
- if (mydata->deep == 0) {
- XML_StopParser(mydata->parser, 0);
- }
-}
-
-START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
- XML_Parser parser;
- DataIssue240 *mydata;
- enum XML_Status result;
- const char *const doc1 = "<doc><e1/><e><foo/></e></doc>";
-
- parser = XML_ParserCreate(NULL);
- XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
- mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
- mydata->parser = parser;
- mydata->deep = 0;
- XML_SetUserData(parser, mydata);
-
- result = XML_Parse(parser, doc1, (int)strlen(doc1), 1);
- XML_ParserFree(parser);
- free(mydata);
- if (result != XML_STATUS_ERROR)
- fail("Stopping the parser did not work as expected");
-}
-END_TEST
-
-START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
- XML_Parser parser;
- DataIssue240 *mydata;
- enum XML_Status result;
- const char *const doc2 = "<doc><elem/></doc>";
-
- parser = XML_ParserCreate(NULL);
- XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
- mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
- mydata->parser = parser;
- mydata->deep = 0;
- XML_SetUserData(parser, mydata);
-
- result = XML_Parse(parser, doc2, (int)strlen(doc2), 1);
- XML_ParserFree(parser);
- free(mydata);
- if (result != XML_STATUS_ERROR)
- fail("Stopping the parser did not work as expected");
-}
-END_TEST
-
-#ifdef XML_DTD
-START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
- const char *const inputOne = "<!DOCTYPE d [\n"
- "<!ENTITY % e ']><d/>'>\n"
- "\n"
- "%e;";
- const char *const inputTwo = "<!DOCTYPE d [\n"
- "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&e1;'>\n"
- "\n"
- "%e2;";
- const char *const inputThree = "<!DOCTYPE d [\n"
- "<!ENTITY % e ']><d'>\n"
- "\n"
- "%e;";
- const char *const inputIssue317 = "<!DOCTYPE doc [\n"
- "<!ENTITY % foo ']>\n"
- "<doc>Hell<oc (#PCDATA)*>'>\n"
- "%foo;\n"
- "]>\n"
- "<doc>Hello, world</dVc>";
-
- const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
- size_t inputIndex = 0;
-
- for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
- XML_Parser parser;
- enum XML_Status parseResult;
- int setParamEntityResult;
- XML_Size lineNumber;
- XML_Size columnNumber;
- const char *const input = inputs[inputIndex];
-
- parser = XML_ParserCreate(NULL);
- setParamEntityResult
- = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- if (setParamEntityResult != 1)
- fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
-
- parseResult = XML_Parse(parser, input, (int)strlen(input), 0);
- if (parseResult != XML_STATUS_ERROR) {
- parseResult = XML_Parse(parser, "", 0, 1);
- if (parseResult != XML_STATUS_ERROR) {
- fail("Parsing was expected to fail but succeeded.");
- }
- }
-
- if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
- fail("Error code does not match XML_ERROR_INVALID_TOKEN");
-
- lineNumber = XML_GetCurrentLineNumber(parser);
- if (lineNumber != 4)
- fail("XML_GetCurrentLineNumber does not work as expected.");
-
- columnNumber = XML_GetCurrentColumnNumber(parser);
- if (columnNumber != 0)
- fail("XML_GetCurrentColumnNumber does not work as expected.");
-
- XML_ParserFree(parser);
- }
-}
-END_TEST
-#endif
-
-static void
-alloc_setup(void) {
- XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
-
- /* Ensure the parser creation will go through */
- allocation_count = ALLOC_ALWAYS_SUCCEED;
- reallocation_count = REALLOC_ALWAYS_SUCCEED;
- g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
- if (g_parser == NULL)
- fail("Parser not created");
-}
-
-static void
-alloc_teardown(void) {
- basic_teardown();
-}
-
-/* Test the effects of allocation failures on xml declaration processing */
-START_TEST(test_alloc_parse_xdecl) {
- const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<doc>Hello, world</doc>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* Resetting the parser is insufficient, because some memory
- * allocations are cached within the parser. Instead we use
- * the teardown and setup routines to ensure that we have the
- * right sort of parser back in our hands.
- */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed with max allocations");
-}
-END_TEST
-
-/* As above, but with an encoding big enough to cause storing the
- * version information to expand the string pool being used.
- */
-static int XMLCALL
-long_encoding_handler(void *userData, const XML_Char *encoding,
- XML_Encoding *info) {
- int i;
-
- UNUSED_P(userData);
- UNUSED_P(encoding);
- for (i = 0; i < 256; i++)
- info->map[i] = i;
- info->data = NULL;
- info->convert = NULL;
- info->release = NULL;
- return XML_STATUS_OK;
-}
-
-START_TEST(test_alloc_parse_xdecl_2) {
- const char *text
- = "<?xml version='1.0' encoding='"
- /* Each line is 64 characters */
- "ThisIsAStupidlyLongEncodingNameIntendedToTriggerPoolGrowth123456"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN"
- "'?>"
- "<doc>Hello, world</doc>";
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
- XML_SetUnknownEncodingHandler(g_parser, long_encoding_handler, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed with max allocations");
-}
-END_TEST
-
-/* Test the effects of allocation failures on a straightforward parse */
-START_TEST(test_alloc_parse_pi) {
- const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<?pi unknown?>\n"
- "<doc>"
- "Hello, world"
- "</doc>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed with max allocations");
-}
-END_TEST
-
-START_TEST(test_alloc_parse_pi_2) {
- const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<doc>"
- "Hello, world"
- "<?pi unknown?>\n"
- "</doc>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed with max allocations");
-}
-END_TEST
-
-START_TEST(test_alloc_parse_pi_3) {
- const char *text
- = "<?"
- /* 64 characters per line */
- "This processing instruction should be long enough to ensure that"
- "it triggers the growth of an internal string pool when the "
- "allocator fails at a cruicial moment FGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "Q?><doc/>";
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed with max allocations");
-}
-END_TEST
-
-START_TEST(test_alloc_parse_comment) {
- const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<!-- Test parsing this comment -->"
- "<doc>Hi</doc>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetCommentHandler(g_parser, dummy_comment_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed with max allocations");
-}
-END_TEST
-
-START_TEST(test_alloc_parse_comment_2) {
- const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<doc>"
- "Hello, world"
- "<!-- Parse this comment too -->"
- "</doc>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetCommentHandler(g_parser, dummy_comment_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed with max allocations");
-}
-END_TEST
-
-static int XMLCALL
-external_entity_duff_loader(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- XML_Parser new_parser;
- unsigned int i;
- const unsigned int max_alloc_count = 10;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- /* Try a few different allocation levels */
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (new_parser != NULL) {
- XML_ParserFree(new_parser);
- break;
- }
- }
- if (i == 0)
- fail("External parser creation ignored failing allocator");
- else if (i == max_alloc_count)
- fail("Extern parser not created with max allocation count");
-
- /* Make sure other random allocation doesn't now fail */
- allocation_count = ALLOC_ALWAYS_SUCCEED;
-
- /* Make sure the failure code path is executed too */
- return XML_STATUS_ERROR;
-}
-
-/* Test that external parser creation running out of memory is
- * correctly reported. Based on the external entity test cases.
- */
-START_TEST(test_alloc_create_external_parser) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, foo_text);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_duff_loader);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR) {
- fail("External parser allocator returned success incorrectly");
- }
-}
-END_TEST
-
-/* More external parser memory allocation testing */
-START_TEST(test_alloc_run_external_parser) {
- const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
- unsigned int i;
- const unsigned int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, foo_text);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing ignored failing allocator");
- else if (i == max_alloc_count)
- fail("Parsing failed with allocation count 10");
-}
-END_TEST
-
-static int XMLCALL
-external_entity_dbl_handler(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- intptr_t callno = (intptr_t)XML_GetUserData(parser);
- const char *text;
- XML_Parser new_parser;
- int i;
- const int max_alloc_count = 20;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- if (callno == 0) {
- /* First time through, check how many calls to malloc occur */
- text = ("<!ELEMENT doc (e+)>\n"
- "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
- "<!ELEMENT e EMPTY>\n");
- allocation_count = 10000;
- new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (new_parser == NULL) {
- fail("Unable to allocate first external parser");
- return XML_STATUS_ERROR;
- }
- /* Stash the number of calls in the user data */
- XML_SetUserData(parser, (void *)(intptr_t)(10000 - allocation_count));
- } else {
- text = ("<?xml version='1.0' encoding='us-ascii'?>"
- "<e/>");
- /* Try at varying levels to exercise more code paths */
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = callno + i;
- new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (new_parser != NULL)
- break;
- }
- if (i == 0) {
- fail("Second external parser unexpectedly created");
- XML_ParserFree(new_parser);
- return XML_STATUS_ERROR;
- } else if (i == max_alloc_count) {
- fail("Second external parser not created");
- return XML_STATUS_ERROR;
- }
- }
-
- allocation_count = ALLOC_ALWAYS_SUCCEED;
- if (_XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(new_parser);
- return XML_STATUS_ERROR;
- }
- XML_ParserFree(new_parser);
- return XML_STATUS_OK;
-}
-
-/* Test that running out of memory in dtdCopy is correctly reported.
- * Based on test_default_ns_from_ext_subset_and_ext_ge()
- */
-START_TEST(test_alloc_dtd_copy_default_atts) {
- const char *text = "<?xml version='1.0'?>\n"
- "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
- " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/ns1'>\n"
- "&en;\n"
- "</doc>";
-
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler);
- XML_SetUserData(g_parser, NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-}
-END_TEST
-
-static int XMLCALL
-external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- intptr_t callno = (intptr_t)XML_GetUserData(parser);
- const char *text;
- XML_Parser new_parser;
- enum XML_Status rv;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- if (callno == 0) {
- /* Try different allocation levels for whole exercise */
- text = ("<!ELEMENT doc (e+)>\n"
- "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
- "<!ELEMENT e EMPTY>\n");
- XML_SetUserData(parser, (void *)(intptr_t)1);
- new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (new_parser == NULL)
- return XML_STATUS_ERROR;
- rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
- } else {
- /* Just run through once */
- text = ("<?xml version='1.0' encoding='us-ascii'?>"
- "<e/>");
- new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (new_parser == NULL)
- return XML_STATUS_ERROR;
- rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
- }
- XML_ParserFree(new_parser);
- if (rv == XML_STATUS_ERROR)
- return XML_STATUS_ERROR;
- return XML_STATUS_OK;
-}
-
-/* Test more external entity allocation failure paths */
-START_TEST(test_alloc_external_entity) {
- const char *text = "<?xml version='1.0'?>\n"
- "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
- " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/ns1'>\n"
- "&en;\n"
- "</doc>";
- int i;
- const int alloc_test_max_repeats = 50;
-
- for (i = 0; i < alloc_test_max_repeats; i++) {
- allocation_count = -1;
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler_2);
- XML_SetUserData(g_parser, NULL);
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- allocation_count = -1;
- if (i == 0)
- fail("External entity parsed despite duff allocator");
- if (i == alloc_test_max_repeats)
- fail("External entity not parsed at max allocation count");
-}
-END_TEST
-
-/* Test more allocation failure paths */
-static int XMLCALL
-external_entity_alloc_set_encoding(XML_Parser parser, const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId) {
- /* As for external_entity_loader() */
- const char *text = "<?xml encoding='iso-8859-3'?>"
- "\xC3\xA9";
- XML_Parser ext_parser;
- enum XML_Status status;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- return XML_STATUS_ERROR;
- if (! XML_SetEncoding(ext_parser, XCS("utf-8"))) {
- XML_ParserFree(ext_parser);
- return XML_STATUS_ERROR;
- }
- status
- = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
- XML_ParserFree(ext_parser);
- if (status == XML_STATUS_ERROR)
- return XML_STATUS_ERROR;
- return XML_STATUS_OK;
-}
-
-START_TEST(test_alloc_ext_entity_set_encoding) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- int i;
- const int max_allocation_count = 30;
-
- for (i = 0; i < max_allocation_count; i++) {
- XML_SetExternalEntityRefHandler(g_parser,
- external_entity_alloc_set_encoding);
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- break;
- allocation_count = -1;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Encoding check succeeded despite failing allocator");
- if (i == max_allocation_count)
- fail("Encoding failed at max allocation count");
-}
-END_TEST
-
-static int XMLCALL
-unknown_released_encoding_handler(void *data, const XML_Char *encoding,
- XML_Encoding *info) {
- UNUSED_P(data);
- if (! xcstrcmp(encoding, XCS("unsupported-encoding"))) {
- int i;
-
- for (i = 0; i < 256; i++)
- info->map[i] = i;
- info->data = NULL;
- info->convert = NULL;
- info->release = dummy_release;
- return XML_STATUS_OK;
- }
- return XML_STATUS_ERROR;
-}
-
-/* Test the effects of allocation failure in internal entities.
- * Based on test_unknown_encoding_internal_entity
- */
-START_TEST(test_alloc_internal_entity) {
- const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
- "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
- "<test a='&foo;'/>";
- unsigned int i;
- const unsigned int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUnknownEncodingHandler(g_parser, unknown_released_encoding_handler,
- NULL);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Internal entity worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Internal entity failed at max allocation count");
-}
-END_TEST
-
-/* Test the robustness against allocation failure of element handling
- * Based on test_dtd_default_handling().
- */
-START_TEST(test_alloc_dtd_default_handling) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
- "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
- "<!ENTITY e1 SYSTEM 'http://example.org/e' NDATA n>\n"
- "<!ELEMENT doc (#PCDATA)>\n"
- "<!ATTLIST doc a CDATA #IMPLIED>\n"
- "<?pi in dtd?>\n"
- "<!--comment in dtd-->\n"
- "]>\n"
- "<doc><![CDATA[text in doc]]></doc>";
- const XML_Char *expected = XCS("\n\n\n\n\n\n\n\n\n<doc>text in doc</doc>");
- CharData storage;
- int i;
- const int max_alloc_count = 25;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- dummy_handler_flags = 0;
- XML_SetDefaultHandler(g_parser, accumulate_characters);
- XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
- dummy_end_doctype_handler);
- XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
- XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
- XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
- XML_SetCommentHandler(g_parser, dummy_comment_handler);
- XML_SetCdataSectionHandler(g_parser, dummy_start_cdata_handler,
- dummy_end_cdata_handler);
- XML_SetUnparsedEntityDeclHandler(g_parser,
- dummy_unparsed_entity_decl_handler);
- CharData_Init(&storage);
- XML_SetUserData(g_parser, &storage);
- XML_SetCharacterDataHandler(g_parser, accumulate_characters);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Default DTD parsed despite allocation failures");
- if (i == max_alloc_count)
- fail("Default DTD not parsed with maximum alloc count");
- CharData_CheckXMLChars(&storage, expected);
- if (dummy_handler_flags
- != (DUMMY_START_DOCTYPE_HANDLER_FLAG | DUMMY_END_DOCTYPE_HANDLER_FLAG
- | DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG
- | DUMMY_ELEMENT_DECL_HANDLER_FLAG | DUMMY_ATTLIST_DECL_HANDLER_FLAG
- | DUMMY_COMMENT_HANDLER_FLAG | DUMMY_PI_HANDLER_FLAG
- | DUMMY_START_CDATA_HANDLER_FLAG | DUMMY_END_CDATA_HANDLER_FLAG
- | DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG))
- fail("Not all handlers were called");
-}
-END_TEST
-
-/* Test robustness of XML_SetEncoding() with a failing allocator */
-START_TEST(test_alloc_explicit_encoding) {
- int i;
- const int max_alloc_count = 5;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (XML_SetEncoding(g_parser, XCS("us-ascii")) == XML_STATUS_OK)
- break;
- }
- if (i == 0)
- fail("Encoding set despite failing allocator");
- else if (i == max_alloc_count)
- fail("Encoding not set at max allocation count");
-}
-END_TEST
-
-/* Test robustness of XML_SetBase against a failing allocator */
-START_TEST(test_alloc_set_base) {
- const XML_Char *new_base = XCS("/local/file/name.xml");
- int i;
- const int max_alloc_count = 5;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (XML_SetBase(g_parser, new_base) == XML_STATUS_OK)
- break;
- }
- if (i == 0)
- fail("Base set despite failing allocator");
- else if (i == max_alloc_count)
- fail("Base not set with max allocation count");
-}
-END_TEST
-
-/* Test buffer extension in the face of a duff reallocator */
-START_TEST(test_alloc_realloc_buffer) {
- const char *text = get_buffer_test_text;
- void *buffer;
- int i;
- const int max_realloc_count = 10;
-
- /* Get a smallish buffer */
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- buffer = XML_GetBuffer(g_parser, 1536);
- if (buffer == NULL)
- fail("1.5K buffer reallocation failed");
- assert(buffer != NULL);
- memcpy(buffer, text, strlen(text));
- if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
- == XML_STATUS_OK)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- reallocation_count = -1;
- if (i == 0)
- fail("Parse succeeded with no reallocation");
- else if (i == max_realloc_count)
- fail("Parse failed with max reallocation count");
-}
-END_TEST
-
-/* Same test for external entity parsers */
-static int XMLCALL
-external_entity_reallocator(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = get_buffer_test_text;
- XML_Parser ext_parser;
- void *buffer;
- enum XML_Status status;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- fail("Could not create external entity parser");
-
- reallocation_count = (intptr_t)XML_GetUserData(parser);
- buffer = XML_GetBuffer(ext_parser, 1536);
- if (buffer == NULL)
- fail("Buffer allocation failed");
- assert(buffer != NULL);
- memcpy(buffer, text, strlen(text));
- status = XML_ParseBuffer(ext_parser, (int)strlen(text), XML_FALSE);
- reallocation_count = -1;
- XML_ParserFree(ext_parser);
- return (status == XML_STATUS_OK) ? XML_STATUS_OK : XML_STATUS_ERROR;
-}
-
-START_TEST(test_alloc_ext_entity_realloc_buffer) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- XML_SetExternalEntityRefHandler(g_parser, external_entity_reallocator);
- XML_SetUserData(g_parser, (void *)(intptr_t)i);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- == XML_STATUS_OK)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Succeeded with no reallocations");
- if (i == max_realloc_count)
- fail("Failed with max reallocations");
-}
-END_TEST
-
-/* Test elements with many attributes are handled correctly */
-START_TEST(test_alloc_realloc_many_attributes) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ATTLIST doc za CDATA 'default'>\n"
- "<!ATTLIST doc zb CDATA 'def2'>\n"
- "<!ATTLIST doc zc CDATA 'def3'>\n"
- "]>\n"
- "<doc a='1'"
- " b='2'"
- " c='3'"
- " d='4'"
- " e='5'"
- " f='6'"
- " g='7'"
- " h='8'"
- " i='9'"
- " j='10'"
- " k='11'"
- " l='12'"
- " m='13'"
- " n='14'"
- " p='15'"
- " q='16'"
- " r='17'"
- " s='18'>"
- "</doc>";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite no reallocations");
- if (i == max_realloc_count)
- fail("Parse failed at max reallocations");
-}
-END_TEST
-
-/* Test handling of a public entity with failing allocator */
-START_TEST(test_alloc_public_entity_value) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
- "<doc></doc>\n";
- char dtd_text[]
- = "<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % e1 PUBLIC 'foo' 'bar.ent'>\n"
- "<!ENTITY % "
- /* Each line is 64 characters */
- "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- " '%e1;'>\n"
- "%e1;\n";
- int i;
- const int max_alloc_count = 50;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- dummy_handler_flags = 0;
- XML_SetUserData(g_parser, dtd_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
- /* Provoke a particular code path */
- XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocation");
- if (i == max_alloc_count)
- fail("Parsing failed at max allocation count");
- if (dummy_handler_flags != DUMMY_ENTITY_DECL_HANDLER_FLAG)
- fail("Entity declaration handler not called");
-}
-END_TEST
-
-START_TEST(test_alloc_realloc_subst_public_entity_value) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
- "<doc></doc>\n";
- char dtd_text[]
- = "<!ELEMENT doc EMPTY>\n"
- "<!ENTITY % "
- /* Each line is 64 characters */
- "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- " PUBLIC 'foo' 'bar.ent'>\n"
- "%ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP;";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetUserData(g_parser, dtd_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocation");
- if (i == max_realloc_count)
- fail("Parsing failed at max reallocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_parse_public_doctype) {
- const char *text
- = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<!DOCTYPE doc PUBLIC '"
- /* 64 characters per line */
- "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "' 'test'>\n"
- "<doc></doc>";
- int i;
- const int max_alloc_count = 25;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- dummy_handler_flags = 0;
- XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
- dummy_end_doctype_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
- if (dummy_handler_flags
- != (DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG
- | DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG))
- fail("Doctype handler functions not called");
-}
-END_TEST
-
-START_TEST(test_alloc_parse_public_doctype_long_name) {
- const char *text
- = "<?xml version='1.0' encoding='utf-8'?>\n"
- "<!DOCTYPE doc PUBLIC 'http://example.com/foo' '"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "'>\n"
- "<doc></doc>";
- int i;
- const int max_alloc_count = 25;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
- dummy_end_doctype_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
-}
-END_TEST
-
-static int XMLCALL
-external_entity_alloc(XML_Parser parser, const XML_Char *context,
- const XML_Char *base, const XML_Char *systemId,
- const XML_Char *publicId) {
- const char *text = (const char *)XML_GetUserData(parser);
- XML_Parser ext_parser;
- int parse_res;
-
- UNUSED_P(base);
- UNUSED_P(systemId);
- UNUSED_P(publicId);
- ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (ext_parser == NULL)
- return XML_STATUS_ERROR;
- parse_res
- = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
- XML_ParserFree(ext_parser);
- return parse_res;
-}
-
-/* Test foreign DTD handling */
-START_TEST(test_alloc_set_foreign_dtd) {
- const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<doc>&entity;</doc>";
- char text2[] = "<!ELEMENT doc (#PCDATA)*>";
- int i;
- const int max_alloc_count = 25;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(g_parser, &text2);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
- fail("Could not set foreign DTD");
- if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
-}
-END_TEST
-
-/* Test based on ibm/valid/P32/ibm32v04.xml */
-START_TEST(test_alloc_attribute_enum_value) {
- const char *text = "<?xml version='1.0' standalone='no'?>\n"
- "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
- "<animal>This is a \n <a/> \n\nyellow tiger</animal>";
- char dtd_text[] = "<!ELEMENT animal (#PCDATA|a)*>\n"
- "<!ELEMENT a EMPTY>\n"
- "<!ATTLIST animal xml:space (default|preserve) 'preserve'>";
- int i;
- const int max_alloc_count = 30;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- XML_SetUserData(g_parser, dtd_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- /* An attribute list handler provokes a different code path */
- XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
-}
-END_TEST
-
-/* Test attribute enums sufficient to overflow the string pool */
-START_TEST(test_alloc_realloc_attribute_enum_value) {
- const char *text = "<?xml version='1.0' standalone='no'?>\n"
- "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
- "<animal>This is a yellow tiger</animal>";
- /* We wish to define a collection of attribute enums that will
- * cause the string pool storing them to have to expand. This
- * means more than 1024 bytes, including the parentheses and
- * separator bars.
- */
- char dtd_text[]
- = "<!ELEMENT animal (#PCDATA)*>\n"
- "<!ATTLIST animal thing "
- "(default"
- /* Each line is 64 characters */
- "|ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO)"
- " 'default'>";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- XML_SetUserData(g_parser, dtd_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- /* An attribute list handler provokes a different code path */
- XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
-}
-END_TEST
-
-/* Test attribute enums in a #IMPLIED attribute forcing pool growth */
-START_TEST(test_alloc_realloc_implied_attribute) {
- /* Forcing this particular code path is a balancing act. The
- * addition of the closing parenthesis and terminal NUL must be
- * what pushes the string of enums over the 1024-byte limit,
- * otherwise a different code path will pick up the realloc.
- */
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc EMPTY>\n"
- "<!ATTLIST doc a "
- /* Each line is 64 characters */
- "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
- " #IMPLIED>\n"
- "]><doc/>";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
-}
-END_TEST
-
-/* Test attribute enums in a defaulted attribute forcing pool growth */
-START_TEST(test_alloc_realloc_default_attribute) {
- /* Forcing this particular code path is a balancing act. The
- * addition of the closing parenthesis and terminal NUL must be
- * what pushes the string of enums over the 1024-byte limit,
- * otherwise a different code path will pick up the realloc.
- */
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc EMPTY>\n"
- "<!ATTLIST doc a "
- /* Each line is 64 characters */
- "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
- "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
- " 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO'"
- ">\n]><doc/>";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
-}
-END_TEST
-
-/* Test long notation name with dodgy allocator */
-START_TEST(test_alloc_notation) {
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!NOTATION "
- /* Each line is 64 characters */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- " SYSTEM 'http://example.org/n'>\n"
- "<!ENTITY e SYSTEM 'http://example.org/e' NDATA "
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- ">\n"
- "<!ELEMENT doc EMPTY>\n"
- "]>\n<doc/>";
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- dummy_handler_flags = 0;
- XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
- XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite allocation failures");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
- if (dummy_handler_flags
- != (DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG))
- fail("Entity declaration handler not called");
-}
-END_TEST
-
-/* Test public notation with dodgy allocator */
-START_TEST(test_alloc_public_notation) {
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!NOTATION note PUBLIC '"
- /* 64 characters per line */
- "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "' 'foo'>\n"
- "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
- "<!ELEMENT doc EMPTY>\n"
- "]>\n<doc/>";
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- dummy_handler_flags = 0;
- XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite allocation failures");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
- if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
- fail("Notation handler not called");
-}
-END_TEST
-
-/* Test public notation with dodgy allocator */
-START_TEST(test_alloc_system_notation) {
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!NOTATION note SYSTEM '"
- /* 64 characters per line */
- "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "'>\n"
- "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
- "<!ELEMENT doc EMPTY>\n"
- "]>\n<doc/>";
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- dummy_handler_flags = 0;
- XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite allocation failures");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
- if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
- fail("Notation handler not called");
-}
-END_TEST
-
-START_TEST(test_alloc_nested_groups) {
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc "
- /* Sixteen elements per line */
- "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
- "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
- "))))))))))))))))))))))))))))))))>\n"
- "<!ELEMENT e EMPTY>"
- "]>\n"
- "<doc><e/></doc>";
- CharData storage;
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- CharData_Init(&storage);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetStartElementHandler(g_parser, record_element_start_handler);
- XML_SetUserData(g_parser, &storage);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
-
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum reallocation count");
- CharData_CheckXMLChars(&storage, XCS("doce"));
- if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
- fail("Element handler not fired");
-}
-END_TEST
-
-START_TEST(test_alloc_realloc_nested_groups) {
- const char *text
- = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc "
- /* Sixteen elements per line */
- "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
- "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
- "))))))))))))))))))))))))))))))))>\n"
- "<!ELEMENT e EMPTY>"
- "]>\n"
- "<doc><e/></doc>";
- CharData storage;
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- CharData_Init(&storage);
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- XML_SetStartElementHandler(g_parser, record_element_start_handler);
- XML_SetUserData(g_parser, &storage);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
-
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
- CharData_CheckXMLChars(&storage, XCS("doce"));
- if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
- fail("Element handler not fired");
-}
-END_TEST
-
-START_TEST(test_alloc_large_group) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc ("
- "a1|a2|a3|a4|a5|a6|a7|a8|"
- "b1|b2|b3|b4|b5|b6|b7|b8|"
- "c1|c2|c3|c4|c5|c6|c7|c8|"
- "d1|d2|d3|d4|d5|d6|d7|d8|"
- "e1"
- ")+>\n"
- "]>\n"
- "<doc>\n"
- "<a1/>\n"
- "</doc>\n";
- int i;
- const int max_alloc_count = 50;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
- if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
- fail("Element handler flag not raised");
-}
-END_TEST
-
-START_TEST(test_alloc_realloc_group_choice) {
- const char *text = "<!DOCTYPE doc [\n"
- "<!ELEMENT doc ("
- "a1|a2|a3|a4|a5|a6|a7|a8|"
- "b1|b2|b3|b4|b5|b6|b7|b8|"
- "c1|c2|c3|c4|c5|c6|c7|c8|"
- "d1|d2|d3|d4|d5|d6|d7|d8|"
- "e1"
- ")+>\n"
- "]>\n"
- "<doc>\n"
- "<a1/>\n"
- "<b2 attr='foo'>This is a foo</b2>\n"
- "<c3></c3>\n"
- "</doc>\n";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
- if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
- fail("Element handler flag not raised");
-}
-END_TEST
-
-START_TEST(test_alloc_pi_in_epilog) {
- const char *text = "<doc></doc>\n"
- "<?pi in epilog?>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse completed despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
- if (dummy_handler_flags != DUMMY_PI_HANDLER_FLAG)
- fail("Processing instruction handler not invoked");
-}
-END_TEST
-
-START_TEST(test_alloc_comment_in_epilog) {
- const char *text = "<doc></doc>\n"
- "<!-- comment in epilog -->";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetCommentHandler(g_parser, dummy_comment_handler);
- dummy_handler_flags = 0;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse completed despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
- if (dummy_handler_flags != DUMMY_COMMENT_HANDLER_FLAG)
- fail("Processing instruction handler not invoked");
-}
-END_TEST
-
-START_TEST(test_alloc_realloc_long_attribute_value) {
- const char *text
- = "<!DOCTYPE doc [<!ENTITY foo '"
- /* Each line is 64 characters */
- "This entity will be substituted as an attribute value, and is "
- "calculated to be exactly long enough that the terminating NUL "
- "that the library adds internally will trigger the string pool to"
- "grow. GHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "'>]>\n"
- "<doc a='&foo;'></doc>";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_attribute_whitespace) {
- const char *text = "<doc a=' '></doc>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_attribute_predefined_entity) {
- const char *text = "<doc a='&amp;'></doc>";
- int i;
- const int max_alloc_count = 15;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
-}
-END_TEST
-
-/* Test that a character reference at the end of a suitably long
- * default value for an attribute can trigger pool growth, and recovers
- * if the allocator fails on it.
- */
-START_TEST(test_alloc_long_attr_default_with_char_ref) {
- const char *text
- = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHI"
- "&#x31;'>]>\n"
- "<doc/>";
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
-}
-END_TEST
-
-/* Test that a long character reference substitution triggers a pool
- * expansion correctly for an attribute value.
- */
-START_TEST(test_alloc_long_attr_value) {
- const char *text
- = "<!DOCTYPE test [<!ENTITY foo '\n"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "'>]>\n"
- "<test a='&foo;'/>";
- int i;
- const int max_alloc_count = 25;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing allocator");
- if (i == max_alloc_count)
- fail("Parse failed at maximum allocation count");
-}
-END_TEST
-
-/* Test that an error in a nested parameter entity substitution is
- * handled correctly. It seems unlikely that the code path being
- * exercised can be reached purely by carefully crafted XML, but an
- * allocation error in the right place will definitely do it.
- */
-START_TEST(test_alloc_nested_entities) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
- "<doc />";
- ExtFaults test_data
- = {"<!ENTITY % pe1 '"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "'>\n"
- "<!ENTITY % pe2 '%pe1;'>\n"
- "%pe2;",
- "Memory Fail not faulted", NULL, XML_ERROR_NO_MEMORY};
-
- /* Causes an allocation error in a nested storeEntityValue() */
- allocation_count = 12;
- XML_SetUserData(g_parser, &test_data);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
- expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- "Entity allocation failure not noted");
-}
-END_TEST
-
-START_TEST(test_alloc_realloc_param_entity_newline) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
- "<doc/>";
- char dtd_text[]
- = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
- /* 64 characters per line */
- "This default value is carefully crafted so that the carriage "
- "return right at the end of the entity string causes an internal "
- "string pool to have to grow. This allows us to test the alloc "
- "failure path from that point. OPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDE"
- "\">\n'>"
- "%pe;\n";
- int i;
- const int max_realloc_count = 5;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetUserData(g_parser, dtd_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_realloc_ce_extends_pe) {
- const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
- "<doc/>";
- char dtd_text[]
- = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
- /* 64 characters per line */
- "This default value is carefully crafted so that the character "
- "entity at the end causes an internal string pool to have to "
- "grow. This allows us to test the allocation failure path from "
- "that point onwards. EFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFG&#x51;"
- "\">\n'>"
- "%pe;\n";
- int i;
- const int max_realloc_count = 5;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetUserData(g_parser, dtd_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_realloc_attributes) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ATTLIST doc\n"
- " a1 (a|b|c) 'a'\n"
- " a2 (foo|bar) #IMPLIED\n"
- " a3 NMTOKEN #IMPLIED\n"
- " a4 NMTOKENS #IMPLIED\n"
- " a5 ID #IMPLIED\n"
- " a6 IDREF #IMPLIED\n"
- " a7 IDREFS #IMPLIED\n"
- " a8 ENTITY #IMPLIED\n"
- " a9 ENTITIES #IMPLIED\n"
- " a10 CDATA #IMPLIED\n"
- " >]>\n"
- "<doc>wombat</doc>\n";
- int i;
- const int max_realloc_count = 5;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
-
- if (i == 0)
- fail("Parse succeeded despite failing reallocator");
- if (i == max_realloc_count)
- fail("Parse failed at maximum reallocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_long_doc_name) {
- const char *text =
- /* 64 characters per line */
- "<LongRootElementNameThatWillCauseTheNextAllocationToExpandTheStr"
- "ingPoolForTheDTDQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- " a='1'/>";
- int i;
- const int max_alloc_count = 20;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max reallocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_long_base) {
- const char *text = "<!DOCTYPE doc [\n"
- " <!ENTITY e SYSTEM 'foo'>\n"
- "]>\n"
- "<doc>&e;</doc>";
- char entity_text[] = "Hello world";
- const XML_Char *base =
- /* 64 characters per line */
- /* clang-format off */
- XCS("LongBaseURI/that/will/overflow/an/internal/buffer/and/cause/it/t")
- XCS("o/have/to/grow/PQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/");
- /* clang-format on */
- int i;
- const int max_alloc_count = 25;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, entity_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- if (XML_SetBase(g_parser, base) == XML_STATUS_ERROR) {
- XML_ParserReset(g_parser, NULL);
- continue;
- }
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_long_public_id) {
- const char *text
- = "<!DOCTYPE doc [\n"
- " <!ENTITY e PUBLIC '"
- /* 64 characters per line */
- "LongPublicIDThatShouldResultInAnInternalStringPoolGrowingAtASpec"
- "ificMomentKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "' 'bar'>\n"
- "]>\n"
- "<doc>&e;</doc>";
- char entity_text[] = "Hello world";
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, entity_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_long_entity_value) {
- const char *text
- = "<!DOCTYPE doc [\n"
- " <!ENTITY e1 '"
- /* 64 characters per line */
- "Long entity value that should provoke a string pool to grow whil"
- "e setting up to parse the external entity below. xyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "'>\n"
- " <!ENTITY e2 SYSTEM 'bar'>\n"
- "]>\n"
- "<doc>&e2;</doc>";
- char entity_text[] = "Hello world";
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, entity_text);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-START_TEST(test_alloc_long_notation) {
- const char *text
- = "<!DOCTYPE doc [\n"
- " <!NOTATION note SYSTEM '"
- /* 64 characters per line */
- "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
- "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "'>\n"
- " <!ENTITY e1 SYSTEM 'foo' NDATA "
- /* 64 characters per line */
- "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
- "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
- ">\n"
- " <!ENTITY e2 SYSTEM 'bar'>\n"
- "]>\n"
- "<doc>&e2;</doc>";
- ExtOption options[]
- = {{XCS("foo"), "Entity Foo"}, {XCS("bar"), "Entity Bar"}, {NULL, NULL}};
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
-
- /* See comment in test_alloc_parse_xdecl() */
- alloc_teardown();
- alloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-static void
-nsalloc_setup(void) {
- XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
- XML_Char ns_sep[2] = {' ', '\0'};
-
- /* Ensure the parser creation will go through */
- allocation_count = ALLOC_ALWAYS_SUCCEED;
- reallocation_count = REALLOC_ALWAYS_SUCCEED;
- g_parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep);
- if (g_parser == NULL)
- fail("Parser not created");
-}
-
-static void
-nsalloc_teardown(void) {
- basic_teardown();
-}
-
-/* Test the effects of allocation failure in simple namespace parsing.
- * Based on test_ns_default_with_empty_uri()
- */
-START_TEST(test_nsalloc_xmlns) {
- const char *text = "<doc xmlns='http://example.org/'>\n"
- " <e xmlns=''/>\n"
- "</doc>";
- unsigned int i;
- const unsigned int max_alloc_count = 30;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- /* Exercise more code paths with a default handler */
- XML_SetDefaultHandler(g_parser, dummy_default_handler);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* Resetting the parser is insufficient, because some memory
- * allocations are cached within the parser. Instead we use
- * the teardown and setup routines to ensure that we have the
- * right sort of parser back in our hands.
- */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at maximum allocation count");
-}
-END_TEST
-
-/* Test XML_ParseBuffer interface with namespace and a dicky allocator */
-START_TEST(test_nsalloc_parse_buffer) {
- const char *text = "<doc>Hello</doc>";
- void *buffer;
-
- /* Try a parse before the start of the world */
- /* (Exercises new code path) */
- allocation_count = 0;
- if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR)
- fail("Pre-init XML_ParseBuffer not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_MEMORY)
- fail("Pre-init XML_ParseBuffer faulted for wrong reason");
-
- /* Now with actual memory allocation */
- allocation_count = ALLOC_ALWAYS_SUCCEED;
- if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_OK)
- xml_failure(g_parser);
-
- /* Check that resuming an unsuspended parser is faulted */
- if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
- fail("Resuming unsuspended parser not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_NOT_SUSPENDED)
- xml_failure(g_parser);
-
- /* Get the parser into suspended state */
- XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
- resumable = XML_TRUE;
- buffer = XML_GetBuffer(g_parser, (int)strlen(text));
- if (buffer == NULL)
- fail("Could not acquire parse buffer");
- assert(buffer != NULL);
- memcpy(buffer, text, strlen(text));
- if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
- != XML_STATUS_SUSPENDED)
- xml_failure(g_parser);
- if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
- xml_failure(g_parser);
- if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Suspended XML_ParseBuffer not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
- xml_failure(g_parser);
- if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
- fail("Suspended XML_GetBuffer not faulted");
-
- /* Get it going again and complete the world */
- XML_SetCharacterDataHandler(g_parser, NULL);
- if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
- xml_failure(g_parser);
- if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- fail("Post-finishing XML_ParseBuffer not faulted");
- if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
- xml_failure(g_parser);
- if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
- fail("Post-finishing XML_GetBuffer not faulted");
-}
-END_TEST
-
-/* Check handling of long prefix names (pool growth) */
-START_TEST(test_nsalloc_long_prefix) {
- const char *text
- = "<"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":foo xmlns:"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "='http://example.org/'>"
- "</"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":foo>";
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-/* Check handling of long uri names (pool growth) */
-START_TEST(test_nsalloc_long_uri) {
- const char *text
- = "<foo:e xmlns:foo='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "' bar:a='12'\n"
- "xmlns:bar='http://example.org/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
- "'>"
- "</foo:e>";
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-/* Test handling of long attribute names with prefixes */
-START_TEST(test_nsalloc_long_attr) {
- const char *text
- = "<foo:e xmlns:foo='http://example.org/' bar:"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "='12'\n"
- "xmlns:bar='http://example.org/'>"
- "</foo:e>";
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-/* Test handling of an attribute name with a long namespace prefix */
-START_TEST(test_nsalloc_long_attr_prefix) {
- const char *text
- = "<foo:e xmlns:foo='http://example.org/' "
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":a='12'\n"
- "xmlns:"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "='http://example.org/'>"
- "</foo:e>";
- const XML_Char *elemstr[] = {
- /* clang-format off */
- XCS("http://example.org/ e foo"),
- XCS("http://example.org/ a ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
- /* clang-format on */
- };
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetReturnNSTriplet(g_parser, XML_TRUE);
- XML_SetUserData(g_parser, (void *)elemstr);
- XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-/* Test attribute handling in the face of a dodgy reallocator */
-START_TEST(test_nsalloc_realloc_attributes) {
- const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
- " xmlns:bar='http://example.org/'>"
- "</foo:e>";
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_realloc_count)
- fail("Parsing failed at max reallocation count");
-}
-END_TEST
-
-/* Test long element names with namespaces under a failing allocator */
-START_TEST(test_nsalloc_long_element) {
- const char *text
- = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
- " xmlns:foo='http://example.org/' bar:a='12'\n"
- " xmlns:bar='http://example.org/'>"
- "</foo:thisisalongenoughelementnametotriggerareallocation>";
- const XML_Char *elemstr[]
- = {XCS("http://example.org/")
- XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
- XCS("http://example.org/ a bar")};
- int i;
- const int max_alloc_count = 30;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetReturnNSTriplet(g_parser, XML_TRUE);
- XML_SetUserData(g_parser, (void *)elemstr);
- XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_alloc_count)
- fail("Parsing failed at max reallocation count");
-}
-END_TEST
-
-/* Test the effects of reallocation failure when reassigning a
- * binding.
- *
- * XML_ParserReset does not free the BINDING structures used by a
- * parser, but instead adds them to an internal free list to be reused
- * as necessary. Likewise the URI buffers allocated for the binding
- * aren't freed, but kept attached to their existing binding. If the
- * new binding has a longer URI, it will need reallocation. This test
- * provokes that reallocation, and tests the control path if it fails.
- */
-START_TEST(test_nsalloc_realloc_binding_uri) {
- const char *first = "<doc xmlns='http://example.org/'>\n"
- " <e xmlns='' />\n"
- "</doc>";
- const char *second
- = "<doc xmlns='http://example.org/long/enough/URI/to/reallocate/'>\n"
- " <e xmlns='' />\n"
- "</doc>";
- unsigned i;
- const unsigned max_realloc_count = 10;
-
- /* First, do a full parse that will leave bindings around */
- if (_XML_Parse_SINGLE_BYTES(g_parser, first, (int)strlen(first), XML_TRUE)
- == XML_STATUS_ERROR)
- xml_failure(g_parser);
-
- /* Now repeat with a longer URI and a duff reallocator */
- for (i = 0; i < max_realloc_count; i++) {
- XML_ParserReset(g_parser, NULL);
- reallocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, second, (int)strlen(second), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocation");
- else if (i == max_realloc_count)
- fail("Parsing failed at max reallocation count");
-}
-END_TEST
-
-/* Check handling of long prefix names (pool growth) */
-START_TEST(test_nsalloc_realloc_long_prefix) {
- const char *text
- = "<"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":foo xmlns:"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "='http://example.org/'>"
- "</"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":foo>";
- int i;
- const int max_realloc_count = 12;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_realloc_count)
- fail("Parsing failed even at max reallocation count");
-}
-END_TEST
-
-/* Check handling of even long prefix names (different code path) */
-START_TEST(test_nsalloc_realloc_longer_prefix) {
- const char *text
- = "<"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "Q:foo xmlns:"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "Q='http://example.org/'>"
- "</"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "Q:foo>";
- int i;
- const int max_realloc_count = 12;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_realloc_count)
- fail("Parsing failed even at max reallocation count");
-}
-END_TEST
-
-START_TEST(test_nsalloc_long_namespace) {
- const char *text1
- = "<"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":e xmlns:"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "='http://example.org/'>\n";
- const char *text2
- = "<"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":f "
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":attr='foo'/>\n"
- "</"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- ":e>";
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
- != XML_STATUS_ERROR
- && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
- XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-/* Using a slightly shorter namespace name provokes allocations in
- * slightly different places in the code.
- */
-START_TEST(test_nsalloc_less_long_namespace) {
- const char *text
- = "<"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
- ":e xmlns:"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
- "='http://example.org/'>\n"
- "<"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
- ":f "
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
- ":att='foo'/>\n"
- "</"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
- ":e>";
- int i;
- const int max_alloc_count = 40;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-START_TEST(test_nsalloc_long_context) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ATTLIST doc baz ID #REQUIRED>\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
- "' baz='2'>\n"
- "&en;"
- "</doc>";
- ExtOption options[] = {
- {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
- int i;
- const int max_alloc_count = 70;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
-
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-/* This function is void; it will throw a fail() on error, so if it
- * returns normally it must have succeeded.
- */
-static void
-context_realloc_test(const char *text) {
- ExtOption options[] = {
- {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
- int i;
- const int max_realloc_count = 6;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_realloc_count)
- fail("Parsing failed even at max reallocation count");
-}
-
-START_TEST(test_nsalloc_realloc_long_context) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
- "'>\n"
- "&en;"
- "</doc>";
-
- context_realloc_test(text);
-}
-END_TEST
-
-START_TEST(test_nsalloc_realloc_long_context_2) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJK"
- "'>\n"
- "&en;"
- "</doc>";
-
- context_realloc_test(text);
-}
-END_TEST
-
-START_TEST(test_nsalloc_realloc_long_context_3) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGH"
- "'>\n"
- "&en;"
- "</doc>";
-
- context_realloc_test(text);
-}
-END_TEST
-
-START_TEST(test_nsalloc_realloc_long_context_4) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO"
- "'>\n"
- "&en;"
- "</doc>";
-
- context_realloc_test(text);
-}
-END_TEST
-
-START_TEST(test_nsalloc_realloc_long_context_5) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABC"
- "'>\n"
- "&en;"
- "</doc>";
-
- context_realloc_test(text);
-}
-END_TEST
-
-START_TEST(test_nsalloc_realloc_long_context_6) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
- "'>\n"
- "&en;"
- "</doc>";
-
- context_realloc_test(text);
-}
-END_TEST
-
-START_TEST(test_nsalloc_realloc_long_context_7) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLM"
- "'>\n"
- "&en;"
- "</doc>";
-
- context_realloc_test(text);
-}
-END_TEST
-
-START_TEST(test_nsalloc_realloc_long_ge_name) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY "
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- " SYSTEM 'bar'>\n"
- "]>\n"
- "<doc xmlns='http://example.org/baz'>\n"
- "&"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- ";"
- "</doc>";
- ExtOption options[] = {
- {XCS("foo"), "<!ELEMENT el EMPTY>"}, {XCS("bar"), "<el/>"}, {NULL, NULL}};
- int i;
- const int max_realloc_count = 10;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_realloc_count)
- fail("Parsing failed even at max reallocation count");
-}
-END_TEST
-
-/* Test that when a namespace is passed through the context mechanism
- * to an external entity parser, the parsers handle reallocation
- * failures correctly. The prefix is exactly the right length to
- * provoke particular uncommon code paths.
- */
-START_TEST(test_nsalloc_realloc_long_context_in_dtd) {
- const char *text1
- = "<!DOCTYPE "
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- ":doc [\n"
- " <!ENTITY First SYSTEM 'foo/First'>\n"
- "]>\n"
- "<"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- ":doc xmlns:"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "='foo/Second'>&First;";
- const char *text2
- = "</"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- ":doc>";
- ExtOption options[] = {{XCS("foo/First"), "Hello world"}, {NULL, NULL}};
- int i;
- const int max_realloc_count = 20;
-
- for (i = 0; i < max_realloc_count; i++) {
- reallocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
- != XML_STATUS_ERROR
- && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
- XML_TRUE)
- != XML_STATUS_ERROR)
- break;
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing reallocations");
- else if (i == max_realloc_count)
- fail("Parsing failed even at max reallocation count");
-}
-END_TEST
-
-START_TEST(test_nsalloc_long_default_in_ext) {
- const char *text
- = "<!DOCTYPE doc [\n"
- " <!ATTLIST e a1 CDATA '"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
- "'>\n"
- " <!ENTITY x SYSTEM 'foo'>\n"
- "]>\n"
- "<doc>&x;</doc>";
- ExtOption options[] = {{XCS("foo"), "<e/>"}, {NULL, NULL}};
- int i;
- const int max_alloc_count = 50;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
-
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-START_TEST(test_nsalloc_long_systemid_in_ext) {
- const char *text
- = "<!DOCTYPE doc SYSTEM 'foo' [\n"
- " <!ENTITY en SYSTEM '"
- /* 64 characters per line */
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
- "'>\n"
- "]>\n"
- "<doc>&en;</doc>";
- ExtOption options[] = {
- {XCS("foo"), "<!ELEMENT e EMPTY>"},
- {/* clang-format off */
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
- XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"),
- /* clang-format on */
- "<e/>"},
- {NULL, NULL}};
- int i;
- const int max_alloc_count = 55;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
-
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Parsing worked despite failing allocations");
- else if (i == max_alloc_count)
- fail("Parsing failed even at max allocation count");
-}
-END_TEST
-
-/* Test the effects of allocation failure on parsing an element in a
- * namespace. Based on test_nsalloc_long_context.
- */
-START_TEST(test_nsalloc_prefixed_element) {
- const char *text = "<!DOCTYPE pfx:element SYSTEM 'foo' [\n"
- " <!ATTLIST pfx:element baz ID #REQUIRED>\n"
- " <!ENTITY en SYSTEM 'bar'>\n"
- "]>\n"
- "<pfx:element xmlns:pfx='http://example.org/' baz='2'>\n"
- "&en;"
- "</pfx:element>";
- ExtOption options[] = {
- {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
- int i;
- const int max_alloc_count = 70;
-
- for (i = 0; i < max_alloc_count; i++) {
- allocation_count = i;
- XML_SetUserData(g_parser, options);
- XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
- if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
- != XML_STATUS_ERROR)
- break;
-
- /* See comment in test_nsalloc_xmlns() */
- nsalloc_teardown();
- nsalloc_setup();
- }
- if (i == 0)
- fail("Success despite failing allocator");
- else if (i == max_alloc_count)
- fail("Failed even at full allocation count");
-}
-END_TEST
+XML_Parser g_parser = NULL;
static Suite *
make_suite(void) {
Suite *s = suite_create("basic");
- TCase *tc_basic = tcase_create("basic tests");
- TCase *tc_namespace = tcase_create("XML namespaces");
- TCase *tc_misc = tcase_create("miscellaneous tests");
- TCase *tc_alloc = tcase_create("allocation tests");
- TCase *tc_nsalloc = tcase_create("namespace allocation tests");
-
- suite_add_tcase(s, tc_basic);
- tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
- tcase_add_test(tc_basic, test_nul_byte);
- tcase_add_test(tc_basic, test_u0000_char);
- tcase_add_test(tc_basic, test_siphash_self);
- tcase_add_test(tc_basic, test_siphash_spec);
- tcase_add_test(tc_basic, test_bom_utf8);
- tcase_add_test(tc_basic, test_bom_utf16_be);
- tcase_add_test(tc_basic, test_bom_utf16_le);
- tcase_add_test(tc_basic, test_nobom_utf16_le);
- tcase_add_test(tc_basic, test_illegal_utf8);
- tcase_add_test(tc_basic, test_utf8_auto_align);
- tcase_add_test(tc_basic, test_utf16);
- tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
- tcase_add_test(tc_basic, test_not_utf16);
- tcase_add_test(tc_basic, test_bad_encoding);
- tcase_add_test(tc_basic, test_latin1_umlauts);
- tcase_add_test(tc_basic, test_long_utf8_character);
- tcase_add_test(tc_basic, test_long_latin1_attribute);
- tcase_add_test(tc_basic, test_long_ascii_attribute);
- /* Regression test for SF bug #491986. */
- tcase_add_test(tc_basic, test_danish_latin1);
- /* Regression test for SF bug #514281. */
- tcase_add_test(tc_basic, test_french_charref_hexidecimal);
- tcase_add_test(tc_basic, test_french_charref_decimal);
- tcase_add_test(tc_basic, test_french_latin1);
- tcase_add_test(tc_basic, test_french_utf8);
- tcase_add_test(tc_basic, test_utf8_false_rejection);
- tcase_add_test(tc_basic, test_line_number_after_parse);
- tcase_add_test(tc_basic, test_column_number_after_parse);
- tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
- tcase_add_test(tc_basic, test_line_number_after_error);
- tcase_add_test(tc_basic, test_column_number_after_error);
- tcase_add_test(tc_basic, test_really_long_lines);
- tcase_add_test(tc_basic, test_really_long_encoded_lines);
- tcase_add_test(tc_basic, test_end_element_events);
- tcase_add_test(tc_basic, test_attr_whitespace_normalization);
- tcase_add_test(tc_basic, test_xmldecl_misplaced);
- tcase_add_test(tc_basic, test_xmldecl_invalid);
- tcase_add_test(tc_basic, test_xmldecl_missing_attr);
- tcase_add_test(tc_basic, test_xmldecl_missing_value);
- tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
- tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
- tcase_add_test(tc_basic, test_wfc_undeclared_entity_unread_external_subset);
- tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
- tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
- tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
- tcase_add_test(tc_basic, test_not_standalone_handler_reject);
- tcase_add_test(tc_basic, test_not_standalone_handler_accept);
- tcase_add_test(tc_basic,
- test_wfc_undeclared_entity_with_external_subset_standalone);
- tcase_add_test(tc_basic, test_entity_with_external_subset_unless_standalone);
- tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
- tcase_add_test(tc_basic, test_ext_entity_set_encoding);
- tcase_add_test(tc_basic, test_ext_entity_no_handler);
- tcase_add_test(tc_basic, test_ext_entity_set_bom);
- tcase_add_test(tc_basic, test_ext_entity_bad_encoding);
- tcase_add_test(tc_basic, test_ext_entity_bad_encoding_2);
- tcase_add_test(tc_basic, test_ext_entity_invalid_parse);
- tcase_add_test(tc_basic, test_ext_entity_invalid_suspended_parse);
- tcase_add_test(tc_basic, test_dtd_default_handling);
- tcase_add_test(tc_basic, test_dtd_attr_handling);
- tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
- tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
- tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
- tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
- tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls);
- tcase_add_test(tc_basic, test_good_cdata_ascii);
- tcase_add_test(tc_basic, test_good_cdata_utf16);
- tcase_add_test(tc_basic, test_good_cdata_utf16_le);
- tcase_add_test(tc_basic, test_long_cdata_utf16);
-#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
- tcase_add_test(tc_basic, test_multichar_cdata_utf16);
-#endif
- tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair);
- tcase_add_test(tc_basic, test_bad_cdata);
-#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
- tcase_add_test(tc_basic, test_bad_cdata_utf16);
-#endif
- tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls);
- tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls);
- tcase_add_test(tc_basic, test_memory_allocation);
- tcase_add_test(tc_basic, test_default_current);
- tcase_add_test(tc_basic, test_dtd_elements);
- tcase_add_test(tc_basic, test_set_foreign_dtd);
- tcase_add_test(tc_basic, test_foreign_dtd_not_standalone);
- tcase_add_test(tc_basic, test_invalid_foreign_dtd);
- tcase_add_test(tc_basic, test_foreign_dtd_with_doctype);
- tcase_add_test(tc_basic, test_foreign_dtd_without_external_subset);
- tcase_add_test(tc_basic, test_empty_foreign_dtd);
- tcase_add_test(tc_basic, test_set_base);
- tcase_add_test(tc_basic, test_attributes);
- tcase_add_test(tc_basic, test_reset_in_entity);
- tcase_add_test(tc_basic, test_resume_invalid_parse);
- tcase_add_test(tc_basic, test_resume_resuspended);
- tcase_add_test(tc_basic, test_cdata_default);
- tcase_add_test(tc_basic, test_subordinate_reset);
- tcase_add_test(tc_basic, test_subordinate_suspend);
- tcase_add_test(tc_basic, test_subordinate_xdecl_suspend);
- tcase_add_test(tc_basic, test_subordinate_xdecl_abort);
- tcase_add_test(tc_basic, test_explicit_encoding);
- tcase_add_test(tc_basic, test_trailing_cr);
- tcase_add_test(tc_basic, test_ext_entity_trailing_cr);
- tcase_add_test(tc_basic, test_trailing_rsqb);
- tcase_add_test(tc_basic, test_ext_entity_trailing_rsqb);
- tcase_add_test(tc_basic, test_ext_entity_good_cdata);
- tcase_add_test(tc_basic, test_user_parameters);
- tcase_add_test(tc_basic, test_ext_entity_ref_parameter);
- tcase_add_test(tc_basic, test_empty_parse);
- tcase_add_test(tc_basic, test_get_buffer_1);
- tcase_add_test(tc_basic, test_get_buffer_2);
- tcase_add_test(tc_basic, test_byte_info_at_end);
- tcase_add_test(tc_basic, test_byte_info_at_error);
- tcase_add_test(tc_basic, test_byte_info_at_cdata);
- tcase_add_test(tc_basic, test_predefined_entities);
- tcase_add_test(tc_basic, test_invalid_tag_in_dtd);
- tcase_add_test(tc_basic, test_not_predefined_entities);
- tcase_add_test(tc_basic, test_ignore_section);
- tcase_add_test(tc_basic, test_ignore_section_utf16);
- tcase_add_test(tc_basic, test_ignore_section_utf16_be);
- tcase_add_test(tc_basic, test_bad_ignore_section);
- tcase_add_test(tc_basic, test_external_entity_values);
- tcase_add_test(tc_basic, test_ext_entity_not_standalone);
- tcase_add_test(tc_basic, test_ext_entity_value_abort);
- tcase_add_test(tc_basic, test_bad_public_doctype);
- tcase_add_test(tc_basic, test_attribute_enum_value);
- tcase_add_test(tc_basic, test_predefined_entity_redefinition);
- tcase_add_test(tc_basic, test_dtd_stop_processing);
- tcase_add_test(tc_basic, test_public_notation_no_sysid);
- tcase_add_test(tc_basic, test_nested_groups);
- tcase_add_test(tc_basic, test_group_choice);
- tcase_add_test(tc_basic, test_standalone_parameter_entity);
- tcase_add_test(tc_basic, test_skipped_parameter_entity);
- tcase_add_test(tc_basic, test_recursive_external_parameter_entity);
- tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd);
- tcase_add_test(tc_basic, test_suspend_xdecl);
- tcase_add_test(tc_basic, test_abort_epilog);
- tcase_add_test(tc_basic, test_abort_epilog_2);
- tcase_add_test(tc_basic, test_suspend_epilog);
- tcase_add_test(tc_basic, test_suspend_in_sole_empty_tag);
- tcase_add_test(tc_basic, test_unfinished_epilog);
- tcase_add_test(tc_basic, test_partial_char_in_epilog);
- tcase_add_test(tc_basic, test_hash_collision);
- tcase_add_test(tc_basic, test_suspend_resume_internal_entity);
- tcase_add_test(tc_basic, test_resume_entity_with_syntax_error);
- tcase_add_test(tc_basic, test_suspend_resume_parameter_entity);
- tcase_add_test(tc_basic, test_restart_on_error);
- tcase_add_test(tc_basic, test_reject_lt_in_attribute_value);
- tcase_add_test(tc_basic, test_reject_unfinished_param_in_att_value);
- tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
- tcase_add_test(tc_basic, test_standalone_internal_entity);
- tcase_add_test(tc_basic, test_skipped_external_entity);
- tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
- tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
- tcase_add_test(tc_basic, test_param_entity_with_trailing_cr);
- tcase_add_test(tc_basic, test_invalid_character_entity);
- tcase_add_test(tc_basic, test_invalid_character_entity_2);
- tcase_add_test(tc_basic, test_invalid_character_entity_3);
- tcase_add_test(tc_basic, test_invalid_character_entity_4);
- tcase_add_test(tc_basic, test_pi_handled_in_default);
- tcase_add_test(tc_basic, test_comment_handled_in_default);
- tcase_add_test(tc_basic, test_pi_yml);
- tcase_add_test(tc_basic, test_pi_xnl);
- tcase_add_test(tc_basic, test_pi_xmm);
- tcase_add_test(tc_basic, test_utf16_pi);
- tcase_add_test(tc_basic, test_utf16_be_pi);
- tcase_add_test(tc_basic, test_utf16_be_comment);
- tcase_add_test(tc_basic, test_utf16_le_comment);
- tcase_add_test(tc_basic, test_missing_encoding_conversion_fn);
- tcase_add_test(tc_basic, test_failing_encoding_conversion_fn);
- tcase_add_test(tc_basic, test_unknown_encoding_success);
- tcase_add_test(tc_basic, test_unknown_encoding_bad_name);
- tcase_add_test(tc_basic, test_unknown_encoding_bad_name_2);
- tcase_add_test(tc_basic, test_unknown_encoding_long_name_1);
- tcase_add_test(tc_basic, test_unknown_encoding_long_name_2);
- tcase_add_test(tc_basic, test_invalid_unknown_encoding);
- tcase_add_test(tc_basic, test_unknown_ascii_encoding_ok);
- tcase_add_test(tc_basic, test_unknown_ascii_encoding_fail);
- tcase_add_test(tc_basic, test_unknown_encoding_invalid_length);
- tcase_add_test(tc_basic, test_unknown_encoding_invalid_topbit);
- tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate);
- tcase_add_test(tc_basic, test_unknown_encoding_invalid_high);
- tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value);
- tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom);
- tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom);
- tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom2);
- tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom2);
- tcase_add_test(tc_basic, test_ext_entity_utf16_be);
- tcase_add_test(tc_basic, test_ext_entity_utf16_le);
- tcase_add_test(tc_basic, test_ext_entity_utf16_unknown);
- tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
- tcase_add_test(tc_basic, test_utf8_in_cdata_section);
- tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
- tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
- tcase_add_test(tc_basic, test_utf16_attribute);
- tcase_add_test(tc_basic, test_utf16_second_attr);
- tcase_add_test(tc_basic, test_attr_after_solidus);
- tcase_add_test(tc_basic, test_utf16_pe);
- tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
- tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
- tcase_add_test(tc_basic, test_bad_doctype);
- tcase_add_test(tc_basic, test_bad_doctype_utf16);
- tcase_add_test(tc_basic, test_bad_doctype_plus);
- tcase_add_test(tc_basic, test_bad_doctype_star);
- tcase_add_test(tc_basic, test_bad_doctype_query);
- tcase_add_test(tc_basic, test_unknown_encoding_bad_ignore);
- tcase_add_test(tc_basic, test_entity_in_utf16_be_attr);
- tcase_add_test(tc_basic, test_entity_in_utf16_le_attr);
- tcase_add_test(tc_basic, test_entity_public_utf16_be);
- tcase_add_test(tc_basic, test_entity_public_utf16_le);
- tcase_add_test(tc_basic, test_short_doctype);
- tcase_add_test(tc_basic, test_short_doctype_2);
- tcase_add_test(tc_basic, test_short_doctype_3);
- tcase_add_test(tc_basic, test_long_doctype);
- tcase_add_test(tc_basic, test_bad_entity);
- tcase_add_test(tc_basic, test_bad_entity_2);
- tcase_add_test(tc_basic, test_bad_entity_3);
- tcase_add_test(tc_basic, test_bad_entity_4);
- tcase_add_test(tc_basic, test_bad_notation);
- tcase_add_test(tc_basic, test_default_doctype_handler);
- tcase_add_test(tc_basic, test_empty_element_abort);
-
- suite_add_tcase(s, tc_namespace);
- tcase_add_checked_fixture(tc_namespace, namespace_setup, namespace_teardown);
- tcase_add_test(tc_namespace, test_return_ns_triplet);
- tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
- tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
- tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
- tcase_add_test(tc_namespace, test_default_ns_from_ext_subset_and_ext_ge);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
- tcase_add_test(tc_namespace, test_ns_unbound_prefix);
- tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
- tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
- tcase_add_test(tc_namespace, test_ns_duplicate_hashes);
- tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
- tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
- tcase_add_test(tc_namespace, test_ns_parser_reset);
- tcase_add_test(tc_namespace, test_ns_long_element);
- tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts);
- tcase_add_test(tc_namespace, test_ns_extend_uri_buffer);
- tcase_add_test(tc_namespace, test_ns_reserved_attributes);
- tcase_add_test(tc_namespace, test_ns_reserved_attributes_2);
- tcase_add_test(tc_namespace, test_ns_extremely_long_prefix);
- tcase_add_test(tc_namespace, test_ns_unknown_encoding_success);
- tcase_add_test(tc_namespace, test_ns_double_colon);
- tcase_add_test(tc_namespace, test_ns_double_colon_element);
- tcase_add_test(tc_namespace, test_ns_bad_attr_leafname);
- tcase_add_test(tc_namespace, test_ns_bad_element_leafname);
- tcase_add_test(tc_namespace, test_ns_utf16_leafname);
- tcase_add_test(tc_namespace, test_ns_utf16_element_leafname);
- tcase_add_test(tc_namespace, test_ns_utf16_doctype);
- tcase_add_test(tc_namespace, test_ns_invalid_doctype);
- tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
- suite_add_tcase(s, tc_misc);
- tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
- tcase_add_test(tc_misc, test_misc_alloc_create_parser);
- tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding);
- tcase_add_test(tc_misc, test_misc_null_parser);
- tcase_add_test(tc_misc, test_misc_error_string);
- tcase_add_test(tc_misc, test_misc_version);
- tcase_add_test(tc_misc, test_misc_features);
- tcase_add_test(tc_misc, test_misc_attribute_leak);
- tcase_add_test(tc_misc, test_misc_utf16le);
- tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_1);
- tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2);
-#ifdef XML_DTD
- tcase_add_test(tc_misc,
- test_misc_deny_internal_entity_closing_doctype_issue_317);
+ make_basic_test_case(s);
+ make_namespace_test_case(s);
+ make_miscellaneous_test_case(s);
+ make_alloc_test_case(s);
+ make_nsalloc_test_case(s);
+#if XML_GE == 1
+ make_accounting_test_case(s);
#endif
- suite_add_tcase(s, tc_alloc);
- tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
- tcase_add_test(tc_alloc, test_alloc_parse_xdecl);
- tcase_add_test(tc_alloc, test_alloc_parse_xdecl_2);
- tcase_add_test(tc_alloc, test_alloc_parse_pi);
- tcase_add_test(tc_alloc, test_alloc_parse_pi_2);
- tcase_add_test(tc_alloc, test_alloc_parse_pi_3);
- tcase_add_test(tc_alloc, test_alloc_parse_comment);
- tcase_add_test(tc_alloc, test_alloc_parse_comment_2);
- tcase_add_test(tc_alloc, test_alloc_create_external_parser);
- tcase_add_test(tc_alloc, test_alloc_run_external_parser);
- tcase_add_test(tc_alloc, test_alloc_dtd_copy_default_atts);
- tcase_add_test(tc_alloc, test_alloc_external_entity);
- tcase_add_test(tc_alloc, test_alloc_ext_entity_set_encoding);
- tcase_add_test(tc_alloc, test_alloc_internal_entity);
- tcase_add_test(tc_alloc, test_alloc_dtd_default_handling);
- tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
- tcase_add_test(tc_alloc, test_alloc_set_base);
- tcase_add_test(tc_alloc, test_alloc_realloc_buffer);
- tcase_add_test(tc_alloc, test_alloc_ext_entity_realloc_buffer);
- tcase_add_test(tc_alloc, test_alloc_realloc_many_attributes);
- tcase_add_test(tc_alloc, test_alloc_public_entity_value);
- tcase_add_test(tc_alloc, test_alloc_realloc_subst_public_entity_value);
- tcase_add_test(tc_alloc, test_alloc_parse_public_doctype);
- tcase_add_test(tc_alloc, test_alloc_parse_public_doctype_long_name);
- tcase_add_test(tc_alloc, test_alloc_set_foreign_dtd);
- tcase_add_test(tc_alloc, test_alloc_attribute_enum_value);
- tcase_add_test(tc_alloc, test_alloc_realloc_attribute_enum_value);
- tcase_add_test(tc_alloc, test_alloc_realloc_implied_attribute);
- tcase_add_test(tc_alloc, test_alloc_realloc_default_attribute);
- tcase_add_test(tc_alloc, test_alloc_notation);
- tcase_add_test(tc_alloc, test_alloc_public_notation);
- tcase_add_test(tc_alloc, test_alloc_system_notation);
- tcase_add_test(tc_alloc, test_alloc_nested_groups);
- tcase_add_test(tc_alloc, test_alloc_realloc_nested_groups);
- tcase_add_test(tc_alloc, test_alloc_large_group);
- tcase_add_test(tc_alloc, test_alloc_realloc_group_choice);
- tcase_add_test(tc_alloc, test_alloc_pi_in_epilog);
- tcase_add_test(tc_alloc, test_alloc_comment_in_epilog);
- tcase_add_test(tc_alloc, test_alloc_realloc_long_attribute_value);
- tcase_add_test(tc_alloc, test_alloc_attribute_whitespace);
- tcase_add_test(tc_alloc, test_alloc_attribute_predefined_entity);
- tcase_add_test(tc_alloc, test_alloc_long_attr_default_with_char_ref);
- tcase_add_test(tc_alloc, test_alloc_long_attr_value);
- tcase_add_test(tc_alloc, test_alloc_nested_entities);
- tcase_add_test(tc_alloc, test_alloc_realloc_param_entity_newline);
- tcase_add_test(tc_alloc, test_alloc_realloc_ce_extends_pe);
- tcase_add_test(tc_alloc, test_alloc_realloc_attributes);
- tcase_add_test(tc_alloc, test_alloc_long_doc_name);
- tcase_add_test(tc_alloc, test_alloc_long_base);
- tcase_add_test(tc_alloc, test_alloc_long_public_id);
- tcase_add_test(tc_alloc, test_alloc_long_entity_value);
- tcase_add_test(tc_alloc, test_alloc_long_notation);
-
- suite_add_tcase(s, tc_nsalloc);
- tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown);
- tcase_add_test(tc_nsalloc, test_nsalloc_xmlns);
- tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_uri);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_attr);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_element);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_binding_uri);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_prefix);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_longer_prefix);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_namespace);
- tcase_add_test(tc_nsalloc, test_nsalloc_less_long_namespace);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_context);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_2);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_3);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_4);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_5);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_6);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_7);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_ge_name);
- tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_in_dtd);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_default_in_ext);
- tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
- tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
-
return s;
}
@@ -11573,9 +84,6 @@ main(int argc, char *argv[]) {
Suite *s = make_suite();
SRunner *sr = srunner_create(s);
- /* run the tests for internal helper functions */
- testhelper_is_whitespace_normalized();
-
for (i = 1; i < argc; ++i) {
char *opt = argv[i];
if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
@@ -11589,7 +97,18 @@ main(int argc, char *argv[]) {
}
if (verbosity != CK_SILENT)
printf("Expat version: %" XML_FMT_STR "\n", XML_ExpatVersion());
- srunner_run_all(sr, verbosity);
+
+ for (g_chunkSize = 0; g_chunkSize <= 5; g_chunkSize++) {
+ for (int enabled = 0; enabled <= 1; ++enabled) {
+ char context[100];
+ g_reparseDeferralEnabledDefault = enabled;
+ snprintf(context, sizeof(context), "chunksize=%d deferral=%d",
+ g_chunkSize, enabled);
+ context[sizeof(context) - 1] = '\0';
+ srunner_run_all(sr, context, verbosity);
+ }
+ }
+ srunner_summarize(sr, verbosity);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
diff --git a/contrib/expat/tests/runtests.sln b/contrib/expat/tests/runtests.sln
deleted file mode 100644
index 6e07293f580c..000000000000
--- a/contrib/expat/tests/runtests.sln
+++ /dev/null
@@ -1,24 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.40629.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runtests", "runtests.vcxproj", "{63D6D820-B526-4A5F-9605-9B8551FAC591}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- Template|Win32 = Template|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {63D6D820-B526-4A5F-9605-9B8551FAC591}.Debug|Win32.ActiveCfg = Debug|Win32
- {63D6D820-B526-4A5F-9605-9B8551FAC591}.Debug|Win32.Build.0 = Debug|Win32
- {63D6D820-B526-4A5F-9605-9B8551FAC591}.Release|Win32.ActiveCfg = Release|Win32
- {63D6D820-B526-4A5F-9605-9B8551FAC591}.Release|Win32.Build.0 = Release|Win32
- {63D6D820-B526-4A5F-9605-9B8551FAC591}.Template|Win32.ActiveCfg = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/contrib/expat/tests/runtestspp.cpp b/contrib/expat/tests/runtests_cxx.cpp
index fd3ceaa97a39..396714560a06 100644
--- a/contrib/expat/tests/runtestspp.cpp
+++ b/contrib/expat/tests/runtests_cxx.cpp
@@ -9,8 +9,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/tests/structdata.c b/contrib/expat/tests/structdata.c
index e81b7b184601..e311f1fae3a9 100644
--- a/contrib/expat/tests/structdata.c
+++ b/contrib/expat/tests/structdata.c
@@ -6,8 +6,9 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,10 +31,12 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifdef HAVE_EXPAT_CONFIG_H
-# include "expat_config.h"
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
#endif
+#include "expat_config.h"
+
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
@@ -58,7 +61,7 @@
static XML_Char *
xmlstrdup(const XML_Char *s) {
size_t byte_count = (xcstrlen(s) + 1) * sizeof(XML_Char);
- XML_Char *dup = malloc(byte_count);
+ XML_Char *const dup = (XML_Char *)malloc(byte_count);
assert(dup != NULL);
memcpy(dup, s, byte_count);
@@ -81,13 +84,13 @@ StructData_AddItem(StructData *storage, const XML_Char *s, int data0, int data1,
assert(storage != NULL);
assert(s != NULL);
if (storage->count == storage->max_count) {
- StructDataEntry *new;
+ StructDataEntry *new_entries;
storage->max_count += STRUCT_EXTENSION_COUNT;
- new = realloc(storage->entries,
- storage->max_count * sizeof(StructDataEntry));
- assert(new != NULL);
- storage->entries = new;
+ new_entries = (StructDataEntry *)realloc(
+ storage->entries, storage->max_count * sizeof(StructDataEntry));
+ assert(new_entries != NULL);
+ storage->entries = new_entries;
}
entry = &storage->entries[storage->count];
@@ -105,17 +108,17 @@ void
StructData_CheckItems(StructData *storage, const StructDataEntry *expected,
int count) {
char buffer[1024];
- int i;
assert(storage != NULL);
assert(expected != NULL);
if (count != storage->count) {
- sprintf(buffer, "wrong number of entries: got %d, expected %d",
- storage->count, count);
+ snprintf(buffer, sizeof(buffer),
+ "wrong number of entries: got %d, expected %d", storage->count,
+ count);
StructData_Dispose(storage);
fail(buffer);
} else {
- for (i = 0; i < count; i++) {
+ for (int i = 0; i < count; i++) {
const StructDataEntry *got = &storage->entries[i];
const StructDataEntry *want = &expected[i];
@@ -128,11 +131,11 @@ StructData_CheckItems(StructData *storage, const StructDataEntry *expected,
} else {
if (got->data0 != want->data0 || got->data1 != want->data1
|| got->data2 != want->data2) {
- sprintf(buffer,
- "struct '%" XML_FMT_STR
- "' expected (%d,%d,%d), got (%d,%d,%d)",
- got->str, want->data0, want->data1, want->data2, got->data0,
- got->data1, got->data2);
+ snprintf(buffer, sizeof(buffer),
+ "struct '%" XML_FMT_STR
+ "' expected (%d,%d,%d), got (%d,%d,%d)",
+ got->str, want->data0, want->data1, want->data2, got->data0,
+ got->data1, got->data2);
StructData_Dispose(storage);
fail(buffer);
}
diff --git a/contrib/expat/tests/structdata.h b/contrib/expat/tests/structdata.h
index 870ffaf2af05..09881b175f75 100644
--- a/contrib/expat/tests/structdata.h
+++ b/contrib/expat/tests/structdata.h
@@ -7,8 +7,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/tests/structdata_cxx.cpp b/contrib/expat/tests/structdata_cxx.cpp
new file mode 100644
index 000000000000..43448f634057
--- /dev/null
+++ b/contrib/expat/tests/structdata_cxx.cpp
@@ -0,0 +1,32 @@
+/* C++ compilation harness for the test suite.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "structdata.c"
diff --git a/contrib/expat/tests/udiffer.py b/contrib/expat/tests/udiffer.py
index 6fb91be7e3d0..2b58a4c34860 100755
--- a/contrib/expat/tests/udiffer.py
+++ b/contrib/expat/tests/udiffer.py
@@ -6,7 +6,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+# Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/tests/xmltest.sh b/contrib/expat/tests/xmltest.sh
index 9b5003511430..dc409d01e456 100755
--- a/contrib/expat/tests/xmltest.sh
+++ b/contrib/expat/tests/xmltest.sh
@@ -1,24 +1,55 @@
#! /usr/bin/env bash
-
-# EXPAT TEST SCRIPT FOR W3C XML TEST SUITE
-
+# EXPAT TEST SCRIPT FOR W3C XML TEST SUITE
+#
# This script can be used to exercise Expat against the
# w3c.org xml test suite, available from
# http://www.w3.org/XML/Test/xmlts20020606.zip.
-
+#
# To run this script, first set XMLWF below so that xmlwf can be
# found, then set the output directory with OUTPUT.
-
+#
# The script lists all test cases where Expat shows a discrepancy
# from the expected result. Test cases where only the canonical
# output differs are prefixed with "Output differs:", and a diff file
# is generated in the appropriate subdirectory under $OUTPUT.
-
+#
# If there are output files provided, the script will use
# output from xmlwf and compare the desired output against it.
# However, one has to take into account that the canonical output
# produced by xmlwf conforms to an older definition of canonical XML
# and does not generate notation declarations.
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2002-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+# Copyright (c) 2002 Karl Waclawek <karl@waclawek.net>
+# Copyright (c) 2008-2019 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
shopt -s nullglob
diff --git a/contrib/expat/xmlwf/Makefile.am b/contrib/expat/xmlwf/Makefile.am
index 4b41c2cbdab8..c7eebd1eeec2 100644
--- a/contrib/expat/xmlwf/Makefile.am
+++ b/contrib/expat/xmlwf/Makefile.am
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2021 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -37,12 +37,13 @@ xmlwf_SOURCES = \
codepage.c \
@FILEMAP@.c
-xmlwf_CPPFLAGS = -I$(srcdir)/../lib
+xmlwf_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+xmlwf_LDFLAGS = @AM_LDFLAGS@ @LIBM@
if MINGW
if UNICODE
xmlwf_CPPFLAGS += -mwindows
-xmlwf_LDFLAGS = -municode
+xmlwf_LDFLAGS += -municode
endif
endif
diff --git a/contrib/expat/xmlwf/Makefile.in b/contrib/expat/xmlwf/Makefile.in
index 368d3777431d..a8a84dc4e6de 100644
--- a/contrib/expat/xmlwf/Makefile.in
+++ b/contrib/expat/xmlwf/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Expat development team
+# Copyright (c) 2017-2021 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -120,6 +120,7 @@ build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = xmlwf$(EXEEXT)
@MINGW_TRUE@@UNICODE_TRUE@am__append_1 = -mwindows
+@MINGW_TRUE@@UNICODE_TRUE@am__append_2 = -municode
subdir = xmlwf
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
@@ -133,6 +134,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/conftools/ax-append-compile-flags.m4 \
$(top_srcdir)/conftools/ax-append-link-flags.m4 \
$(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx.m4 \
+ $(top_srcdir)/conftools/ax-cxx-compile-stdcxx-11.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -215,14 +218,16 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in \
$(top_srcdir)/conftools/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
@@ -232,8 +237,10 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CPP = @CPP@
+CMAKE_SHARED_LIBRARY_PREFIX = @CMAKE_SHARED_LIBRARY_PREFIX@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -249,10 +256,20 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
+EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
+EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
+EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
+EXPAT_DTD = @EXPAT_DTD@
+EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
+EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
+EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FILEMAP = @FILEMAP@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -262,6 +279,8 @@ LD = @LD@
LDFLAGS = @LDFLAGS@
LIBAGE = @LIBAGE@
LIBCURRENT = @LIBCURRENT@
+LIBDIR_BASENAME = @LIBDIR_BASENAME@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBREVISION = @LIBREVISION@
LIBS = @LIBS@
@@ -270,6 +289,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -291,6 +311,9 @@ RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SO_MAJOR = @SO_MAJOR@
+SO_MINOR = @SO_MINOR@
+SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
@@ -301,6 +324,7 @@ ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_void_p = @ac_cv_sizeof_void_p@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -338,6 +362,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -353,8 +378,8 @@ xmlwf_SOURCES = \
codepage.c \
@FILEMAP@.c
-xmlwf_CPPFLAGS = -I$(srcdir)/../lib $(am__append_1)
-@MINGW_TRUE@@UNICODE_TRUE@xmlwf_LDFLAGS = -municode
+xmlwf_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib $(am__append_1)
+xmlwf_LDFLAGS = @AM_LDFLAGS@ @LIBM@ $(am__append_2)
EXTRA_DIST = \
codepage.h \
ct.c \
@@ -371,7 +396,7 @@ all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -395,9 +420,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: $(am__configure_deps)
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-binPROGRAMS: $(bin_PROGRAMS)
@@ -605,7 +630,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
diff --git a/contrib/expat/xmlwf/codepage.c b/contrib/expat/xmlwf/codepage.c
index 1095adf63eb2..8e0b5d199cdd 100644
--- a/contrib/expat/xmlwf/codepage.c
+++ b/contrib/expat/xmlwf/codepage.c
@@ -7,7 +7,11 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2005-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2019 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -38,9 +42,11 @@
# define WIN32_LEAN_AND_MEAN 1
# include <windows.h>
+#endif /* defined(_WIN32) */
int
codepageMap(int cp, int *map) {
+#if defined(_WIN32)
int i;
CPINFO info;
if (! GetCPInfo(cp, &info) || info.MaxCharSize > 2)
@@ -68,32 +74,25 @@ codepageMap(int cp, int *map) {
}
}
return 1;
+#else
+ UNUSED_P(cp);
+ UNUSED_P(map);
+ return 0;
+#endif
}
int
codepageConvert(int cp, const char *p) {
+#if defined(_WIN32)
unsigned short c;
if (MultiByteToWideChar(cp, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, p, 2, &c,
1)
== 1)
return c;
return -1;
-}
-
-#else /* not _WIN32 */
-
-int
-codepageMap(int cp, int *map) {
- UNUSED_P(cp);
- UNUSED_P(map);
- return 0;
-}
-
-int
-codepageConvert(int cp, const char *p) {
+#else
UNUSED_P(cp);
UNUSED_P(p);
return -1;
+#endif
}
-
-#endif /* not _WIN32 */
diff --git a/contrib/expat/xmlwf/codepage.h b/contrib/expat/xmlwf/codepage.h
index 1b75d58365f4..75ddbce4a456 100644
--- a/contrib/expat/xmlwf/codepage.h
+++ b/contrib/expat/xmlwf/codepage.h
@@ -7,7 +7,9 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2016-2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/xmlwf/ct.c b/contrib/expat/xmlwf/ct.c
index dcf92bab568b..d4c0e7a0a95d 100644
--- a/contrib/expat/xmlwf/ct.c
+++ b/contrib/expat/xmlwf/ct.c
@@ -7,7 +7,8 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2016-2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/xmlwf/filemap.h b/contrib/expat/xmlwf/filemap.h
index ef66114422f3..5e0c70fa99b6 100644
--- a/contrib/expat/xmlwf/filemap.h
+++ b/contrib/expat/xmlwf/filemap.h
@@ -7,7 +7,9 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2016-2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/xmlwf/readfilemap.c b/contrib/expat/xmlwf/readfilemap.c
index d5b84f995ad4..2cb53feef8d5 100644
--- a/contrib/expat/xmlwf/readfilemap.c
+++ b/contrib/expat/xmlwf/readfilemap.c
@@ -7,7 +7,13 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2001-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2002-2009 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2017 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2017 Franek Korta <fkorta@gmail.com>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -45,14 +51,14 @@
#if defined(_MSC_VER)
# include <io.h>
/* https://msdn.microsoft.com/en-us/library/wyssk1bs(v=vs.100).aspx */
-# define _EXPAT_read _read
-# define _EXPAT_read_count_t int
-# define _EXPAT_read_req_t unsigned int
+# define EXPAT_read _read
+# define EXPAT_read_count_t int
+# define EXPAT_read_req_t unsigned int
#else /* POSIX */
/* http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html */
-# define _EXPAT_read read
-# define _EXPAT_read_count_t ssize_t
-# define _EXPAT_read_req_t size_t
+# define EXPAT_read read
+# define EXPAT_read_count_t ssize_t
+# define EXPAT_read_req_t size_t
#endif
#ifndef S_ISREG
@@ -62,7 +68,7 @@
# ifndef S_IFMT
# define S_IFMT _S_IFMT
# endif
-# define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif /* not S_ISREG */
#ifndef O_BINARY
@@ -82,7 +88,7 @@ filemap(const tchar *name,
void *arg) {
size_t nbytes;
int fd;
- _EXPAT_read_count_t n;
+ EXPAT_read_count_t n;
struct stat sb;
void *p;
@@ -120,14 +126,14 @@ filemap(const tchar *name,
close(fd);
return 0;
}
- n = _EXPAT_read(fd, p, (_EXPAT_read_req_t)nbytes);
+ n = EXPAT_read(fd, p, (EXPAT_read_req_t)nbytes);
if (n < 0) {
tperror(name);
free(p);
close(fd);
return 0;
}
- if (n != (_EXPAT_read_count_t)nbytes) {
+ if (n != (EXPAT_read_count_t)nbytes) {
ftprintf(stderr, T("%s: read unexpected number of bytes\n"), name);
free(p);
close(fd);
diff --git a/contrib/expat/xmlwf/unixfilemap.c b/contrib/expat/xmlwf/unixfilemap.c
index 0d0dc0424dc0..d0ce9cc60a8a 100644
--- a/contrib/expat/xmlwf/unixfilemap.c
+++ b/contrib/expat/xmlwf/unixfilemap.c
@@ -7,7 +7,11 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2001-2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2017 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/xmlwf/win32filemap.c b/contrib/expat/xmlwf/win32filemap.c
index 0c9b7ecc5ffb..a2db8eafc43c 100644
--- a/contrib/expat/xmlwf/win32filemap.c
+++ b/contrib/expat/xmlwf/win32filemap.c
@@ -7,7 +7,10 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2022 Martin Ettl <ettl.martin78@googlemail.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -105,7 +108,7 @@ filemap(const TCHAR *name,
static void
win32perror(const TCHAR *s) {
- LPVOID buf;
+ LPVOID buf = NULL;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0,
diff --git a/contrib/expat/xmlwf/xmlfile.c b/contrib/expat/xmlwf/xmlfile.c
index 922e18b0b7e2..0598b86b5fb7 100644
--- a/contrib/expat/xmlwf/xmlfile.c
+++ b/contrib/expat/xmlwf/xmlfile.c
@@ -7,7 +7,14 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2004-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2021 Donghee Na <donghee.na@python.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,6 +37,8 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "expat_config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -38,9 +47,7 @@
#ifdef _WIN32
# include "winconfig.h"
-#elif defined(HAVE_EXPAT_CONFIG_H)
-# include <expat_config.h>
-#endif /* ndef _WIN32 */
+#endif
#include "expat.h"
#include "internal.h" /* for UNUSED_P only */
@@ -64,11 +71,7 @@
# endif
#endif
-#ifdef _DEBUG
-# define READ_SIZE 16
-#else
-# define READ_SIZE (1024 * 8)
-#endif
+int g_read_size_bytes = 1024 * 8;
typedef struct {
XML_Parser parser;
@@ -176,7 +179,7 @@ externalEntityRefFilemap(XML_Parser parser, const XML_Char *context,
static int
processStream(const XML_Char *filename, XML_Parser parser) {
- /* passing NULL for filename means read intput from stdin */
+ /* passing NULL for filename means read input from stdin */
int fd = 0; /* 0 is the fileno for stdin */
if (filename != NULL) {
@@ -188,7 +191,7 @@ processStream(const XML_Char *filename, XML_Parser parser) {
}
for (;;) {
int nread;
- char *buf = (char *)XML_GetBuffer(parser, READ_SIZE);
+ char *buf = (char *)XML_GetBuffer(parser, g_read_size_bytes);
if (! buf) {
if (filename != NULL)
close(fd);
@@ -196,7 +199,7 @@ processStream(const XML_Char *filename, XML_Parser parser) {
filename != NULL ? filename : T("xmlwf"));
return 0;
}
- nread = read(fd, buf, READ_SIZE);
+ nread = read(fd, buf, g_read_size_bytes);
if (nread < 0) {
tperror(filename != NULL ? filename : T("STDIN"));
if (filename != NULL)
diff --git a/contrib/expat/xmlwf/xmlfile.h b/contrib/expat/xmlwf/xmlfile.h
index 6e5d5b49eb78..579201ccf498 100644
--- a/contrib/expat/xmlwf/xmlfile.h
+++ b/contrib/expat/xmlwf/xmlfile.h
@@ -7,7 +7,10 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2005 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -39,5 +42,7 @@
# define XML_FMT_INT_MOD "l"
#endif
+extern int g_read_size_bytes;
+
extern int XML_ProcessFile(XML_Parser parser, const XML_Char *filename,
unsigned flags);
diff --git a/contrib/expat/xmlwf/xmlmime.c b/contrib/expat/xmlwf/xmlmime.c
index 39160d7198ce..883e293dac4f 100644
--- a/contrib/expat/xmlwf/xmlmime.c
+++ b/contrib/expat/xmlwf/xmlmime.c
@@ -7,7 +7,9 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2016-2018 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/xmlwf/xmlmime.h b/contrib/expat/xmlwf/xmlmime.h
index 0471286234a1..591a8847760c 100644
--- a/contrib/expat/xmlwf/xmlmime.h
+++ b/contrib/expat/xmlwf/xmlmime.h
@@ -7,7 +7,8 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2016-2017 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/contrib/expat/xmlwf/xmltchar.h b/contrib/expat/xmlwf/xmltchar.h
index d7e7b411b44b..30283d086dde 100644
--- a/contrib/expat/xmlwf/xmltchar.h
+++ b/contrib/expat/xmlwf/xmltchar.h
@@ -7,7 +7,8 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -54,6 +55,8 @@
# define tmain wmain
# define tremove _wremove
# define tchar wchar_t
+# define tcstof wcstof
+# define tcstoull wcstoull
#else /* not XML_UNICODE */
# define T(x) x
# define ftprintf fprintf
@@ -71,4 +74,6 @@
# define tmain main
# define tremove remove
# define tchar char
+# define tcstof strtof
+# define tcstoull strtoull
#endif /* not XML_UNICODE */
diff --git a/contrib/expat/xmlwf/xmlwf.c b/contrib/expat/xmlwf/xmlwf.c
index 2d5a87e7d99d..7c0a8cd4d6a4 100644
--- a/contrib/expat/xmlwf/xmlwf.c
+++ b/contrib/expat/xmlwf/xmlwf.c
@@ -7,7 +7,18 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
+ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
+ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2004-2009 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2020 Joe Orton <jorton@redhat.com>
+ Copyright (c) 2020 Kleber TarcĂ­sio <klebertarcisio@yahoo.com.br>
+ Copyright (c) 2021 Tim Bray <tbray@textuality.com>
+ Copyright (c) 2022 Martin Ettl <ettl.martin78@googlemail.com>
+ Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -30,11 +41,15 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "expat_config.h"
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
+#include <math.h> /* for isnan */
+#include <errno.h>
#include "expat.h"
#include "codepage.h"
@@ -50,6 +65,14 @@
# include <wchar.h>
#endif
+enum ExitCode {
+ XMLWF_EXIT_SUCCESS = 0,
+ XMLWF_EXIT_INTERNAL_ERROR = 1,
+ XMLWF_EXIT_NOT_WELLFORMED = 2,
+ XMLWF_EXIT_OUTPUT_ERROR = 3,
+ XMLWF_EXIT_USAGE_ERROR = 4,
+};
+
/* Structures for handler user data */
typedef struct NotationList {
struct NotationList *next;
@@ -156,7 +179,7 @@ is equivalent to lexicographically comparing based on the character number. */
static int
attcmp(const void *att1, const void *att2) {
- return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2);
+ return tcscmp(*(const XML_Char *const *)att1, *(const XML_Char *const *)att2);
}
static void XMLCALL
@@ -193,10 +216,10 @@ endElement(void *userData, const XML_Char *name) {
static int
nsattcmp(const void *p1, const void *p2) {
- const XML_Char *att1 = *(const XML_Char **)p1;
- const XML_Char *att2 = *(const XML_Char **)p2;
+ const XML_Char *att1 = *(const XML_Char *const *)p1;
+ const XML_Char *att2 = *(const XML_Char *const *)p2;
int sep1 = (tcsrchr(att1, NSSEP) != 0);
- int sep2 = (tcsrchr(att1, NSSEP) != 0);
+ int sep2 = (tcsrchr(att2, NSSEP) != 0);
if (sep1 != sep2)
return sep1 - sep2;
return tcscmp(att1, att2);
@@ -322,6 +345,13 @@ freeNotations(XmlwfUserData *data) {
data->notationListHead = NULL;
}
+static void
+cleanupUserData(XmlwfUserData *userData) {
+ free((void *)userData->currentDoctypeName);
+ userData->currentDoctypeName = NULL;
+ freeNotations(userData);
+}
+
static int
xcscmp(const XML_Char *xs, const XML_Char *xt) {
while (*xs != 0 && *xt != 0) {
@@ -341,8 +371,8 @@ xcscmp(const XML_Char *xs, const XML_Char *xt) {
static int
notationCmp(const void *a, const void *b) {
- const NotationList *const n1 = *(NotationList **)a;
- const NotationList *const n2 = *(NotationList **)b;
+ const NotationList *const n1 = *(const NotationList *const *)a;
+ const NotationList *const n2 = *(const NotationList *const *)b;
return xcscmp(n1->notationName, n2->notationName);
}
@@ -842,47 +872,71 @@ showVersion(XML_Char *prog) {
}
}
+#if defined(__GNUC__)
+__attribute__((noreturn))
+#endif
static void
usage(const XML_Char *prog, int rc) {
ftprintf(
stderr,
/* Generated with:
* $ xmlwf/xmlwf_helpgen.sh
+ * To update, change xmlwf/xmlwf_helpgen.py, then paste the output of
+ * xmlwf/xmlwf_helpgen.sh in here.
*/
/* clang-format off */
- T("usage: %s [-s] [-n] [-p] [-x] [-e ENCODING] [-w] [-r] [-d DIRECTORY]\n")
- T(" [-c | -m | -t] [-N]\n")
- T(" [FILE [FILE ...]]\n")
+ T("usage:\n")
+ T(" %s [OPTIONS] [FILE ...]\n")
+ T(" %s -h|--help\n")
+ T(" %s -v|--version\n")
T("\n")
T("xmlwf - Determines if an XML document is well-formed\n")
T("\n")
T("positional arguments:\n")
- T(" FILE files to process (default: STDIN)\n")
+ T(" FILE file to process (default: STDIN)\n")
T("\n")
T("input control arguments:\n")
- T(" -s print an error if the document is not [s]tandalone\n")
- T(" -n enable [n]amespace processing\n")
- T(" -p enable processing external DTDs and [p]arameter entities\n")
- T(" -x enable processing of e[x]ternal entities\n")
- T(" -e ENCODING override any in-document [e]ncoding declaration\n")
- T(" -w enable support for [W]indows code pages\n")
- T(" -r disable memory-mapping and use normal file [r]ead IO calls instead\n")
+ T(" -s print an error if the document is not [s]tandalone\n")
+ T(" -n enable [n]amespace processing\n")
+ T(" -p enable processing of external DTDs and [p]arameter entities\n")
+ T(" -x enable processing of e[x]ternal entities\n")
+ T(" -e ENCODING override any in-document [e]ncoding declaration\n")
+ T(" -w enable support for [W]indows code pages\n")
+ T(" -r disable memory-mapping and use [r]ead calls instead\n")
+ T(" -g BYTES buffer size to request per call pair to XML_[G]etBuffer and read (default: 8 KiB)\n")
+ T(" -k when processing multiple files, [k]eep processing after first file with error\n")
T("\n")
T("output control arguments:\n")
- T(" -d DIRECTORY output [d]estination directory\n")
- T(" -c write a [c]opy of input XML, not canonical XML\n")
- T(" -m write [m]eta XML, not canonical XML\n")
- T(" -t write no XML output for [t]iming of plain parsing\n")
- T(" -N enable adding doctype and [n]otation declarations\n")
+ T(" -d DIRECTORY output [d]estination directory\n")
+ T(" -c write a [c]opy of input XML, not canonical XML\n")
+ T(" -m write [m]eta XML, not canonical XML\n")
+ T(" -t write no XML output for [t]iming of plain parsing\n")
+ T(" -N enable adding doctype and [n]otation declarations\n")
+ T("\n")
+ T("billion laughs attack protection:\n")
+ T(" NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n")
+ T("\n")
+ T(" -a FACTOR set maximum tolerated [a]mplification factor (default: 100.0)\n")
+ T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB)\n")
+ T("\n")
+ T("reparse deferral:\n")
+ T(" -q disable reparse deferral, and allow [q]uadratic parse runtime with large tokens\n")
T("\n")
T("info arguments:\n")
- T(" -h show this [h]elp message and exit\n")
- T(" -v show program's [v]ersion number and exit\n")
+ T(" -h, --help show this [h]elp message and exit\n")
+ T(" -v, --version show program's [v]ersion number and exit\n")
+ T("\n")
+ T("exit status:\n")
+ T(" 0 the input files are well-formed and the output (if requested) was written successfully\n")
+ T(" 1 could not allocate data structures, signals a serious problem with execution environment\n")
+ T(" 2 one or more input files were not well-formed\n")
+ T(" 3 could not create an output file\n")
+ T(" 4 command-line argument error\n")
T("\n")
- T("libexpat is software libre, licensed under the MIT license.\n")
- T("Please report bugs at https://github.com/libexpat/libexpat/issues. Thank you!\n")
+ T("xmlwf of libexpat is software libre, licensed under the MIT license.\n")
+ T("Please report bugs at https://github.com/libexpat/libexpat/issues -- thank you!\n")
, /* clang-format on */
- prog);
+ prog, prog, prog);
exit(rc);
}
@@ -891,6 +945,21 @@ usage(const XML_Char *prog, int rc) {
int wmain(int argc, XML_Char **argv);
#endif
+#define XMLWF_SHIFT_ARG_INTO(constCharStarTarget, argc, argv, i, j) \
+ { \
+ if (argv[i][j + 1] == T('\0')) { \
+ if (++i == argc) { \
+ usage(argv[0], XMLWF_EXIT_USAGE_ERROR); \
+ /* usage called exit(..), never gets here */ \
+ } \
+ constCharStarTarget = argv[i]; \
+ } else { \
+ constCharStarTarget = argv[i] + j + 1; \
+ } \
+ i++; \
+ j = 0; \
+ }
+
int
tmain(int argc, XML_Char **argv) {
int i, j;
@@ -902,6 +971,15 @@ tmain(int argc, XML_Char **argv) {
int useNamespaces = 0;
int requireStandalone = 0;
int requiresNotations = 0;
+ int continueOnError = 0;
+
+ float attackMaximumAmplification = -1.0f; /* signaling "not set" */
+ unsigned long long attackThresholdBytes = 0;
+ XML_Bool attackThresholdGiven = XML_FALSE;
+
+ XML_Bool disableDeferral = XML_FALSE;
+
+ int exitCode = XMLWF_EXIT_SUCCESS;
enum XML_ParamEntityParsing paramEntityParsing
= XML_PARAM_ENTITY_PARSING_NEVER;
int useStdin = 0;
@@ -917,9 +995,17 @@ tmain(int argc, XML_Char **argv) {
if (j == 0) {
if (argv[i][0] != T('-'))
break;
- if (argv[i][1] == T('-') && argv[i][2] == T('\0')) {
- i++;
- break;
+ if (argv[i][1] == T('-')) {
+ if (argv[i][2] == T('\0')) {
+ i++;
+ break;
+ } else if (tcscmp(argv[i] + 2, T("help")) == 0) {
+ usage(argv[0], XMLWF_EXIT_SUCCESS);
+ // usage called exit(..), never gets here
+ } else if (tcscmp(argv[i] + 2, T("version")) == 0) {
+ showVersion(argv[0]);
+ return XMLWF_EXIT_SUCCESS;
+ }
}
j++;
}
@@ -965,31 +1051,91 @@ tmain(int argc, XML_Char **argv) {
j++;
break;
case T('d'):
- if (argv[i][j + 1] == T('\0')) {
- if (++i == argc)
- usage(argv[0], 2);
- outputDir = argv[i];
- } else
- outputDir = argv[i] + j + 1;
- i++;
- j = 0;
+ XMLWF_SHIFT_ARG_INTO(outputDir, argc, argv, i, j);
break;
case T('e'):
- if (argv[i][j + 1] == T('\0')) {
- if (++i == argc)
- usage(argv[0], 2);
- encoding = argv[i];
- } else
- encoding = argv[i] + j + 1;
- i++;
- j = 0;
+ XMLWF_SHIFT_ARG_INTO(encoding, argc, argv, i, j);
break;
case T('h'):
- usage(argv[0], 0);
- return 0;
+ usage(argv[0], XMLWF_EXIT_SUCCESS);
+ // usage called exit(..), never gets here
case T('v'):
showVersion(argv[0]);
- return 0;
+ return XMLWF_EXIT_SUCCESS;
+ case T('g'): {
+ const XML_Char *valueText = NULL;
+ XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
+
+ errno = 0;
+ XML_Char *afterValueText = (XML_Char *)valueText;
+ const long long read_size_bytes_candidate
+ = tcstoull(valueText, &afterValueText, 10);
+ if ((errno != 0) || (afterValueText[0] != T('\0'))
+ || (read_size_bytes_candidate < 1)
+ || (read_size_bytes_candidate > (INT_MAX / 2 + 1))) {
+ // This prevents tperror(..) from reporting misleading "[..]: Success"
+ errno = ERANGE;
+ tperror(T("invalid buffer size") T(
+ " (needs an integer from 1 to INT_MAX/2+1 i.e. 1,073,741,824 on most platforms)"));
+ exit(XMLWF_EXIT_USAGE_ERROR);
+ }
+ g_read_size_bytes = (int)read_size_bytes_candidate;
+ break;
+ }
+ case T('k'):
+ continueOnError = 1;
+ j++;
+ break;
+ case T('a'): {
+ const XML_Char *valueText = NULL;
+ XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
+
+ errno = 0;
+ XML_Char *afterValueText = NULL;
+ attackMaximumAmplification = tcstof(valueText, &afterValueText);
+ if ((errno != 0) || (afterValueText[0] != T('\0'))
+ || isnan(attackMaximumAmplification)
+ || (attackMaximumAmplification < 1.0f)) {
+ // This prevents tperror(..) from reporting misleading "[..]: Success"
+ errno = ERANGE;
+ tperror(T("invalid amplification limit") T(
+ " (needs a floating point number greater or equal than 1.0)"));
+ exit(XMLWF_EXIT_USAGE_ERROR);
+ }
+#if XML_GE == 0
+ ftprintf(stderr,
+ T("Warning: Given amplification limit ignored")
+ T(", xmlwf has been compiled without DTD/GE support.\n"));
+#endif
+ break;
+ }
+ case T('b'): {
+ const XML_Char *valueText = NULL;
+ XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
+
+ errno = 0;
+ XML_Char *afterValueText = (XML_Char *)valueText;
+ attackThresholdBytes = tcstoull(valueText, &afterValueText, 10);
+ if ((errno != 0) || (afterValueText[0] != T('\0'))) {
+ // This prevents tperror(..) from reporting misleading "[..]: Success"
+ errno = ERANGE;
+ tperror(T("invalid ignore threshold")
+ T(" (needs an integer from 0 to 2^64-1)"));
+ exit(XMLWF_EXIT_USAGE_ERROR);
+ }
+ attackThresholdGiven = XML_TRUE;
+#if XML_GE == 0
+ ftprintf(stderr,
+ T("Warning: Given attack threshold ignored")
+ T(", xmlwf has been compiled without DTD/GE support.\n"));
+#endif
+ break;
+ }
+ case T('q'): {
+ disableDeferral = XML_TRUE;
+ j++;
+ break;
+ }
case T('\0'):
if (j > 1) {
i++;
@@ -998,7 +1144,8 @@ tmain(int argc, XML_Char **argv) {
}
/* fall through */
default:
- usage(argv[0], 2);
+ usage(argv[0], XMLWF_EXIT_USAGE_ERROR);
+ // usage called exit(..), never gets here
}
}
if (i == argc) {
@@ -1017,7 +1164,32 @@ tmain(int argc, XML_Char **argv) {
if (! parser) {
tperror(T("Could not instantiate parser"));
- exit(1);
+ exit(XMLWF_EXIT_INTERNAL_ERROR);
+ }
+
+ if (attackMaximumAmplification != -1.0f) {
+#if XML_GE == 1
+ XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parser, attackMaximumAmplification);
+#endif
+ }
+ if (attackThresholdGiven) {
+#if XML_GE == 1
+ XML_SetBillionLaughsAttackProtectionActivationThreshold(
+ parser, attackThresholdBytes);
+#else
+ (void)attackThresholdBytes; // silence -Wunused-but-set-variable
+#endif
+ }
+
+ if (disableDeferral) {
+ const XML_Bool success = XML_SetReparseDeferralEnabled(parser, XML_FALSE);
+ if (! success) {
+ // This prevents tperror(..) from reporting misleading "[..]: Success"
+ errno = EINVAL;
+ tperror(T("Failed to disable reparse deferral"));
+ exit(XMLWF_EXIT_INTERNAL_ERROR);
+ }
}
if (requireStandalone)
@@ -1051,13 +1223,24 @@ tmain(int argc, XML_Char **argv) {
}
outName = (XML_Char *)malloc((tcslen(outputDir) + tcslen(file) + 2)
* sizeof(XML_Char));
+ if (! outName) {
+ tperror(T("Could not allocate memory"));
+ exit(XMLWF_EXIT_INTERNAL_ERROR);
+ }
tcscpy(outName, outputDir);
tcscat(outName, delim);
tcscat(outName, file);
userData.fp = tfopen(outName, T("wb"));
if (! userData.fp) {
tperror(outName);
- exit(1);
+ exitCode = XMLWF_EXIT_OUTPUT_ERROR;
+ free(outName);
+ XML_ParserFree(parser);
+ if (continueOnError) {
+ continue;
+ } else {
+ break;
+ }
}
setvbuf(userData.fp, NULL, _IOFBF, 16384);
#ifdef XML_UNICODE
@@ -1119,8 +1302,12 @@ tmain(int argc, XML_Char **argv) {
}
XML_ParserFree(parser);
if (! result) {
- exit(2);
+ exitCode = XMLWF_EXIT_NOT_WELLFORMED;
+ cleanupUserData(&userData);
+ if (! continueOnError) {
+ break;
+ }
}
}
- return 0;
+ return exitCode;
}
diff --git a/contrib/expat/xmlwf/xmlwf_helpgen.py b/contrib/expat/xmlwf/xmlwf_helpgen.py
index 0dcb6d34e37c..3d32f5d148b7 100755
--- a/contrib/expat/xmlwf/xmlwf_helpgen.py
+++ b/contrib/expat/xmlwf/xmlwf_helpgen.py
@@ -6,7 +6,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2019 Expat development team
+# Copyright (c) 2019-2023 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2021 Tim Bray <tbray@textuality.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -31,11 +32,25 @@
import argparse
epilog = """
-libexpat is software libre, licensed under the MIT license.
-Please report bugs at https://github.com/libexpat/libexpat/issues. Thank you!
+exit status:
+ 0 the input files are well-formed and the output (if requested) was written successfully
+ 1 could not allocate data structures, signals a serious problem with execution environment
+ 2 one or more input files were not well-formed
+ 3 could not create an output file
+ 4 command-line argument error
+
+xmlwf of libexpat is software libre, licensed under the MIT license.
+Please report bugs at https://github.com/libexpat/libexpat/issues -- thank you!
+"""
+
+usage = """
+ %(prog)s [OPTIONS] [FILE ...]
+ %(prog)s -h|--help
+ %(prog)s -v|--version
"""
parser = argparse.ArgumentParser(prog='xmlwf', add_help=False,
+ usage=usage,
description='xmlwf - Determines if an XML document is well-formed',
formatter_class=argparse.RawTextHelpFormatter,
epilog=epilog)
@@ -43,11 +58,13 @@ parser = argparse.ArgumentParser(prog='xmlwf', add_help=False,
input_related = parser.add_argument_group('input control arguments')
input_related.add_argument('-s', action='store_true', help='print an error if the document is not [s]tandalone')
input_related.add_argument('-n', action='store_true', help='enable [n]amespace processing')
-input_related.add_argument('-p', action='store_true', help='enable processing external DTDs and [p]arameter entities')
+input_related.add_argument('-p', action='store_true', help='enable processing of external DTDs and [p]arameter entities')
input_related.add_argument('-x', action='store_true', help='enable processing of e[x]ternal entities')
input_related.add_argument('-e', action='store', metavar='ENCODING', help='override any in-document [e]ncoding declaration')
input_related.add_argument('-w', action='store_true', help='enable support for [W]indows code pages')
-input_related.add_argument('-r', action='store_true', help='disable memory-mapping and use normal file [r]ead IO calls instead')
+input_related.add_argument('-r', action='store_true', help='disable memory-mapping and use [r]ead calls instead')
+input_related.add_argument('-g', metavar='BYTES', help='buffer size to request per call pair to XML_[G]etBuffer and read (default: 8 KiB)')
+input_related.add_argument('-k', action='store_true', help='when processing multiple files, [k]eep processing after first file with error')
output_related = parser.add_argument_group('output control arguments')
output_related.add_argument('-d', action='store', metavar='DIRECTORY', help='output [d]estination directory')
@@ -57,12 +74,24 @@ output_mode.add_argument('-m', action='store_true', help='write [m]eta XML, not
output_mode.add_argument('-t', action='store_true', help='write no XML output for [t]iming of plain parsing')
output_related.add_argument('-N', action='store_true', help='enable adding doctype and [n]otation declarations')
-parser.add_argument('files', metavar='FILE', nargs='*', help='files to process (default: STDIN)')
+billion_laughs = parser.add_argument_group('billion laughs attack protection',
+ description='NOTE: '
+ 'If you ever need to increase these values '
+ 'for non-attack payload, please file a bug report.')
+billion_laughs.add_argument('-a', metavar='FACTOR',
+ help='set maximum tolerated [a]mplification factor (default: 100.0)')
+billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB)')
+
+reparse_deferral = parser.add_argument_group('reparse deferral')
+reparse_deferral.add_argument('-q', metavar='FACTOR',
+ help='disable reparse deferral, and allow [q]uadratic parse runtime with large tokens')
+
+parser.add_argument('files', metavar='FILE', nargs='*', help='file to process (default: STDIN)')
info = parser.add_argument_group('info arguments')
info = info.add_mutually_exclusive_group()
-info.add_argument('-h', action='store_true', help='show this [h]elp message and exit')
-info.add_argument('-v', action='store_true', help='show program\'s [v]ersion number and exit')
+info.add_argument('-h', '--help', action='store_true', help='show this [h]elp message and exit')
+info.add_argument('-v', '--version', action='store_true', help='show program\'s [v]ersion number and exit')
if __name__ == '__main__':
diff --git a/contrib/expat/xmlwf/xmlwf_helpgen.sh b/contrib/expat/xmlwf/xmlwf_helpgen.sh
index 6b0fbf929a09..864e47086d15 100755
--- a/contrib/expat/xmlwf/xmlwf_helpgen.sh
+++ b/contrib/expat/xmlwf/xmlwf_helpgen.sh
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2019 Expat development team
+# Copyright (c) 2019-2021 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -29,7 +29,8 @@
# USE OR OTHER DEALINGS IN THE SOFTWARE.
./xmlwf/xmlwf_helpgen.py | sed \
- -e 's,usage: xmlwf,usage: %s,' \
+ -e 's,usage: ,usage:,' \
+ -e 's, xmlwf, %s,' \
-e 's, \[-h | -v\],,' \
-e 's,^, T(",' \
-e 's,$,\\n"),'
diff --git a/contrib/expat/xmlwf/xmlwin32url.cxx b/contrib/expat/xmlwf/xmlwin32url.cxx
deleted file mode 100644
index ef2a137452e7..000000000000
--- a/contrib/expat/xmlwf/xmlwin32url.cxx
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- __ __ _
- ___\ \/ /_ __ __ _| |_
- / _ \\ /| '_ \ / _` | __|
- | __// \| |_) | (_| | |_
- \___/_/\_\ .__/ \__,_|\__|
- |_| XML parser
-
- Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
- Copyright (c) 2000-2017 Expat development team
- Licensed under the MIT license:
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to permit
- persons to whom the Software is furnished to do so, subject to the
- following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
- NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#include "expat.h"
-#ifdef XML_UNICODE
-#define UNICODE
-#endif
-#include <windows.h>
-#include <urlmon.h>
-#include <wininet.h>
-#include <stdio.h>
-#include <tchar.h>
-#include "xmlurl.h"
-#include "xmlmime.h"
-
-static int
-processURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url);
-
-typedef void (*StopHandler)(void *, HRESULT);
-
-class Callback : public IBindStatusCallback {
-public:
- // IUnknown methods
- STDMETHODIMP QueryInterface(REFIID,void **);
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
- // IBindStatusCallback methods
- STDMETHODIMP OnStartBinding(DWORD, IBinding *);
- STDMETHODIMP GetPriority(LONG *);
- STDMETHODIMP OnLowResource(DWORD);
- STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR);
- STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR);
- STDMETHODIMP GetBindInfo(DWORD *, BINDINFO *);
- STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC *, STGMEDIUM *);
- STDMETHODIMP OnObjectAvailable(REFIID, IUnknown *);
- Callback(XML_Parser, IMoniker *, StopHandler, void *);
- ~Callback();
- int externalEntityRef(const XML_Char *context,
- const XML_Char *systemId, const XML_Char *publicId);
-private:
- XML_Parser parser_;
- IMoniker *baseMoniker_;
- DWORD totalRead_;
- ULONG ref_;
- IBinding *pBinding_;
- StopHandler stopHandler_;
- void *stopArg_;
-};
-
-STDMETHODIMP_(ULONG)
-Callback::AddRef()
-{
- return ref_++;
-}
-
-STDMETHODIMP_(ULONG)
-Callback::Release()
-{
- if (--ref_ == 0) {
- delete this;
- return 0;
- }
- return ref_;
-}
-
-STDMETHODIMP
-Callback::QueryInterface(REFIID riid, void** ppv)
-{
- if (IsEqualGUID(riid, IID_IUnknown))
- *ppv = (IUnknown *)this;
- else if (IsEqualGUID(riid, IID_IBindStatusCallback))
- *ppv = (IBindStatusCallback *)this;
- else
- return E_NOINTERFACE;
- ((LPUNKNOWN)*ppv)->AddRef();
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::OnStartBinding(DWORD, IBinding* pBinding)
-{
- pBinding_ = pBinding;
- pBinding->AddRef();
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::GetPriority(LONG *)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP
-Callback::OnLowResource(DWORD)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP
-Callback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR)
-{
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::OnStopBinding(HRESULT hr, LPCWSTR szError)
-{
- if (pBinding_) {
- pBinding_->Release();
- pBinding_ = 0;
- }
- if (baseMoniker_) {
- baseMoniker_->Release();
- baseMoniker_ = 0;
- }
- stopHandler_(stopArg_, hr);
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo)
-{
- *pgrfBINDF = BINDF_ASYNCHRONOUS;
- return S_OK;
-}
-
-static void
-reportError(XML_Parser parser)
-{
- int code = XML_GetErrorCode(parser);
- const XML_Char *message = XML_ErrorString(code);
- if (message)
- _ftprintf(stderr, _T("%s:%d:%ld: %s\n"),
- XML_GetBase(parser),
- XML_GetErrorLineNumber(parser),
- XML_GetErrorColumnNumber(parser),
- message);
- else
- _ftprintf(stderr, _T("%s: (unknown message %d)\n"),
- XML_GetBase(parser), code);
-}
-
-STDMETHODIMP
-Callback::OnDataAvailable(DWORD grfBSCF,
- DWORD dwSize,
- FORMATETC *pfmtetc,
- STGMEDIUM* pstgmed)
-{
- if (grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
- IWinInetHttpInfo *hp;
- HRESULT hr = pBinding_->QueryInterface(IID_IWinInetHttpInfo,
- (void **)&hp);
- if (SUCCEEDED(hr)) {
- char contentType[1024];
- DWORD bufSize = sizeof(contentType);
- DWORD flags = 0;
- contentType[0] = 0;
- hr = hp->QueryInfo(HTTP_QUERY_CONTENT_TYPE, contentType,
- &bufSize, 0, NULL);
- if (SUCCEEDED(hr)) {
- char charset[CHARSET_MAX];
- getXMLCharset(contentType, charset);
- if (charset[0]) {
-#ifdef XML_UNICODE
- XML_Char wcharset[CHARSET_MAX];
- XML_Char *p1 = wcharset;
- const char *p2 = charset;
- while ((*p1++ = (unsigned char)*p2++) != 0)
- ;
- XML_SetEncoding(parser_, wcharset);
-#else
- XML_SetEncoding(parser_, charset);
-#endif
- }
- }
- hp->Release();
- }
- }
- if (!parser_)
- return E_ABORT;
- if (pstgmed->tymed == TYMED_ISTREAM) {
- while (totalRead_ < dwSize) {
-#define READ_MAX (64*1024)
- DWORD nToRead = dwSize - totalRead_;
- if (nToRead > READ_MAX)
- nToRead = READ_MAX;
- void *buf = XML_GetBuffer(parser_, nToRead);
- if (!buf) {
- _ftprintf(stderr, _T("out of memory\n"));
- return E_ABORT;
- }
- DWORD nRead;
- HRESULT hr = pstgmed->pstm->Read(buf, nToRead, &nRead);
- if (SUCCEEDED(hr)) {
- totalRead_ += nRead;
- if (!XML_ParseBuffer(parser_,
- nRead,
- (grfBSCF & BSCF_LASTDATANOTIFICATION) != 0
- && totalRead_ == dwSize)) {
- reportError(parser_);
- return E_ABORT;
- }
- }
- }
- }
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::OnObjectAvailable(REFIID, IUnknown *)
-{
- return S_OK;
-}
-
-int
-Callback::externalEntityRef(const XML_Char *context,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- XML_Parser entParser = XML_ExternalEntityParserCreate(parser_, context, 0);
- XML_SetBase(entParser, systemId);
- int ret = processURL(entParser, baseMoniker_, systemId);
- XML_ParserFree(entParser);
- return ret;
-}
-
-Callback::Callback(XML_Parser parser, IMoniker *baseMoniker,
- StopHandler stopHandler, void *stopArg)
-: parser_(parser),
- baseMoniker_(baseMoniker),
- ref_(0),
- pBinding_(0),
- totalRead_(0),
- stopHandler_(stopHandler),
- stopArg_(stopArg)
-{
- if (baseMoniker_)
- baseMoniker_->AddRef();
-}
-
-Callback::~Callback()
-{
- if (pBinding_)
- pBinding_->Release();
- if (baseMoniker_)
- baseMoniker_->Release();
-}
-
-static int
-externalEntityRef(void *arg,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- return ((Callback *)arg)->externalEntityRef(context, systemId, publicId);
-}
-
-
-static HRESULT
-openStream(XML_Parser parser,
- IMoniker *baseMoniker,
- const XML_Char *uri,
- StopHandler stopHandler, void *stopArg)
-{
- if (!XML_SetBase(parser, uri))
- return E_OUTOFMEMORY;
- HRESULT hr;
- IMoniker *m;
-#ifdef XML_UNICODE
- hr = CreateURLMoniker(0, uri, &m);
-#else
- LPWSTR uriw = new wchar_t[strlen(uri) + 1];
- for (int i = 0;; i++) {
- uriw[i] = uri[i];
- if (uriw[i] == 0)
- break;
- }
- hr = CreateURLMoniker(baseMoniker, uriw, &m);
- delete [] uriw;
-#endif
- if (FAILED(hr))
- return hr;
- IBindStatusCallback *cb = new Callback(parser, m, stopHandler, stopArg);
- XML_SetExternalEntityRefHandler(parser, externalEntityRef);
- XML_SetExternalEntityRefHandlerArg(parser, cb);
- cb->AddRef();
- IBindCtx *b;
- if (FAILED(hr = CreateAsyncBindCtx(0, cb, 0, &b))) {
- cb->Release();
- m->Release();
- return hr;
- }
- cb->Release();
- IStream *pStream;
- hr = m->BindToStorage(b, 0, IID_IStream, (void **)&pStream);
- if (SUCCEEDED(hr)) {
- if (pStream)
- pStream->Release();
- }
- if (hr == MK_S_ASYNCHRONOUS)
- hr = S_OK;
- m->Release();
- b->Release();
- return hr;
-}
-
-struct QuitInfo {
- const XML_Char *url;
- HRESULT hr;
- int stop;
-};
-
-static void
-winPerror(const XML_Char *url, HRESULT hr)
-{
- LPVOID buf;
- if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
- | FORMAT_MESSAGE_FROM_HMODULE,
- GetModuleHandleA("urlmon.dll"),
- hr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &buf,
- 0,
- NULL)
- || FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
- | FORMAT_MESSAGE_FROM_SYSTEM,
- 0,
- hr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &buf,
- 0,
- NULL)) {
- /* The system error messages seem to end with a newline. */
- _ftprintf(stderr, _T("%s: %s"), url, buf);
- fflush(stderr);
- LocalFree(buf);
- }
- else
- _ftprintf(stderr, _T("%s: error %x\n"), url, hr);
-}
-
-static void
-threadQuit(void *p, HRESULT hr)
-{
- QuitInfo *qi = (QuitInfo *)p;
- qi->hr = hr;
- qi->stop = 1;
-}
-
-extern "C"
-int
-XML_URLInit(void)
-{
- return SUCCEEDED(CoInitialize(0));
-}
-
-extern "C"
-void
-XML_URLUninit(void)
-{
- CoUninitialize();
-}
-
-static int
-processURL(XML_Parser parser, IMoniker *baseMoniker,
- const XML_Char *url)
-{
- QuitInfo qi;
- qi.stop = 0;
- qi.url = url;
-
- XML_SetBase(parser, url);
- HRESULT hr = openStream(parser, baseMoniker, url, threadQuit, &qi);
- if (FAILED(hr)) {
- winPerror(url, hr);
- return 0;
- }
- else if (FAILED(qi.hr)) {
- winPerror(url, qi.hr);
- return 0;
- }
- MSG msg;
- while (!qi.stop && GetMessage (&msg, NULL, 0, 0)) {
- TranslateMessage (&msg);
- DispatchMessage (&msg);
- }
- return 1;
-}
-
-extern "C"
-int
-XML_ProcessURL(XML_Parser parser,
- const XML_Char *url,
- unsigned flags)
-{
- return processURL(parser, 0, url);
-}