From 941ad551408a8d34aff023563857b4cf15b350d2 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 27 Jun 2017 05:34:22 -0400 Subject: [PATCH] Update expat sources --- lib-src/expat/CMake.README | 12 +- lib-src/expat/CMakeLists.txt | 78 +- lib-src/expat/COPYING | 5 +- lib-src/expat/Changes | 196 +- lib-src/expat/MANIFEST | 66 +- lib-src/expat/Makefile.in | 60 +- lib-src/expat/README | 4 +- .../expat/conftools/ac_c_bigendian_cross.m4 | 2 +- lib-src/expat/conftools/mkinstalldirs | 2 +- lib-src/expat/doc/expat.png | Bin 1027 -> 1029 bytes lib-src/expat/doc/reference.html | 10 +- lib-src/expat/doc/valid-xhtml10.png | Bin 2368 -> 2370 bytes lib-src/expat/examples/elements.c | 15 +- lib-src/expat/examples/outline.c | 11 +- lib-src/expat/lib/expat.h | 35 +- lib-src/expat/lib/expat_external.h | 19 +- lib-src/expat/lib/internal.h | 22 + lib-src/expat/lib/libexpat.def | 3 + lib-src/expat/lib/libexpatw.def | 3 + lib-src/expat/lib/siphash.h | 344 +++ lib-src/expat/lib/winconfig.h | 10 + lib-src/expat/lib/xmlparse.c | 712 ++++- lib-src/expat/lib/xmlrole.c | 230 +- lib-src/expat/lib/xmltok.c | 244 +- lib-src/expat/lib/xmltok.h | 10 +- lib-src/expat/lib/xmltok_impl.c | 226 +- lib-src/expat/tests/benchmark/README.txt | 2 +- lib-src/expat/tests/benchmark/benchmark.c | 4 - lib-src/expat/tests/chardata.c | 8 +- lib-src/expat/tests/minicheck.c | 12 +- lib-src/expat/tests/minicheck.h | 16 +- lib-src/expat/tests/runtests.c | 2416 +++++++++++++++-- lib-src/expat/tests/xmltest.sh | 13 +- lib-src/expat/win32/MANIFEST.txt | 2 - lib-src/expat/win32/README.txt | 21 +- lib-src/expat/win32/expat.iss | 35 +- lib-src/expat/xmlwf/codepage.c | 11 +- lib-src/expat/xmlwf/filemap.h | 12 + lib-src/expat/xmlwf/readfilemap.c | 18 +- lib-src/expat/xmlwf/unixfilemap.c | 8 +- lib-src/expat/xmlwf/win32filemap.c | 7 +- lib-src/expat/xmlwf/xmlfile.c | 56 +- lib-src/expat/xmlwf/xmlwf.c | 56 +- 43 files changed, 4134 insertions(+), 882 deletions(-) create mode 100644 lib-src/expat/lib/siphash.h diff --git a/lib-src/expat/CMake.README b/lib-src/expat/CMake.README index eda302d91..53b4322fe 100755 --- a/lib-src/expat/CMake.README +++ b/lib-src/expat/CMake.README @@ -3,25 +3,25 @@ The cmake based buildsystem for expat works on Windows (cygwin, mingw, Visual Studio) and should work on all other platform cmake supports. -Assuming ~/expat-2.1.0 is the source directory of expat, add a subdirectory +Assuming ~/expat-2.2.1 is the source directory of expat, add a subdirectory build and change into that directory: -~/expat-2.1.0$ mkdir build && cd build -~/expat-2.1.0/build$ +~/expat-2.2.1$ mkdir build && cd build +~/expat-2.2.1/build$ From that directory, call cmake first, then call make, make test and make install in the usual way: -~/expat-2.1.0/build$ cmake .. +~/expat-2.2.1/build$ cmake .. -- The C compiler identification is GNU -- The CXX compiler identification is GNU .... -- Configuring done -- Generating done --- Build files have been written to: /home/patrick/expat-2.1.0/build +-- Build files have been written to: /home/patrick/expat-2.2.1/build If you want to specify the install location for your files, append -DCMAKE_INSTALL_PREFIX=/your/install/path to the cmake call. -~/expat-2.1.0/build$ make && make test && make install +~/expat-2.2.1/build$ make && make test && make install Scanning dependencies of target expat [ 5%] Building C object CMakeFiles/expat.dir/lib/xmlparse.c.o [ 11%] Building C object CMakeFiles/expat.dir/lib/xmlrole.c.o diff --git a/lib-src/expat/CMakeLists.txt b/lib-src/expat/CMakeLists.txt index bc930571b..cbb198165 100755 --- a/lib-src/expat/CMakeLists.txt +++ b/lib-src/expat/CMakeLists.txt @@ -6,7 +6,7 @@ project(expat) cmake_minimum_required(VERSION 2.6) set(PACKAGE_BUGREPORT "expat-bugs@libexpat.org") set(PACKAGE_NAME "expat") -set(PACKAGE_VERSION "2.1.0") +set(PACKAGE_VERSION "2.2.1") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}") @@ -14,6 +14,8 @@ option(BUILD_tools "build the xmlwf tool for expat library" ON) option(BUILD_examples "build the examples for expat library" ON) option(BUILD_tests "build the tests for expat library" ON) option(BUILD_shared "build a shared expat library" ON) +option(BUILD_doc "build man page for xmlwf" ON) +option(INSTALL "install expat files in cmake install target" ON) # configuration options set(XML_CONTEXT_BYTES 1024 CACHE STRING "Define to specify how much context to retain around the current parse point") @@ -37,32 +39,60 @@ endif(BUILD_tests) include(ConfigureChecks.cmake) +set(EXTRA_LINK_AND_COMPILE_FLAGS "-fno-strict-aliasing") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_LINK_AND_COMPILE_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_LINK_AND_COMPILE_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EXTRA_LINK_AND_COMPILE_FLAGS}") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EXTRA_LINK_AND_COMPILE_FLAGS}") + include_directories(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/lib) if(MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS -wd4996) endif(MSVC) +if(WIN32) + set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Add a suffix, usually d on Windows") +endif(WIN32) set(expat_SRCS lib/xmlparse.c lib/xmlrole.c - lib/xmltok.c - lib/xmltok_impl.c + lib/xmltok.c + lib/xmltok_impl.c lib/xmltok_ns.c ) -if(WIN32 AND BUILD_shared) - set(expat_SRCS ${expat_SRCS} lib/libexpat.def) -endif(WIN32 AND BUILD_shared) - if(BUILD_shared) set(_SHARED SHARED) + if(WIN32) + set(expat_SRCS ${expat_SRCS} lib/libexpat.def) + endif(WIN32) else(BUILD_shared) set(_SHARED STATIC) + if(WIN32) + add_definitions(-DXML_STATIC) + endif(WIN32) endif(BUILD_shared) add_library(expat ${_SHARED} ${expat_SRCS}) -install(TARGETS expat RUNTIME DESTINATION bin +set(LIBCURRENT 7) # sync +set(LIBREVISION 3) # with +set(LIBAGE 6) # configure.ac! +math(EXPR LIBCURRENT_MINUS_AGE "${LIBCURRENT} - ${LIBAGE}") + +if(NOT WIN32) + set_property(TARGET expat PROPERTY VERSION ${LIBCURRENT_MINUS_AGE}.${LIBAGE}.${LIBREVISION}) + set_property(TARGET expat PROPERTY SOVERSION ${LIBCURRENT_MINUS_AGE}) + set_property(TARGET expat PROPERTY NO_SONAME ${NO_SONAME}) +endif(NOT WIN32) + +macro(expat_install) + if(INSTALL) + install(${ARGN}) + endif() +endmacro() + +expat_install(TARGETS expat RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) @@ -72,10 +102,8 @@ set(libdir "\${prefix}/lib") set(includedir "\${prefix}/include") configure_file(expat.pc.in ${CMAKE_CURRENT_BINARY_DIR}/expat.pc) -install(FILES lib/expat.h lib/expat_external.h DESTINATION include) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/expat.pc DESTINATION lib/pkgconfig) - - +expat_install(FILES lib/expat.h lib/expat_external.h DESTINATION include) +expat_install(FILES ${CMAKE_CURRENT_BINARY_DIR}/expat.pc DESTINATION lib/pkgconfig) if(BUILD_tools AND NOT WINCE) set(xmlwf_SRCS @@ -86,26 +114,40 @@ if(BUILD_tools AND NOT WINCE) ) add_executable(xmlwf ${xmlwf_SRCS}) + set_property(TARGET xmlwf PROPERTY RUNTIME_OUTPUT_DIRECTORY xmlwf) target_link_libraries(xmlwf expat) - install(TARGETS xmlwf DESTINATION bin) - install(FILES doc/xmlwf.1 DESTINATION share/man/man1) + expat_install(TARGETS xmlwf DESTINATION bin) + if(BUILD_doc AND NOT MSVC) + if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") + set(make_command "$(MAKE)") + else() + set(make_command "make") + endif() + + add_custom_command(TARGET expat PRE_BUILD COMMAND "${make_command}" -C "${PROJECT_SOURCE_DIR}/doc" xmlwf.1) + expat_install(FILES "${PROJECT_SOURCE_DIR}/doc/xmlwf.1" DESTINATION share/man/man1) + endif() endif(BUILD_tools AND NOT WINCE) if(BUILD_examples) add_executable(elements examples/elements.c) + set_property(TARGET elements PROPERTY RUNTIME_OUTPUT_DIRECTORY examples) target_link_libraries(elements expat) add_executable(outline examples/outline.c) + set_property(TARGET outline PROPERTY RUNTIME_OUTPUT_DIRECTORY examples) target_link_libraries(outline expat) endif(BUILD_examples) if(BUILD_tests) ## these are unittests that can be run on any platform - add_executable(runtests tests/runtests.c tests/chardata.c tests/minicheck.c) + add_executable(runtests tests/runtests.c tests/chardata.c tests/minicheck.c tests/memcheck.c) + set_property(TARGET runtests PROPERTY RUNTIME_OUTPUT_DIRECTORY tests) target_link_libraries(runtests expat) - add_test(runtests runtests) + add_test(runtests tests/runtests) - add_executable(runtestspp tests/runtestspp.cpp tests/chardata.c tests/minicheck.c) + add_executable(runtestspp tests/runtestspp.cpp tests/chardata.c tests/minicheck.c tests/memcheck.c) + set_property(TARGET runtestspp PROPERTY RUNTIME_OUTPUT_DIRECTORY tests) target_link_libraries(runtestspp expat) - add_test(runtestspp runtestspp) + add_test(runtestspp tests/runtestspp) endif(BUILD_tests) diff --git a/lib-src/expat/COPYING b/lib-src/expat/COPYING index dcb450642..8d288f0f2 100644 --- a/lib-src/expat/COPYING +++ b/lib-src/expat/COPYING @@ -1,6 +1,5 @@ -Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd - and Clark Cooper -Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers. +Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper +Copyright (c) 2001-2017 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/lib-src/expat/Changes b/lib-src/expat/Changes index 08897b9f9..3054c3234 100644 --- a/lib-src/expat/Changes +++ b/lib-src/expat/Changes @@ -1,29 +1,213 @@ +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.1 Sat June 17 2017 + Security fixes: + CVE-2017-9233 -- External entity infinite loop DoS + Details: https://libexpat.github.io/doc/cve-2017-9233/ + Commit c4bf96bb51dd2a1b0e185374362ee136fe2c9d7f + [MOX-002] CVE-2016-9063 -- Detect integer overflow; commit + d4f735b88d9932bd5039df2335eefdd0723dbe20 + (Fixed version of existing downstream patches!) + (SF.net) #539 Fix regression from fix to CVE-2016-0718 cutting off + longer tag names; commits + * 896b6c1fd3b842f377d1b62135dccf0a579cf65d + * af507cef2c93cb8d40062a0abe43a4f4e9158fb2 + #16 * 0dbbf43fdb20f593ddf4fa1ff67288000dd4a7fd + #25 More integer overflow detection (function poolGrow); commits + * 810b74e4703dcfdd8f404e3cb177d44684775143 + * 44178553f3539ce69d34abee77a05e879a7982ac + [MOX-002] Detect overflow from len=INT_MAX call to XML_Parse; commits + * 4be2cb5afcc018d996f34bbbce6374b7befad47f + * 7e5b71b748491b6e459e5c9a1d090820f94544d8 + [MOX-005] #30 Use high quality entropy for hash initialization: + * arc4random_buf on BSD, systems with libbsd + (when configured with --with-libbsd), CloudABI + * RtlGenRandom on Windows XP / Server 2003 and later + * getrandom on Linux 3.17+ + In a way, that's still part of CVE-2016-5300. + https://github.com/libexpat/libexpat/pull/30/commits + [MOX-005] For the low quality entropy extraction fallback code, + the parser instance address can no longer leak, commit + 04ad658bd3079dd15cb60fc67087900f0ff4b083 + [MOX-003] Prevent use of uninitialised variable; commit + [MOX-004] a4dc944f37b664a3ca7199c624a98ee37babdb4b + Add missing parameter validation to public API functions + and dedicated error code XML_ERROR_INVALID_ARGUMENT: + [MOX-006] * NULL checks; commits + * d37f74b2b7149a3a95a680c4c4cd2a451a51d60a (merge/many) + * 9ed727064b675b7180c98cb3d4f75efba6966681 + * 6a747c837c50114dfa413994e07c0ba477be4534 + * Negative length (XML_Parse); commit + [MOX-002] 70db8d2538a10f4c022655d6895e4c3e78692e7f + [MOX-001] #35 Change hash algorithm to William Ahern's version of SipHash + to go further with fixing CVE-2012-0876. + https://github.com/libexpat/libexpat/pull/39/commits + + Bug fixes: + #32 Fix sharing of hash salt across parsers; + relevant where XML_ExternalEntityParserCreate is called + prior to XML_Parse, in particular (e.g. FBReader) + #28 xmlwf: Auto-disable use of memory-mapping (and parsing + as a single chunk) for files larger than ~1 GB (2^30 bytes) + rather than failing with error "out of memory" + #3 Fix double free after malloc failure in DTD code; commit + 7ae9c3d3af433cd4defe95234eae7dc8ed15637f + #17 Fix memory leak on parser error for unbound XML attribute + prefix with new namespaces defined in the same tag; + found by Google's OSS-Fuzz; commits + * 16f87daae5a16132e479e4f71862128c7a915c73 + * b47dbc9745932c160893d433220e462bd605f8cd + xmlwf on Windows: Add missing calls to CloseHandle + + New features: + #30 Introduced environment switch EXPAT_ENTROPY_DEBUG=1 + for runtime debugging of entropy extraction + + Other changes: + Increase code coverage + #33 Reject use of XML_UNICODE_WCHAR_T with sizeof(wchar_t) != 2; + XML_UNICODE_WCHAR_T was never meant to be used outside + of Windows; 4-byte wchar_t is common on Linux + (SF.net) #538 Start using -fno-strict-aliasing + (SF.net) #540 Support compilation against cloudlibc of CloudABI + Allow MinGW cross-compilation + (SF.net) #534 CMake: Introduce option "BUILD_doc" (enabled by default) + to bypass compilation of the xmlwf.1 man page + (SF.net) pr2 CMake: Introduce option "INSTALL" (enabled by default) + to bypass installation of expat files + CMake: Fix ninja support + Autotools: Add parameters --enable-xml-context [COUNT] + and --disable-xml-context; default of context of 1024 + bytes enabled unchanged + #14 Drop AmigaOS 4.x code and includes + #14 Drop ancient build systems: + * Borland C++ Builder + * OpenVMS + * Open Watcom + * Visual Studio 6.0 + * Pre-X Mac OS (MPW Makefile) + If you happen to rely on some of these, please get in + touch for joining with maintenance. + #10 Move from WIN32 to _WIN32 + #13 Fix "make run-xmltest" order instability + Address compile warnings + Bump version info from 7:2:6 to 7:3:6 + Add AUTHORS file + + Infrastructure: + #1 Migrate from SourceForge to GitHub (except downloads): + https://github.com/libexpat/ + #1 Re-create http://libexpat.org/ project website + Start utilizing Travis CI + + Special thanks to: + Andy Wang + Don Lewis + Ed Schouten + Karl Waclawek + Pascal Cuoq + Rhodri James + Sergei Nikulov + Tobias Taschner + Viktor Szakats + and + Core Infrastructure Initiative + Mozilla Foundation (MOSS Track 3: Secure Open Source) + Radically Open Security + +Release 2.2.0 Tue June 21 2016 + Security fixes: + #537 CVE-2016-0718 -- Fix crash on malformed input + CVE-2016-4472 -- Improve insufficient fix to CVE-2015-1283 / + CVE-2015-2716 introduced with Expat 2.1.1 + #499 CVE-2016-5300 -- Use more entropy for hash initialization + than the original fix to CVE-2012-0876 + #519 CVE-2012-6702 -- Resolve troublesome internal call to srand + that was introduced with Expat 2.1.0 + when addressing CVE-2012-0876 (issue #496) + + Bug fixes: + Fix uninitialized reads of size 1 + (e.g. in little2_updatePosition) + Fix detection of UTF-8 character boundaries + + Other changes: + #532 Fix compilation for Visual Studio 2010 (keyword "C99") + Autotools: Resolve use of "$<" to better support bmake + Autotools: Add QA script "qa.sh" (and make target "qa") + Autotools: Respect CXXFLAGS if given + Autotools: Fix "make run-xmltest" + Autotools: Have "make run-xmltest" check for expected output + p90 CMake: Fix static build (BUILD_shared=OFF) on Windows + #536 CMake: Add soversion, support -DNO_SONAME=yes to bypass + #323 CMake: Add suffix "d" to differentiate debug from release + CMake: Define WIN32 with CMake on Windows + Annotate memory allocators for GCC + Address all currently known compile warnings + Make sure that API symbols remain visible despite + -fvisibility=hidden + Remove executable flag from source files + Resolve COMPILED_FROM_DSP in favor of WIN32 + + Special thanks to: + Björn Lindahl + Christian Heimes + Cristian Rodríguez + Daniel Krügler + Gustavo Grieco + Karl Waclawek + László Böszörményi + Marco Grassi + Pascal Cuoq + Sergei Nikulov + Thomas Beutlich + Warren Young + Yann Droneaud + +Release 2.1.1 Sat March 12 2016 + Security fixes: + #582: CVE-2015-1283 - Multiple integer overflows in XML_GetBuffer + + Bug fixes: + #502: Fix potential null pointer dereference + #520: Symbol XML_SetHashSalt was not exported + Output of "xmlwf -h" was incomplete + + Other changes: + #503: Document behavior of calling XML_SetHashSalt with salt 0 + Minor improvements to man page xmlwf(1) + Improvements to the experimental CMake build system + libtool now invoked with --verbose + Release 2.1.0 Sat March 24 2012 + - Security fixes: + #2958794: CVE-2012-1148 - Memory leak in poolGrow. + #2895533: CVE-2012-1147 - Resource leak in readfilemap.c. + #3496608: CVE-2012-0876 - Hash DOS attack. + #2894085: CVE-2009-3560 - Buffer over-read and crash in big2_toUtf8(). + #1990430: CVE-2009-3720 - Parser crash with special UTF-8 sequences. - Bug Fixes: #1742315: Harmful XML_ParserCreateNS suggestion. - #2895533: CVE-2012-1147 - Resource leak in readfilemap.c. #1785430: Expat build fails on linux-amd64 with gcc version>=4.1 -O3. #1983953, 2517952, 2517962, 2649838: Build modifications using autoreconf instead of buildconf.sh. #2815947, #2884086: OBJEXT and EXEEXT support while building. - #1990430: CVE-2009-3720 - Parser crash with special UTF-8 sequences. #2517938: xmlwf should return non-zero exit status if not well-formed. #2517946: Wrong statement about XMLDecl in xmlwf.1 and xmlwf.sgml. #2855609: Dangling positionPtr after error. - #2894085: CVE-2009-3560 - Buffer over-read and crash in big2_toUtf8(). - #2958794: CVE-2012-1148 - Memory leak in poolGrow. #2990652: CMake support. #3010819: UNEXPECTED_STATE with a trailing "%" in entity value. #3206497: Unitialized memory returned from XML_Parse. #3287849: make check fails on mingw-w64. - #3496608: CVE-2012-0876 - Hash DOS attack. - Patches: #1749198: pkg-config support. #3010222: Fix for bug #3010819. #3312568: CMake support. #3446384: Report byte offsets for attr names and values. - New Features / API changes: - Added new API member XML_SetHashSalt() that allows setting an intial + Added new API member XML_SetHashSalt() that allows setting an initial value (salt) for hash calculations. This is part of the fix for bug #3496608 to randomize hash parameters. When compiled with XML_ATTR_INFO defined, adds new API member diff --git a/lib-src/expat/MANIFEST b/lib-src/expat/MANIFEST index 7a020dc05..c8479ed0a 100644 --- a/lib-src/expat/MANIFEST +++ b/lib-src/expat/MANIFEST @@ -1,50 +1,10 @@ -amiga/launch.c -amiga/expat_68k.c -amiga/expat_68k.h -amiga/expat_68k_handler_stubs.c -amiga/expat_base.h -amiga/expat_vectors.c -amiga/expat_lib.c -amiga/expat.xml -amiga/README.txt -amiga/Makefile -amiga/include/proto/expat.h -amiga/include/libraries/expat.h -amiga/include/interfaces/expat.h -amiga/include/inline4/expat.h -bcb5/README.txt -bcb5/all_projects.bpg -bcb5/elements.bpf -bcb5/elements.bpr -bcb5/elements.mak -bcb5/expat.bpf -bcb5/expat.bpr -bcb5/expat.mak -bcb5/expat_static.bpf -bcb5/expat_static.bpr -bcb5/expat_static.mak -bcb5/expatw.bpf -bcb5/expatw.bpr -bcb5/expatw.mak -bcb5/expatw_static.bpf -bcb5/expatw_static.bpr -bcb5/expatw_static.mak -bcb5/libexpat_mtd.def -bcb5/libexpatw_mtd.def -bcb5/makefile.mak -bcb5/outline.bpf -bcb5/outline.bpr -bcb5/outline.mak -bcb5/setup.bat -bcb5/xmlwf.bpf -bcb5/xmlwf.bpr -bcb5/xmlwf.mak +AUTHORS doc/expat.png doc/reference.html doc/style.css doc/valid-xhtml10.png doc/xmlwf.1 -doc/xmlwf.sgml +doc/xmlwf.xml CMakeLists.txt CMake.README COPYING @@ -54,12 +14,12 @@ MANIFEST Makefile.in README configure -configure.in +configure.ac expat_config.h.in expat_config.h.cmake expat.pc.in -expat.dsw aclocal.m4 +run.sh.in conftools/PrintPath conftools/ac_c_bigendian_cross.m4 conftools/expat.m4 @@ -75,26 +35,18 @@ m4/ltoptions.m4 m4/ltsugar.m4 m4/lt~obsolete.m4 examples/elements.c -examples/elements.dsp examples/outline.c -examples/outline.dsp -lib/Makefile.MPW -lib/amigaconfig.h lib/ascii.h lib/asciitab.h -lib/expat.dsp lib/expat.h lib/expat_external.h -lib/expat_static.dsp -lib/expatw.dsp -lib/expatw_static.dsp lib/iasciitab.h lib/internal.h lib/latin1tab.h lib/libexpat.def lib/libexpatw.def -lib/macconfig.h lib/nametab.h +lib/siphash.h lib/utf8tab.h lib/winconfig.h lib/xmlparse.c @@ -107,19 +59,16 @@ lib/xmltok_impl.h lib/xmltok_ns.c tests/benchmark/README.txt tests/benchmark/benchmark.c -tests/benchmark/benchmark.dsp -tests/benchmark/benchmark.dsw tests/README.txt tests/chardata.c tests/chardata.h +tests/memcheck.c +tests/memcheck.h tests/minicheck.c tests/minicheck.h tests/runtests.c tests/runtestspp.cpp tests/xmltest.sh -vms/README.vms -vms/descrip.mms -vms/expat_config.h win32/MANIFEST.txt win32/README.txt win32/expat.iss @@ -137,5 +86,4 @@ xmlwf/xmlmime.h xmlwf/xmltchar.h xmlwf/xmlurl.h xmlwf/xmlwf.c -xmlwf/xmlwf.dsp xmlwf/xmlwin32url.cxx diff --git a/lib-src/expat/Makefile.in b/lib-src/expat/Makefile.in index 9c0f5d49f..3ee11e858 100644 --- a/lib-src/expat/Makefile.in +++ b/lib-src/expat/Makefile.in @@ -42,7 +42,7 @@ INSTALL_DATA = @INSTALL_DATA@ mkinstalldirs = $(SHELL) $(top_srcdir)/conftools/mkinstalldirs MANFILE = $(srcdir)/doc/xmlwf.1 -APIHEADER = $(srcdir)/lib/expat.h $(srcdir)/lib/expat_external.h +APIHEADER = $(srcdir)/lib/expat.h $(srcdir)/lib/expat_external.h expat_config.h LIBRARY = libexpat.la DESTDIR = $(INSTALL_ROOT) @@ -51,14 +51,14 @@ default: buildlib xmlwf/xmlwf@EXEEXT@ buildlib: $(LIBRARY) expat.pc -all: $(LIBRARY) expat.pc xmlwf/xmlwf@EXEEXT@ examples/elements examples/outline +all: $(LIBRARY) expat.pc xmlwf/xmlwf@EXEEXT@ examples/elements examples/outline $(MANFILE) clean: cd lib && rm -f $(LIBRARY) *.@OBJEXT@ *.lo && rm -rf .libs _libs cd xmlwf && rm -f xmlwf *.@OBJEXT@ *.lo && rm -rf .libs _libs cd examples && rm -f elements outline *.@OBJEXT@ *.lo && rm -rf .libs _libs - cd tests && rm -rf .libs runtests runtests.@OBJEXT@ runtestspp runtestspp.@OBJEXT@ - cd tests && rm -f chardata.@OBJEXT@ minicheck.@OBJEXT@ + cd tests && rm -rf .libs runtests@EXEEXT@ runtests.@OBJEXT@ runtestspp@EXEEXT@ runtestspp.@OBJEXT@ + cd tests && rm -f chardata.@OBJEXT@ memcheck.@OBJEXT@ minicheck.@OBJEXT@ rm -rf .libs libexpat.la rm -f examples/core tests/core xmlwf/core @@ -73,11 +73,14 @@ extraclean: distclean rm -f aclocal.m4 m4/* rm -f conftools/ltmain.sh conftools/install-sh conftools/config.guess conftools/config.sub -check: tests/runtests tests/runtestspp - tests/runtests - tests/runtestspp +check: tests/runtests@EXEEXT@ tests/runtestspp@EXEEXT@ + ./run.sh tests/runtests@EXEEXT@ + ./run.sh tests/runtestspp@EXEEXT@ -install: xmlwf/xmlwf@EXEEXT@ installlib +$(MANFILE): + $(MAKE) -C doc xmlwf.1 + +install: xmlwf/xmlwf@EXEEXT@ installlib $(MANFILE) $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) xmlwf/xmlwf@EXEEXT@ $(DESTDIR)$(bindir)/xmlwf $(INSTALL_DATA) $(MANFILE) $(DESTDIR)$(man1dir) @@ -116,12 +119,12 @@ CXXFLAGS = @CXXFLAGS@ VSNFLAG = -version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@ ### autoconf this? -LTFLAGS = --silent +LTFLAGS = --verbose COMPILE = $(CC) $(INCLUDES) $(CFLAGS) $(DEFS) $(CPPFLAGS) CXXCOMPILE = $(CXX) $(INCLUDES) $(CXXFLAGS) $(DEFS) $(CPPFLAGS) LTCOMPILE = $(LIBTOOL) $(LTFLAGS) --mode=compile $(COMPILE) -LINK_LIB = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) -no-undefined $(VSNFLAG) -rpath $(libdir) $(LDFLAGS) -o $@ +LINK_LIB = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) -no-undefined $(VSNFLAG) -rpath $(libdir) $(LDFLAGS) @LIBS@ -o $@ LINK_EXE = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) $(LDFLAGS) -o $@ LINK_CXX_EXE = $(LIBTOOL) $(LTFLAGS) --mode=link $(CXXCOMPILE) $(LDFLAGS) -o $@ @@ -132,7 +135,7 @@ $(LIBRARY): $(LIB_OBJS) expat.pc: $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $@ -lib/xmlparse.lo: lib/xmlparse.c lib/expat.h lib/xmlrole.h lib/xmltok.h \ +lib/xmlparse.lo: lib/xmlparse.c lib/expat.h lib/siphash.h lib/xmlrole.h lib/xmltok.h \ $(top_builddir)/expat_config.h lib/expat_external.h lib/internal.h lib/xmlrole.lo: lib/xmlrole.c lib/ascii.h lib/xmlrole.h \ @@ -148,26 +151,27 @@ XMLWF_OBJS = xmlwf/xmlwf.@OBJEXT@ xmlwf/xmlfile.@OBJEXT@ xmlwf/codepage.@OBJEXT@ xmlwf/xmlwf.@OBJEXT@: xmlwf/xmlwf.c xmlwf/xmlfile.@OBJEXT@: xmlwf/xmlfile.c xmlwf/codepage.@OBJEXT@: xmlwf/codepage.c -xmlwf/@FILEMAP@.@OBJEXT@: xmlwf/@FILEMAP@.c +xmlwf/@FILEMAP@.@OBJEXT@: xmlwf/@FILEMAP@.c xmlwf/filemap.h xmlwf/xmlwf@EXEEXT@: $(XMLWF_OBJS) $(LIBRARY) $(LINK_EXE) $(XMLWF_OBJS) $(LIBRARY) examples/elements.@OBJEXT@: examples/elements.c examples/elements: examples/elements.@OBJEXT@ $(LIBRARY) - $(LINK_EXE) $< $(LIBRARY) + $(LINK_EXE) examples/elements.@OBJEXT@ $(LIBRARY) examples/outline.@OBJEXT@: examples/outline.c examples/outline: examples/outline.@OBJEXT@ $(LIBRARY) - $(LINK_EXE) $< $(LIBRARY) + $(LINK_EXE) examples/outline.@OBJEXT@ $(LIBRARY) tests/chardata.@OBJEXT@: tests/chardata.c tests/chardata.h tests/minicheck.@OBJEXT@: tests/minicheck.c tests/minicheck.h -tests/runtests.@OBJEXT@: tests/runtests.c tests/chardata.h -tests/runtests: tests/runtests.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY) - $(LINK_EXE) tests/runtests.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY) -tests/runtestspp.@OBJEXT@: tests/runtestspp.cpp tests/runtests.c tests/chardata.h -tests/runtestspp: tests/runtestspp.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY) - $(LINK_CXX_EXE) tests/runtestspp.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY) +tests/memcheck.@OBJEXT@: tests/memcheck.c tests/memcheck.h +tests/runtests.@OBJEXT@: tests/runtests.c tests/chardata.h tests/memcheck.h lib/siphash.h +tests/runtests@EXEEXT@: tests/runtests.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ tests/memcheck.@OBJEXT@ $(LIBRARY) + $(LINK_EXE) tests/runtests.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ tests/memcheck.@OBJEXT@ $(LIBRARY) +tests/runtestspp.@OBJEXT@: tests/runtestspp.cpp tests/runtests.c tests/chardata.h tests/memcheck.h +tests/runtestspp@EXEEXT@: tests/runtestspp.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ tests/memcheck.@OBJEXT@ $(LIBRARY) + $(LINK_CXX_EXE) tests/runtestspp.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ tests/memcheck.@OBJEXT@ $(LIBRARY) tests/benchmark/benchmark.@OBJEXT@: tests/benchmark/benchmark.c tests/benchmark/benchmark: tests/benchmark/benchmark.@OBJEXT@ $(LIBRARY) @@ -178,13 +182,21 @@ run-benchmark: tests/benchmark/benchmark tests/xmlts.zip: wget --output-document=tests/xmlts.zip \ - http://www.w3.org/XML/Test/xmlts20080827.zip + https://www.w3.org/XML/Test/xmlts20080827.zip -tests/XML-Test-Suite: tests/xmlts.zip +tests/xmlconf: tests/xmlts.zip cd tests && unzip -q xmlts.zip -run-xmltest: xmlwf/xmlwf@EXEEXT@ tests/XML-Test-Suite - tests/xmltest.sh +run-xmltest: xmlwf/xmlwf@EXEEXT@ tests/xmlconf + tests/xmltest.sh "$(PWD)/run.sh $(PWD)/xmlwf/xmlwf@EXEEXT@" 2>&1 | tee tests/xmltest.log + diff -u -b tests/xmltest.log.expected tests/xmltest.log + +.PHONY: qa +qa: + ./qa.sh address + ./qa.sh memory + ./qa.sh undefined + ./qa.sh coverage .SUFFIXES: .c .cpp .lo .@OBJEXT@ diff --git a/lib-src/expat/README b/lib-src/expat/README index 1f88467d1..cd11a226c 100644 --- a/lib-src/expat/README +++ b/lib-src/expat/README @@ -1,5 +1,5 @@ - Expat, Release 2.1.0 + Expat, Release 2.2.1 This is Expat, a C library for parsing XML, written by James Clark. Expat is a stream-oriented XML parser. This means that you register @@ -114,7 +114,7 @@ Note for Solaris users: The "ar" command is usually located in "/usr/ccs/bin", which is not in the default PATH. You will need to add this to your path for the "make" command, and probably also switch to GNU make (the "make" found in /usr/ccs/bin does not seem to work -properly -- appearantly it does not understand .PHONY directives). If +properly -- apparently it does not understand .PHONY directives). If you're using ksh or bash, use this command to build: PATH=/usr/ccs/bin:$PATH make diff --git a/lib-src/expat/conftools/ac_c_bigendian_cross.m4 b/lib-src/expat/conftools/ac_c_bigendian_cross.m4 index 8ed3edb24..e95ffb6dc 100644 --- a/lib-src/expat/conftools/ac_c_bigendian_cross.m4 +++ b/lib-src/expat/conftools/ac_c_bigendian_cross.m4 @@ -7,7 +7,7 @@ dnl The implementation will create a binary, and instead of running dnl the binary it will be grep'ed for some symbols that will look dnl different for different endianess of the binary. dnl -dnl @version $Id: ac_c_bigendian_cross.m4,v 1.2 2001/10/01 20:03:13 fdrake Exp $ +dnl @version $Id: ac_c_bigendian_cross.m4,v 1.1 2001/07/24 19:51:35 fdrake Exp $ dnl @author Guido Draheim dnl AC_DEFUN([AC_C_BIGENDIAN_CROSS], diff --git a/lib-src/expat/conftools/mkinstalldirs b/lib-src/expat/conftools/mkinstalldirs index c5291db03..4f58503ea 100755 --- a/lib-src/expat/conftools/mkinstalldirs +++ b/lib-src/expat/conftools/mkinstalldirs @@ -4,7 +4,7 @@ # Created: 1993-05-16 # Public domain -# $Id: mkinstalldirs,v 1.1 2000/09/18 16:26:21 coopercc Exp $ +# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $ errstatus=0 diff --git a/lib-src/expat/doc/expat.png b/lib-src/expat/doc/expat.png index 5bc0726cfd8508d0aa53cf53486b0330780b5f21..3d88eac4a1339b2453d6d7be388ae61f658da0f7 100644 GIT binary patch delta 10 RcmZqXXyw?z%);cr1pp480vrGU delta 7 OcmZqWXy(|!%mM%iqXEzW diff --git a/lib-src/expat/doc/reference.html b/lib-src/expat/doc/reference.html index 8811a3397..350b9b67c 100644 --- a/lib-src/expat/doc/reference.html +++ b/lib-src/expat/doc/reference.html @@ -277,7 +277,7 @@ directions or Unix directions below.

If you're using the GNU compiler under cygwin, follow the Unix directions in the next section. Otherwise if you have Microsoft's Developer Studio installed, then from Windows Explorer double-click on -"expat.dsp" in the lib directory and build and install in the usual +"expat.vcxproj" in the lib directory and build and install in the usual manner.

Alternatively, you may download the Win32 binary package that @@ -2151,8 +2151,12 @@ 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 XML_Parse or XML_ParseBuffer. -

Note: 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.

+

Note: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. +

Note:One should not call XML_SetHashSalt with a +hash salt value of 0, as this value is used as sentinel value to indicate +that XML_SetHashSalt has not been called. Consequently +such a call will have no effect, even if it returns 1.

diff --git a/lib-src/expat/doc/valid-xhtml10.png b/lib-src/expat/doc/valid-xhtml10.png
index 4c23f48fe02a58fbb3d1088e6a7d372568830b53..2f755c62b526e1c2ee8f14db7bf6a8c52d431ced 100644
GIT binary patch
delta 10
RcmX>gbVz7}11FOM7XTE_0_*?)

delta 7
OcmX>kbU11A6sVgjH5

diff --git a/lib-src/expat/examples/elements.c b/lib-src/expat/examples/elements.c
index 6b8f85501..fe1699c50 100644
--- a/lib-src/expat/examples/elements.c
+++ b/lib-src/expat/examples/elements.c
@@ -6,11 +6,7 @@
 */
 
 #include 
-#include "expat.h"
-
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include 
-#endif
+#include 
 
 #ifdef XML_LARGE_SIZE
 #if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
@@ -27,6 +23,8 @@ startElement(void *userData, const char *name, const char **atts)
 {
   int i;
   int *depthPtr = (int *)userData;
+  (void)atts;
+
   for (i = 0; i < *depthPtr; i++)
     putchar('\t');
   puts(name);
@@ -37,6 +35,8 @@ static void XMLCALL
 endElement(void *userData, const char *name)
 {
   int *depthPtr = (int *)userData;
+  (void)name;
+
   *depthPtr -= 1;
 }
 
@@ -47,10 +47,13 @@ main(int argc, char *argv[])
   XML_Parser parser = XML_ParserCreate(NULL);
   int done;
   int depth = 0;
+  (void)argc;
+  (void)argv;
+
   XML_SetUserData(parser, &depth);
   XML_SetElementHandler(parser, startElement, endElement);
   do {
-    int len = (int)fread(buf, 1, sizeof(buf), stdin);
+    size_t len = fread(buf, 1, sizeof(buf), stdin);
     done = len < sizeof(buf);
     if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) {
       fprintf(stderr,
diff --git a/lib-src/expat/examples/outline.c b/lib-src/expat/examples/outline.c
index 3a3c83855..2d1e63c36 100644
--- a/lib-src/expat/examples/outline.c
+++ b/lib-src/expat/examples/outline.c
@@ -25,10 +25,6 @@
 #include 
 #include 
 
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include 
-#endif
-
 #ifdef XML_LARGE_SIZE
 #if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
 #define XML_FMT_INT_MOD "I64"
@@ -49,6 +45,7 @@ static void XMLCALL
 start(void *data, const char *el, const char **attr)
 {
   int i;
+  (void)data;
 
   for (i = 0; i < Depth; i++)
     printf("  ");
@@ -66,6 +63,9 @@ start(void *data, const char *el, const char **attr)
 static void XMLCALL
 end(void *data, const char *el)
 {
+  (void)data;
+  (void)el;
+
   Depth--;
 }
 
@@ -73,6 +73,9 @@ int
 main(int argc, char *argv[])
 {
   XML_Parser p = XML_ParserCreate(NULL);
+  (void)argc;
+  (void)argv;
+
   if (! p) {
     fprintf(stderr, "Couldn't allocate memory for parser\n");
     exit(-1);
diff --git a/lib-src/expat/lib/expat.h b/lib-src/expat/lib/expat.h
index 9a21680be..28b0f954d 100644
--- a/lib-src/expat/lib/expat.h
+++ b/lib-src/expat/lib/expat.h
@@ -95,7 +95,9 @@ enum XML_Error {
   /* Added in 2.0. */
   XML_ERROR_RESERVED_PREFIX_XML,
   XML_ERROR_RESERVED_PREFIX_XMLNS,
-  XML_ERROR_RESERVED_NAMESPACE_URI
+  XML_ERROR_RESERVED_NAMESPACE_URI,
+  /* Added in 2.2.1. */
+  XML_ERROR_INVALID_ARGUMENT
 };
 
 enum XML_Content_Type {
@@ -342,7 +344,7 @@ XML_SetEntityDeclHandler(XML_Parser parser,
                          XML_EntityDeclHandler handler);
 
 /* OBSOLETE -- OBSOLETE -- OBSOLETE
-   This handler has been superceded by the EntityDeclHandler above.
+   This handler has been superseded by the EntityDeclHandler above.
    It is provided here for backward compatibility.
 
    This is called for a declaration of an unparsed (NDATA) entity.
@@ -706,6 +708,7 @@ XML_UseParserAsHandlerArg(XML_Parser parser);
      be called, despite an external subset being parsed.
    Note: If XML_DTD is not defined when Expat is compiled, returns
      XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+   Note: If parser == NULL, returns XML_ERROR_INVALID_ARGUMENT.
 */
 XMLPARSEAPI(enum XML_Error)
 XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
@@ -729,15 +732,16 @@ XML_GetBase(XML_Parser parser);
    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
-   XML_StartElementHandler.
+   XML_StartElementHandler.  Returns -1 if parser == NULL.
 */
 XMLPARSEAPI(int)
 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.  Each
-   attribute/value pair counts as 2; thus this correspondds to an
-   index into the atts array passed to the XML_StartElementHandler.
+   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
+   XML_StartElementHandler.
 */
 XMLPARSEAPI(int)
 XML_GetIdAttributeIndex(XML_Parser parser);
@@ -901,6 +905,7 @@ enum XML_ParamEntityParsing {
    entities is requested; otherwise it will return non-zero.
    Note: If XML_SetParamEntityParsing is called after XML_Parse or
       XML_ParseBuffer, then it has no effect and will always return 0.
+   Note: If parser == NULL, the function will do nothing and return 0.
 */
 XMLPARSEAPI(int)
 XML_SetParamEntityParsing(XML_Parser parser,
@@ -910,6 +915,7 @@ XML_SetParamEntityParsing(XML_Parser parser,
    Helps in preventing DoS attacks based on predicting hash
    function behavior. This must be called before parsing is started.
    Returns 1 if successful, 0 when called after parsing has started.
+   Note: If parser == NULL, the function will do nothing and return 0.
 */
 XMLPARSEAPI(int)
 XML_SetHashSalt(XML_Parser parser,
@@ -936,6 +942,10 @@ XML_GetErrorCode(XML_Parser parser);
    the location is the location of the character at which the error
    was detected; otherwise the location is the location of the last
    parse event, as described above.
+
+   Note: XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber
+   return 0 to indicate an error.
+   Note: XML_GetCurrentByteIndex returns -1 to indicate an error.
 */
 XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
 XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
@@ -973,9 +983,12 @@ XML_FreeContentModel(XML_Parser parser, XML_Content *model);
 
 /* Exposing the memory handling functions used in Expat */
 XMLPARSEAPI(void *)
+XML_ATTR_MALLOC
+XML_ATTR_ALLOC_SIZE(2)
 XML_MemMalloc(XML_Parser parser, size_t size);
 
 XMLPARSEAPI(void *)
+XML_ATTR_ALLOC_SIZE(3)
 XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
 
 XMLPARSEAPI(void)
@@ -1031,14 +1044,12 @@ XMLPARSEAPI(const XML_Feature *)
 XML_GetFeatureList(void);
 
 
-/* Expat follows the GNU/Linux convention of odd number minor version for
-   beta/development releases and even number minor version for stable
-   releases. Micro is bumped with each release, and set to 0 with each
-   change to major or minor version.
+/* Expat follows the semantic versioning convention.
+   See http://semver.org.
 */
 #define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 1
-#define XML_MICRO_VERSION 0
+#define XML_MINOR_VERSION 2
+#define XML_MICRO_VERSION 1
 
 #ifdef __cplusplus
 }
diff --git a/lib-src/expat/lib/expat_external.h b/lib-src/expat/lib/expat_external.h
index 2c03284ea..892eb4bbe 100644
--- a/lib-src/expat/lib/expat_external.h
+++ b/lib-src/expat/lib/expat_external.h
@@ -65,12 +65,26 @@
 #endif
 #endif  /* not defined XML_STATIC */
 
+#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
+#define XMLIMPORT __attribute__ ((visibility ("default")))
+#endif
 
 /* If we didn't define it above, define it away: */
 #ifndef XMLIMPORT
 #define XMLIMPORT
 #endif
 
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+#define XML_ATTR_MALLOC __attribute__((__malloc__))
+#else
+#define XML_ATTR_MALLOC
+#endif
+
+#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+#define XML_ATTR_ALLOC_SIZE(x)  __attribute__((__alloc_size__(x)))
+#else
+#define XML_ATTR_ALLOC_SIZE(x)
+#endif
 
 #define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
 
@@ -79,7 +93,10 @@ extern "C" {
 #endif
 
 #ifdef XML_UNICODE_WCHAR_T
-#define XML_UNICODE
+# define XML_UNICODE
+# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
+#  error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
+# endif
 #endif
 
 #ifdef XML_UNICODE     /* Information is UTF-16 encoded. */
diff --git a/lib-src/expat/lib/internal.h b/lib-src/expat/lib/internal.h
index dd5454831..94cb98e15 100644
--- a/lib-src/expat/lib/internal.h
+++ b/lib-src/expat/lib/internal.h
@@ -71,3 +71,25 @@
 #define inline
 #endif
 #endif
+
+#ifndef UNUSED_P
+# ifdef __GNUC__
+#  define UNUSED_P(p) UNUSED_ ## p __attribute__((__unused__))
+# else
+#  define UNUSED_P(p) UNUSED_ ## p
+# endif
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void
+align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib-src/expat/lib/libexpat.def b/lib-src/expat/lib/libexpat.def
index 3920bbcf9..79b049116 100644
--- a/lib-src/expat/lib/libexpat.def
+++ b/lib-src/expat/lib/libexpat.def
@@ -71,3 +71,6 @@ EXPORTS
   XML_StopParser @63
   XML_ResumeParser @64
   XML_GetParsingStatus @65
+; added with version 2.1.1
+; XML_GetAttributeInfo @66
+  XML_SetHashSalt @67@
diff --git a/lib-src/expat/lib/libexpatw.def b/lib-src/expat/lib/libexpatw.def
index 3920bbcf9..79b049116 100644
--- a/lib-src/expat/lib/libexpatw.def
+++ b/lib-src/expat/lib/libexpatw.def
@@ -71,3 +71,6 @@ EXPORTS
   XML_StopParser @63
   XML_ResumeParser @64
   XML_GetParsingStatus @65
+; added with version 2.1.1
+; XML_GetAttributeInfo @66
+  XML_SetHashSalt @67@
diff --git a/lib-src/expat/lib/siphash.h b/lib-src/expat/lib/siphash.h
new file mode 100644
index 000000000..23b56d2ae
--- /dev/null
+++ b/lib-src/expat/lib/siphash.h
@@ -0,0 +1,344 @@
+/* ==========================================================================
+ * siphash.h - SipHash-2-4 in a single header file
+ * --------------------------------------------------------------------------
+ * Derived by William Ahern from the reference implementation[1] published[2]
+ * by Jean-Philippe Aumasson and Daniel J. Berstein. Licensed in kind.
+ * by Jean-Philippe Aumasson and Daniel J. Berstein.
+ * Minimal changes by Sebastian Pipping on top, details below.
+ * Licensed under the CC0 Public Domain Dedication license.
+ *
+ * 1. https://www.131002.net/siphash/siphash24.c
+ * 2. https://www.131002.net/siphash/
+ * --------------------------------------------------------------------------
+ * HISTORY:
+ *
+ * 2017-06-10  (Sebastian Pipping)
+ *   - Clarify license note in the header
+ *   - Address C89 issues:
+ *     - Stop using inline keyword (and let compiler decide)
+ *     - Turn integer suffix ULL to UL
+ *     - Replace _Bool by int
+ *     - Turn macro siphash24 into a function
+ *     - Address invalid conversion (void pointer) by explicit cast
+ *   - Always expose sip24_valid (for self-tests)
+ *
+ * 2012-11-04 - Born.  (William Ahern)
+ * --------------------------------------------------------------------------
+ * USAGE:
+ *
+ * SipHash-2-4 takes as input two 64-bit words as the key, some number of
+ * message bytes, and outputs a 64-bit word as the message digest. This
+ * implementation employs two data structures: a struct sipkey for
+ * representing the key, and a struct siphash for representing the hash
+ * state.
+ *
+ * For converting a 16-byte unsigned char array to a key, use either the
+ * macro sip_keyof or the routine sip_tokey. The former instantiates a
+ * compound literal key, while the latter requires a key object as a
+ * parameter.
+ *
+ * 	unsigned char secret[16];
+ * 	arc4random_buf(secret, sizeof secret);
+ * 	struct sipkey *key = sip_keyof(secret);
+ *
+ * For hashing a message, use either the convenience macro siphash24 or the
+ * routines sip24_init, sip24_update, and sip24_final.
+ *
+ * 	struct siphash state;
+ * 	void *msg;
+ * 	size_t len;
+ * 	uint64_t hash;
+ *
+ * 	sip24_init(&state, key);
+ * 	sip24_update(&state, msg, len);
+ * 	hash = sip24_final(&state);
+ *
+ * or
+ *
+ * 	hash = siphash24(msg, len, key);
+ *
+ * To convert the 64-bit hash value to a canonical 8-byte little-endian
+ * binary representation, use either the macro sip_binof or the routine
+ * sip_tobin. The former instantiates and returns a compound literal array,
+ * while the latter requires an array object as a parameter.
+ * --------------------------------------------------------------------------
+ * NOTES:
+ *
+ * o Neither sip_keyof, sip_binof, nor siphash24 will work with compilers
+ *   lacking compound literal support. Instead, you must use the lower-level
+ *   interfaces which take as parameters the temporary state objects.
+ *
+ * o Uppercase macros may evaluate parameters more than once. Lowercase
+ *   macros should not exhibit any such side effects.
+ * ==========================================================================
+ */
+#ifndef SIPHASH_H
+#define SIPHASH_H
+
+#include  /* size_t */
+#include  /* uint64_t uint32_t uint8_t */
+
+
+#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ( (x) >> (64 - (b))))
+
+#define SIP_U32TO8_LE(p, v) \
+	(p)[0] = (uint8_t)((v) >>  0); (p)[1] = (uint8_t)((v) >>  8); \
+	(p)[2] = (uint8_t)((v) >> 16); (p)[3] = (uint8_t)((v) >> 24);
+
+#define SIP_U64TO8_LE(p, v) \
+	SIP_U32TO8_LE((p) + 0, (uint32_t)((v) >>  0)); \
+	SIP_U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
+
+#define SIP_U8TO64_LE(p) \
+	(((uint64_t)((p)[0]) <<  0) | \
+	 ((uint64_t)((p)[1]) <<  8) | \
+	 ((uint64_t)((p)[2]) << 16) | \
+	 ((uint64_t)((p)[3]) << 24) | \
+	 ((uint64_t)((p)[4]) << 32) | \
+	 ((uint64_t)((p)[5]) << 40) | \
+	 ((uint64_t)((p)[6]) << 48) | \
+	 ((uint64_t)((p)[7]) << 56))
+
+
+#define SIPHASH_INITIALIZER { 0, 0, 0, 0, { 0 }, 0, 0 }
+
+struct siphash {
+	uint64_t v0, v1, v2, v3;
+
+	unsigned char buf[8], *p;
+	uint64_t c;
+}; /* struct siphash */
+
+
+#define SIP_KEYLEN 16
+
+struct sipkey {
+	uint64_t k[2];
+}; /* struct sipkey */
+
+#define sip_keyof(k) sip_tokey(&(struct sipkey){ { 0 } }, (k))
+
+static struct sipkey *sip_tokey(struct sipkey *key, const void *src) {
+	key->k[0] = SIP_U8TO64_LE((const unsigned char *)src);
+	key->k[1] = SIP_U8TO64_LE((const unsigned char *)src + 8);
+	return key;
+} /* sip_tokey() */
+
+
+#define sip_binof(v) sip_tobin((unsigned char[8]){ 0 }, (v))
+
+static void *sip_tobin(void *dst, uint64_t u64) {
+	SIP_U64TO8_LE((unsigned char *)dst, u64);
+	return dst;
+} /* sip_tobin() */
+
+
+static void sip_round(struct siphash *H, const int rounds) {
+	int i;
+
+	for (i = 0; i < rounds; i++) {
+		H->v0 += H->v1;
+		H->v1 = SIP_ROTL(H->v1, 13);
+		H->v1 ^= H->v0;
+		H->v0 = SIP_ROTL(H->v0, 32);
+
+		H->v2 += H->v3;
+		H->v3 = SIP_ROTL(H->v3, 16);
+		H->v3 ^= H->v2;
+
+		H->v0 += H->v3;
+		H->v3 = SIP_ROTL(H->v3, 21);
+		H->v3 ^= H->v0;
+
+		H->v2 += H->v1;
+		H->v1 = SIP_ROTL(H->v1, 17);
+		H->v1 ^= H->v2;
+		H->v2 = SIP_ROTL(H->v2, 32);
+	}
+} /* sip_round() */
+
+
+static struct siphash *sip24_init(struct siphash *H, const struct sipkey *key) {
+	H->v0 = 0x736f6d6570736575UL ^ key->k[0];
+	H->v1 = 0x646f72616e646f6dUL ^ key->k[1];
+	H->v2 = 0x6c7967656e657261UL ^ key->k[0];
+	H->v3 = 0x7465646279746573UL ^ key->k[1];
+
+	H->p = H->buf;
+	H->c = 0;
+
+	return H;
+} /* sip24_init() */
+
+
+#define sip_endof(a) (&(a)[sizeof (a) / sizeof *(a)])
+
+static struct siphash *sip24_update(struct siphash *H, const void *src, size_t len) {
+	const unsigned char *p = (const unsigned char *)src, *pe = p + len;
+	uint64_t m;
+
+	do {
+		while (p < pe && H->p < sip_endof(H->buf))
+			*H->p++ = *p++;
+
+		if (H->p < sip_endof(H->buf))
+			break;
+
+		m = SIP_U8TO64_LE(H->buf);
+		H->v3 ^= m;
+		sip_round(H, 2);
+		H->v0 ^= m;
+
+		H->p = H->buf;
+		H->c += 8;
+	} while (p < pe);
+
+	return H;
+} /* sip24_update() */
+
+
+static uint64_t sip24_final(struct siphash *H) {
+	char left = H->p - H->buf;
+	uint64_t b = (H->c + left) << 56;
+
+	switch (left) {
+	case 7: b |= (uint64_t)H->buf[6] << 48;
+	case 6: b |= (uint64_t)H->buf[5] << 40;
+	case 5: b |= (uint64_t)H->buf[4] << 32;
+	case 4: b |= (uint64_t)H->buf[3] << 24;
+	case 3: b |= (uint64_t)H->buf[2] << 16;
+	case 2: b |= (uint64_t)H->buf[1] << 8;
+	case 1: b |= (uint64_t)H->buf[0] << 0;
+	case 0: break;
+	}
+
+	H->v3 ^= b;
+	sip_round(H, 2);
+	H->v0 ^= b;
+	H->v2 ^= 0xff;
+	sip_round(H, 4);
+
+	return H->v0 ^ H->v1 ^ H->v2  ^ H->v3;
+} /* sip24_final() */
+
+
+static uint64_t siphash24(const void *src, size_t len, const struct sipkey *key) {
+	struct siphash state = SIPHASH_INITIALIZER;
+	return sip24_final(sip24_update(sip24_init(&state, key), src, len));
+} /* siphash24() */
+
+
+/*
+ * SipHash-2-4 output with
+ * k = 00 01 02 ...
+ * and
+ * in = (empty string)
+ * in = 00 (1 byte)
+ * in = 00 01 (2 bytes)
+ * in = 00 01 02 (3 bytes)
+ * ...
+ * in = 00 01 02 ... 3e (63 bytes)
+ */
+static int sip24_valid(void) {
+	static const unsigned char vectors[64][8] = {
+		{ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+		{ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+		{ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+		{ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+		{ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+		{ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+		{ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+		{ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+		{ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+		{ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+		{ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+		{ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+		{ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+		{ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+		{ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+		{ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+		{ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+		{ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+		{ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+		{ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+		{ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+		{ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+		{ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+		{ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+		{ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+		{ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+		{ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+		{ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+		{ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+		{ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+		{ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+		{ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+		{ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+		{ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+		{ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+		{ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+		{ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+		{ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+		{ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+		{ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+		{ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+		{ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+		{ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+		{ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+		{ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+		{ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+		{ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+		{ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+		{ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+		{ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+		{ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+		{ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+		{ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+		{ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+		{ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+		{ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+		{ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+		{ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+		{ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+		{ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+		{ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+		{ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+		{ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+		{ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+	};
+	unsigned char in[64];
+	struct sipkey k;
+	size_t i;
+
+	sip_tokey(&k, "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017");
+
+	for (i = 0; i < sizeof in; ++i) {
+		in[i] = i;
+
+		if (siphash24(in, i, &k) != SIP_U8TO64_LE(vectors[i]))
+			return 0;
+	}
+
+	return 1;
+} /* sip24_valid() */
+
+
+#if SIPHASH_MAIN
+
+#include 
+
+int main(void) {
+	int ok = sip24_valid();
+
+	if (ok)
+		puts("OK");
+	else
+		puts("FAIL");
+
+	return !ok;
+} /* main() */
+
+#endif /* SIPHASH_MAIN */
+
+
+#endif /* SIPHASH_H */
diff --git a/lib-src/expat/lib/winconfig.h b/lib-src/expat/lib/winconfig.h
index c1b791d62..9bf014d7f 100644
--- a/lib-src/expat/lib/winconfig.h
+++ b/lib-src/expat/lib/winconfig.h
@@ -17,6 +17,12 @@
 #include 
 #include 
 
+
+#if defined(HAVE_EXPAT_CONFIG_H)  /* e.g. MinGW */
+# include 
+#else  /* !defined(HAVE_EXPAT_CONFIG_H) */
+
+
 #define XML_NS 1
 #define XML_DTD 1
 #define XML_CONTEXT_BYTES 1024
@@ -27,4 +33,8 @@
 /* Windows has memmove() available. */
 #define HAVE_MEMMOVE
 
+
+#endif /* !defined(HAVE_EXPAT_CONFIG_H) */
+
+
 #endif /* ndef WINCONFIG_H */
diff --git a/lib-src/expat/lib/xmlparse.c b/lib-src/expat/lib/xmlparse.c
index f35aa36ba..76f078e25 100644
--- a/lib-src/expat/lib/xmlparse.c
+++ b/lib-src/expat/lib/xmlparse.c
@@ -1,29 +1,37 @@
 /* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
    See the file COPYING for copying permission.
+
+   77fea421d361dca90041d0040ecf1dca651167fadf2af79e990e35168d70d933 (2.2.1+)
 */
 
+#define _GNU_SOURCE                     /* syscall prototype */
+
 #include 
 #include                      /* memset(), memcpy() */
 #include 
 #include                      /* UINT_MAX */
-#include                        /* time() */
+#include                       /* fprintf */
+#include                      /* getenv */
+
+#ifdef _WIN32
+#define getpid GetCurrentProcessId
+#else
+#include                    /* gettimeofday() */
+#include                   /* getpid() */
+#include                      /* getpid() */
+#endif
 
 #define XML_BUILDING_EXPAT 1
 
-#ifdef COMPILED_FROM_DSP
+#ifdef _WIN32
 #include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
 #elif defined(HAVE_EXPAT_CONFIG_H)
 #include 
-#endif /* ndef COMPILED_FROM_DSP */
+#endif /* ndef _WIN32 */
 
 #include "ascii.h"
 #include "expat.h"
+#include "siphash.h"
 
 #ifdef XML_UNICODE
 #define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
@@ -102,17 +110,11 @@ typedef struct {
   const XML_Memory_Handling_Suite *mem;
 } HASH_TABLE;
 
-/* Basic character hash algorithm, taken from Python's string hash:
-   h = h * 1000003 ^ character, the constant being a prime number.
+static size_t
+keylen(KEY s);
 
-*/
-#ifdef XML_UNICODE
-#define CHAR_HASH(h, c) \
-  (((h) * 0xF4243) ^ (unsigned short)(c))
-#else
-#define CHAR_HASH(h, c) \
-  (((h) * 0xF4243) ^ (unsigned char)(c))
-#endif
+static void
+copy_salt_to_sipkey(XML_Parser parser, struct sipkey * key);
 
 /* For probing (after a collision) we need a step size relative prime
    to the hash table size, which is a power of 2. We use double-hashing,
@@ -348,6 +350,8 @@ doIgnoreSection(XML_Parser parser, const ENCODING *, 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);
@@ -432,7 +436,7 @@ static ELEMENT_TYPE *
 getElementType(XML_Parser parser, const ENCODING *enc,
                const char *ptr, const char *end);
 
-static unsigned long generate_hash_secret_salt(void);
+static unsigned long generate_hash_secret_salt(XML_Parser parser);
 static XML_Bool startParsing(XML_Parser parser);
 
 static XML_Parser
@@ -690,12 +694,155 @@ static const XML_Char implicitContext[] = {
   ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
 };
 
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+# include 
+
+# if defined(HAVE_GETRANDOM)
+#  include     /* getrandom */
+# else
+#  include         /* syscall */
+#  include    /* SYS_getrandom */
+# endif
+
+/* Obtain entropy on Linux 3.17+ */
+static int
+writeRandomBytes_getrandom(void * target, size_t count) {
+  int success = 0;  /* full count bytes written? */
+  size_t bytesWrittenTotal = 0;
+  const unsigned int getrandomFlags = 0;
+
+  do {
+    void * const currentTarget = (void*)((char*)target + bytesWrittenTotal);
+    const size_t bytesToWrite = count - bytesWrittenTotal;
+
+    const int bytesWrittenMore =
+#if defined(HAVE_GETRANDOM)
+        getrandom(currentTarget, bytesToWrite, getrandomFlags);
+#else
+        syscall(SYS_getrandom, currentTarget, bytesToWrite, getrandomFlags);
+#endif
+
+    if (bytesWrittenMore > 0) {
+      bytesWrittenTotal += bytesWrittenMore;
+      if (bytesWrittenTotal >= count)
+        success = 1;
+    }
+  } while (! success && (errno == EINTR || errno == EAGAIN));
+
+  return success;
+}
+
+#endif  /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
+
+
+#ifdef _WIN32
+
+typedef BOOLEAN (APIENTRY *RTLGENRANDOM_FUNC)(PVOID, ULONG);
+
+/* Obtain entropy on Windows XP / Windows Server 2003 and later.
+ * Hint on RtlGenRandom and the following article from libsodioum.
+ *
+ * Michael Howard: Cryptographically Secure Random number on Windows without using CryptoAPI
+ * https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/
+ */
+static int
+writeRandomBytes_RtlGenRandom(void * target, size_t count) {
+  int success = 0;  /* full count bytes written? */
+  const HMODULE advapi32 = LoadLibrary("ADVAPI32.DLL");
+
+  if (advapi32) {
+    const RTLGENRANDOM_FUNC RtlGenRandom
+        = (RTLGENRANDOM_FUNC)GetProcAddress(advapi32, "SystemFunction036");
+    if (RtlGenRandom) {
+      if (RtlGenRandom((PVOID)target, (ULONG)count) == TRUE) {
+        success = 1;
+      }
+    }
+    FreeLibrary(advapi32);
+  }
+
+  return success;
+}
+
+#endif /* _WIN32 */
+
+
 static unsigned long
-generate_hash_secret_salt(void)
+gather_time_entropy(void)
 {
-  unsigned int seed = time(NULL) % UINT_MAX;
-  srand(seed);
-  return rand();
+#ifdef _WIN32
+  FILETIME ft;
+  GetSystemTimeAsFileTime(&ft); /* never fails */
+  return ft.dwHighDateTime ^ ft.dwLowDateTime;
+#else
+  struct timeval tv;
+  int gettimeofday_res;
+
+  gettimeofday_res = gettimeofday(&tv, NULL);
+  assert (gettimeofday_res == 0);
+
+  /* Microseconds time is <20 bits entropy */
+  return tv.tv_usec;
+#endif
+}
+
+#if defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_LIBBSD)
+# include 
+#endif
+
+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,
+        (int)sizeof(entropy) * 2, entropy,
+        (unsigned long)sizeof(entropy));
+  }
+  return entropy;
+}
+
+static unsigned long
+generate_hash_secret_salt(XML_Parser parser)
+{
+  unsigned long entropy;
+  (void)parser;
+#if defined(HAVE_ARC4RANDOM_BUF) || defined(__CloudABI__)
+  (void)gather_time_entropy;
+  arc4random_buf(&entropy, sizeof(entropy));
+  return ENTROPY_DEBUG("arc4random_buf", entropy);
+#else
+  /* Try high quality providers first .. */
+#ifdef _WIN32
+  if (writeRandomBytes_RtlGenRandom((void *)&entropy, sizeof(entropy))) {
+    return ENTROPY_DEBUG("RtlGenRandom", entropy);
+  }
+#elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+  if (writeRandomBytes_getrandom((void *)&entropy, sizeof(entropy))) {
+    return ENTROPY_DEBUG("getrandom", entropy);
+  }
+#endif
+  /* .. and self-made low quality for backup: */
+
+  /* Process ID is 0 bits entropy if attacker has local access */
+  entropy = gather_time_entropy() ^ getpid();
+
+  /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
+  if (sizeof(unsigned long) == 4) {
+    return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647);
+  } else {
+    return ENTROPY_DEBUG("fallback(8)",
+        entropy * (unsigned long)2305843009213693951);
+  }
+#endif
+}
+
+static unsigned long
+get_hash_secret_salt(XML_Parser parser) {
+  if (parser->m_parentParser != NULL)
+    return get_hash_secret_salt(parser->m_parentParser);
+  return parser->m_hash_secret_salt;
 }
 
 static XML_Bool  /* only valid for root parser */
@@ -703,7 +850,7 @@ startParsing(XML_Parser parser)
 {
     /* hash functions must be initialized before setContext() is called */
     if (hash_secret_salt == 0)
-      hash_secret_salt = generate_hash_secret_salt();
+      hash_secret_salt = generate_hash_secret_salt(parser);
     if (ns) {
       /* implicit context only set for root parser, since child
          parsers (i.e. external entity parsers) will inherit it
@@ -926,6 +1073,10 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
 {
   TAG *tStk;
   OPEN_INTERNAL_ENTITY *openEntityList;
+
+  if (parser == NULL)
+      return XML_FALSE;
+
   if (parentParser)
     return XML_FALSE;
   /* move tagStack to freeTagList */
@@ -960,6 +1111,8 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
 enum XML_Status XMLCALL
 XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
 {
+  if (parser == NULL)
+      return XML_STATUS_ERROR;
   /* Block after XML_Parse()/XML_ParseBuffer() has been called.
      XXX There's no way for the caller to determine which of the
      XXX possible error cases caused the XML_STATUS_ERROR return.
@@ -983,52 +1136,88 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
 {
   XML_Parser parser = oldParser;
   DTD *newDtd = NULL;
-  DTD *oldDtd = _dtd;
-  XML_StartElementHandler oldStartElementHandler = startElementHandler;
-  XML_EndElementHandler oldEndElementHandler = endElementHandler;
-  XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
-  XML_ProcessingInstructionHandler oldProcessingInstructionHandler
-      = processingInstructionHandler;
-  XML_CommentHandler oldCommentHandler = commentHandler;
-  XML_StartCdataSectionHandler oldStartCdataSectionHandler
-      = startCdataSectionHandler;
-  XML_EndCdataSectionHandler oldEndCdataSectionHandler
-      = endCdataSectionHandler;
-  XML_DefaultHandler oldDefaultHandler = defaultHandler;
-  XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
-      = unparsedEntityDeclHandler;
-  XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
-  XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
-      = startNamespaceDeclHandler;
-  XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
-      = endNamespaceDeclHandler;
-  XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
-  XML_ExternalEntityRefHandler oldExternalEntityRefHandler
-      = externalEntityRefHandler;
-  XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
-  XML_UnknownEncodingHandler oldUnknownEncodingHandler
-      = unknownEncodingHandler;
-  XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
-  XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
-  XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
-  XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
-  ELEMENT_TYPE * oldDeclElementType = declElementType;
+  DTD *oldDtd;
+  XML_StartElementHandler oldStartElementHandler;
+  XML_EndElementHandler oldEndElementHandler;
+  XML_CharacterDataHandler oldCharacterDataHandler;
+  XML_ProcessingInstructionHandler oldProcessingInstructionHandler;
+  XML_CommentHandler oldCommentHandler;
+  XML_StartCdataSectionHandler oldStartCdataSectionHandler;
+  XML_EndCdataSectionHandler oldEndCdataSectionHandler;
+  XML_DefaultHandler oldDefaultHandler;
+  XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler;
+  XML_NotationDeclHandler oldNotationDeclHandler;
+  XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler;
+  XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler;
+  XML_NotStandaloneHandler oldNotStandaloneHandler;
+  XML_ExternalEntityRefHandler oldExternalEntityRefHandler;
+  XML_SkippedEntityHandler oldSkippedEntityHandler;
+  XML_UnknownEncodingHandler oldUnknownEncodingHandler;
+  XML_ElementDeclHandler oldElementDeclHandler;
+  XML_AttlistDeclHandler oldAttlistDeclHandler;
+  XML_EntityDeclHandler oldEntityDeclHandler;
+  XML_XmlDeclHandler oldXmlDeclHandler;
+  ELEMENT_TYPE * oldDeclElementType;
 
-  void *oldUserData = userData;
-  void *oldHandlerArg = handlerArg;
-  XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
-  XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+  void *oldUserData;
+  void *oldHandlerArg;
+  XML_Bool oldDefaultExpandInternalEntities;
+  XML_Parser oldExternalEntityRefHandlerArg;
 #ifdef XML_DTD
-  enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
-  int oldInEntityValue = prologState.inEntityValue;
+  enum XML_ParamEntityParsing oldParamEntityParsing;
+  int oldInEntityValue;
 #endif
-  XML_Bool oldns_triplets = ns_triplets;
+  XML_Bool oldns_triplets;
   /* Note that the new parser shares the same hash secret as the old
      parser, so that dtdCopy and copyEntityTable can lookup values
      from hash tables associated with either parser without us having
      to worry which hash secrets each table has.
   */
-  unsigned long oldhash_secret_salt = hash_secret_salt;
+  unsigned long oldhash_secret_salt;
+
+  /* Validate the oldParser parameter before we pull everything out of it */
+  if (oldParser == NULL)
+    return NULL;
+
+  /* Stash the original parser contents on the stack */
+  oldDtd = _dtd;
+  oldStartElementHandler = startElementHandler;
+  oldEndElementHandler = endElementHandler;
+  oldCharacterDataHandler = characterDataHandler;
+  oldProcessingInstructionHandler = processingInstructionHandler;
+  oldCommentHandler = commentHandler;
+  oldStartCdataSectionHandler = startCdataSectionHandler;
+  oldEndCdataSectionHandler = endCdataSectionHandler;
+  oldDefaultHandler = defaultHandler;
+  oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler;
+  oldNotationDeclHandler = notationDeclHandler;
+  oldStartNamespaceDeclHandler = startNamespaceDeclHandler;
+  oldEndNamespaceDeclHandler = endNamespaceDeclHandler;
+  oldNotStandaloneHandler = notStandaloneHandler;
+  oldExternalEntityRefHandler = externalEntityRefHandler;
+  oldSkippedEntityHandler = skippedEntityHandler;
+  oldUnknownEncodingHandler = unknownEncodingHandler;
+  oldElementDeclHandler = elementDeclHandler;
+  oldAttlistDeclHandler = attlistDeclHandler;
+  oldEntityDeclHandler = entityDeclHandler;
+  oldXmlDeclHandler = xmlDeclHandler;
+  oldDeclElementType = declElementType;
+
+  oldUserData = userData;
+  oldHandlerArg = handlerArg;
+  oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+  oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+#ifdef XML_DTD
+  oldParamEntityParsing = paramEntityParsing;
+  oldInEntityValue = prologState.inEntityValue;
+#endif
+  oldns_triplets = ns_triplets;
+  /* Note that the new parser shares the same hash secret as the old
+     parser, so that dtdCopy and copyEntityTable can lookup values
+     from hash tables associated with either parser without us having
+     to worry which hash secrets each table has.
+  */
+  oldhash_secret_salt = hash_secret_salt;
 
 #ifdef XML_DTD
   if (!context)
@@ -1194,12 +1383,15 @@ XML_ParserFree(XML_Parser parser)
 void XMLCALL
 XML_UseParserAsHandlerArg(XML_Parser parser)
 {
-  handlerArg = parser;
+  if (parser != NULL)
+    handlerArg = parser;
 }
 
 enum XML_Error XMLCALL
 XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
 {
+  if (parser == NULL)
+    return XML_ERROR_INVALID_ARGUMENT;
 #ifdef XML_DTD
   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
@@ -1214,6 +1406,8 @@ XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
 void XMLCALL
 XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
 {
+  if (parser == NULL)
+    return;
   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
     return;
@@ -1223,6 +1417,8 @@ XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
 void XMLCALL
 XML_SetUserData(XML_Parser parser, void *p)
 {
+  if (parser == NULL)
+    return;
   if (handlerArg == userData)
     handlerArg = userData = p;
   else
@@ -1232,6 +1428,8 @@ XML_SetUserData(XML_Parser parser, void *p)
 enum XML_Status XMLCALL
 XML_SetBase(XML_Parser parser, const XML_Char *p)
 {
+  if (parser == NULL)
+    return XML_STATUS_ERROR;
   if (p) {
     p = poolCopyString(&_dtd->pool, p);
     if (!p)
@@ -1246,18 +1444,24 @@ XML_SetBase(XML_Parser parser, const XML_Char *p)
 const XML_Char * XMLCALL
 XML_GetBase(XML_Parser parser)
 {
+  if (parser == NULL)
+    return NULL;
   return curBase;
 }
 
 int XMLCALL
 XML_GetSpecifiedAttributeCount(XML_Parser parser)
 {
+  if (parser == NULL)
+    return -1;
   return nSpecifiedAtts;
 }
 
 int XMLCALL
 XML_GetIdAttributeIndex(XML_Parser parser)
 {
+  if (parser == NULL)
+    return -1;
   return idAttIndex;
 }
 
@@ -1265,6 +1469,8 @@ XML_GetIdAttributeIndex(XML_Parser parser)
 const XML_AttrInfo * XMLCALL
 XML_GetAttributeInfo(XML_Parser parser)
 {
+  if (parser == NULL)
+    return NULL;
   return attInfo;
 }
 #endif
@@ -1274,6 +1480,8 @@ XML_SetElementHandler(XML_Parser parser,
                       XML_StartElementHandler start,
                       XML_EndElementHandler end)
 {
+  if (parser == NULL)
+    return;
   startElementHandler = start;
   endElementHandler = end;
 }
@@ -1281,34 +1489,39 @@ XML_SetElementHandler(XML_Parser parser,
 void XMLCALL
 XML_SetStartElementHandler(XML_Parser parser,
                            XML_StartElementHandler start) {
-  startElementHandler = start;
+  if (parser != NULL)
+    startElementHandler = start;
 }
 
 void XMLCALL
 XML_SetEndElementHandler(XML_Parser parser,
                          XML_EndElementHandler end) {
-  endElementHandler = end;
+  if (parser != NULL)
+    endElementHandler = end;
 }
 
 void XMLCALL
 XML_SetCharacterDataHandler(XML_Parser parser,
                             XML_CharacterDataHandler handler)
 {
-  characterDataHandler = handler;
+  if (parser != NULL)
+    characterDataHandler = handler;
 }
 
 void XMLCALL
 XML_SetProcessingInstructionHandler(XML_Parser parser,
                                     XML_ProcessingInstructionHandler handler)
 {
-  processingInstructionHandler = handler;
+  if (parser != NULL)
+    processingInstructionHandler = handler;
 }
 
 void XMLCALL
 XML_SetCommentHandler(XML_Parser parser,
                       XML_CommentHandler handler)
 {
-  commentHandler = handler;
+  if (parser != NULL)
+    commentHandler = handler;
 }
 
 void XMLCALL
@@ -1316,6 +1529,8 @@ XML_SetCdataSectionHandler(XML_Parser parser,
                            XML_StartCdataSectionHandler start,
                            XML_EndCdataSectionHandler end)
 {
+  if (parser == NULL)
+    return;
   startCdataSectionHandler = start;
   endCdataSectionHandler = end;
 }
@@ -1323,19 +1538,23 @@ XML_SetCdataSectionHandler(XML_Parser parser,
 void XMLCALL
 XML_SetStartCdataSectionHandler(XML_Parser parser,
                                 XML_StartCdataSectionHandler start) {
-  startCdataSectionHandler = start;
+  if (parser != NULL)
+    startCdataSectionHandler = start;
 }
 
 void XMLCALL
 XML_SetEndCdataSectionHandler(XML_Parser parser,
                               XML_EndCdataSectionHandler end) {
-  endCdataSectionHandler = end;
+  if (parser != NULL)
+    endCdataSectionHandler = end;
 }
 
 void XMLCALL
 XML_SetDefaultHandler(XML_Parser parser,
                       XML_DefaultHandler handler)
 {
+  if (parser == NULL)
+    return;
   defaultHandler = handler;
   defaultExpandInternalEntities = XML_FALSE;
 }
@@ -1344,6 +1563,8 @@ void XMLCALL
 XML_SetDefaultHandlerExpand(XML_Parser parser,
                             XML_DefaultHandler handler)
 {
+  if (parser == NULL)
+    return;
   defaultHandler = handler;
   defaultExpandInternalEntities = XML_TRUE;
 }
@@ -1353,6 +1574,8 @@ XML_SetDoctypeDeclHandler(XML_Parser parser,
                           XML_StartDoctypeDeclHandler start,
                           XML_EndDoctypeDeclHandler end)
 {
+  if (parser == NULL)
+    return;
   startDoctypeDeclHandler = start;
   endDoctypeDeclHandler = end;
 }
@@ -1360,27 +1583,31 @@ XML_SetDoctypeDeclHandler(XML_Parser parser,
 void XMLCALL
 XML_SetStartDoctypeDeclHandler(XML_Parser parser,
                                XML_StartDoctypeDeclHandler start) {
-  startDoctypeDeclHandler = start;
+  if (parser != NULL)
+    startDoctypeDeclHandler = start;
 }
 
 void XMLCALL
 XML_SetEndDoctypeDeclHandler(XML_Parser parser,
                              XML_EndDoctypeDeclHandler end) {
-  endDoctypeDeclHandler = end;
+  if (parser != NULL)
+    endDoctypeDeclHandler = end;
 }
 
 void XMLCALL
 XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
                                  XML_UnparsedEntityDeclHandler handler)
 {
-  unparsedEntityDeclHandler = handler;
+  if (parser != NULL)
+    unparsedEntityDeclHandler = handler;
 }
 
 void XMLCALL
 XML_SetNotationDeclHandler(XML_Parser parser,
                            XML_NotationDeclHandler handler)
 {
-  notationDeclHandler = handler;
+  if (parser != NULL)
+    notationDeclHandler = handler;
 }
 
 void XMLCALL
@@ -1388,6 +1615,8 @@ XML_SetNamespaceDeclHandler(XML_Parser parser,
                             XML_StartNamespaceDeclHandler start,
                             XML_EndNamespaceDeclHandler end)
 {
+  if (parser == NULL)
+    return;
   startNamespaceDeclHandler = start;
   endNamespaceDeclHandler = end;
 }
@@ -1395,32 +1624,38 @@ XML_SetNamespaceDeclHandler(XML_Parser parser,
 void XMLCALL
 XML_SetStartNamespaceDeclHandler(XML_Parser parser,
                                  XML_StartNamespaceDeclHandler start) {
-  startNamespaceDeclHandler = start;
+  if (parser != NULL)
+    startNamespaceDeclHandler = start;
 }
 
 void XMLCALL
 XML_SetEndNamespaceDeclHandler(XML_Parser parser,
                                XML_EndNamespaceDeclHandler end) {
-  endNamespaceDeclHandler = end;
+  if (parser != NULL)
+    endNamespaceDeclHandler = end;
 }
 
 void XMLCALL
 XML_SetNotStandaloneHandler(XML_Parser parser,
                             XML_NotStandaloneHandler handler)
 {
-  notStandaloneHandler = handler;
+  if (parser != NULL)
+    notStandaloneHandler = handler;
 }
 
 void XMLCALL
 XML_SetExternalEntityRefHandler(XML_Parser parser,
                                 XML_ExternalEntityRefHandler handler)
 {
-  externalEntityRefHandler = handler;
+  if (parser != NULL)
+    externalEntityRefHandler = handler;
 }
 
 void XMLCALL
 XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
 {
+  if (parser == NULL)
+    return;
   if (arg)
     externalEntityRefHandlerArg = (XML_Parser)arg;
   else
@@ -1431,7 +1666,8 @@ void XMLCALL
 XML_SetSkippedEntityHandler(XML_Parser parser,
                             XML_SkippedEntityHandler handler)
 {
-  skippedEntityHandler = handler;
+  if (parser != NULL)
+    skippedEntityHandler = handler;
 }
 
 void XMLCALL
@@ -1439,6 +1675,8 @@ XML_SetUnknownEncodingHandler(XML_Parser parser,
                               XML_UnknownEncodingHandler handler,
                               void *data)
 {
+  if (parser == NULL)
+    return;
   unknownEncodingHandler = handler;
   unknownEncodingHandlerData = data;
 }
@@ -1447,33 +1685,39 @@ void XMLCALL
 XML_SetElementDeclHandler(XML_Parser parser,
                           XML_ElementDeclHandler eldecl)
 {
-  elementDeclHandler = eldecl;
+  if (parser != NULL)
+    elementDeclHandler = eldecl;
 }
 
 void XMLCALL
 XML_SetAttlistDeclHandler(XML_Parser parser,
                           XML_AttlistDeclHandler attdecl)
 {
-  attlistDeclHandler = attdecl;
+  if (parser != NULL)
+    attlistDeclHandler = attdecl;
 }
 
 void XMLCALL
 XML_SetEntityDeclHandler(XML_Parser parser,
                          XML_EntityDeclHandler handler)
 {
-  entityDeclHandler = handler;
+  if (parser != NULL)
+    entityDeclHandler = handler;
 }
 
 void XMLCALL
 XML_SetXmlDeclHandler(XML_Parser parser,
                       XML_XmlDeclHandler handler) {
-  xmlDeclHandler = handler;
+  if (parser != NULL)
+    xmlDeclHandler = handler;
 }
 
 int XMLCALL
 XML_SetParamEntityParsing(XML_Parser parser,
                           enum XML_ParamEntityParsing peParsing)
 {
+  if (parser == NULL)
+    return 0;
   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
     return 0;
@@ -1489,6 +1733,10 @@ int XMLCALL
 XML_SetHashSalt(XML_Parser parser,
                 unsigned long hash_salt)
 {
+  if (parser == NULL)
+    return 0;
+  if (parser->m_parentParser)
+    return XML_SetHashSalt(parser->m_parentParser, hash_salt);
   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
     return 0;
@@ -1499,6 +1747,10 @@ XML_SetHashSalt(XML_Parser parser,
 enum XML_Status XMLCALL
 XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
 {
+  if ((parser == NULL) || (len < 0) || ((s == NULL) && (len != 0))) {
+    errorCode = XML_ERROR_INVALID_ARGUMENT;
+    return XML_STATUS_ERROR;
+  }
   switch (ps_parsing) {
   case XML_SUSPENDED:
     errorCode = XML_ERROR_SUSPENDED;
@@ -1550,7 +1802,14 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
   else if (bufferPtr == bufferEnd) {
     const char *end;
     int nLeftOver;
-    enum XML_Error result;
+    enum XML_Status result;
+    /* Detect overflow (a+b > MAX <==> b > MAX-a) */
+    if (len > ((XML_Size)-1) / 2 - parseEndByteIndex) {
+       errorCode = XML_ERROR_NO_MEMORY;
+       eventPtr = eventEndPtr = NULL;
+       processor = errorProcessor;
+       return XML_STATUS_ERROR;
+    }
     parseEndByteIndex += len;
     positionPtr = s;
     ps_finalBuffer = (XML_Bool)isFinal;
@@ -1583,11 +1842,14 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
     nLeftOver = s + len - end;
     if (nLeftOver) {
       if (buffer == NULL || nLeftOver > bufferLim - buffer) {
-        /* FIXME avoid integer overflow */
-        char *temp;
-        temp = (buffer == NULL
-                ? (char *)MALLOC(len * 2)
-                : (char *)REALLOC(buffer, len * 2));
+        /* avoid _signed_ integer overflow */
+        char *temp = NULL;
+        const int bytesToAllocate = (int)((unsigned)len * 2U);
+        if (bytesToAllocate > 0) {
+          temp = (buffer == NULL
+                ? (char *)MALLOC(bytesToAllocate)
+                : (char *)REALLOC(buffer, bytesToAllocate));
+        }
         if (temp == NULL) {
           errorCode = XML_ERROR_NO_MEMORY;
           eventPtr = eventEndPtr = NULL;
@@ -1595,7 +1857,7 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
           return XML_STATUS_ERROR;
         }
         buffer = temp;
-        bufferLim = buffer + len * 2;
+        bufferLim = buffer + bytesToAllocate;
       }
       memcpy(buffer, end, nLeftOver);
     }
@@ -1625,6 +1887,8 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
   const char *start;
   enum XML_Status result = XML_STATUS_OK;
 
+  if (parser == NULL)
+    return XML_STATUS_ERROR;
   switch (ps_parsing) {
   case XML_SUSPENDED:
     errorCode = XML_ERROR_SUSPENDED;
@@ -1678,6 +1942,12 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
 void * XMLCALL
 XML_GetBuffer(XML_Parser parser, int len)
 {
+  if (parser == NULL)
+    return NULL;
+  if (len < 0) {
+    errorCode = XML_ERROR_NO_MEMORY;
+    return NULL;
+  }
   switch (ps_parsing) {
   case XML_SUSPENDED:
     errorCode = XML_ERROR_SUSPENDED;
@@ -1689,11 +1959,17 @@ XML_GetBuffer(XML_Parser parser, int len)
   }
 
   if (len > bufferLim - bufferEnd) {
-    /* FIXME avoid integer overflow */
-    int neededSize = len + (int)(bufferEnd - bufferPtr);
 #ifdef XML_CONTEXT_BYTES
-    int keep = (int)(bufferPtr - buffer);
-
+    int keep;
+#endif  /* defined XML_CONTEXT_BYTES */
+    /* Do not invoke signed arithmetic overflow: */
+    int neededSize = (int) ((unsigned)len + (unsigned)(bufferEnd - bufferPtr));
+    if (neededSize < 0) {
+      errorCode = XML_ERROR_NO_MEMORY;
+      return NULL;
+    }
+#ifdef XML_CONTEXT_BYTES
+    keep = (int)(bufferPtr - buffer);
     if (keep > XML_CONTEXT_BYTES)
       keep = XML_CONTEXT_BYTES;
     neededSize += keep;
@@ -1718,8 +1994,13 @@ XML_GetBuffer(XML_Parser parser, int len)
       if (bufferSize == 0)
         bufferSize = INIT_BUFFER_SIZE;
       do {
-        bufferSize *= 2;
-      } while (bufferSize < neededSize);
+        /* Do not invoke signed arithmetic overflow: */
+        bufferSize = (int) (2U * (unsigned) bufferSize);
+      } while (bufferSize < neededSize && bufferSize > 0);
+      if (bufferSize <= 0) {
+        errorCode = XML_ERROR_NO_MEMORY;
+        return NULL;
+      }
       newBuf = (char *)MALLOC(bufferSize);
       if (newBuf == 0) {
         errorCode = XML_ERROR_NO_MEMORY;
@@ -1759,6 +2040,8 @@ XML_GetBuffer(XML_Parser parser, int len)
 enum XML_Status XMLCALL
 XML_StopParser(XML_Parser parser, XML_Bool resumable)
 {
+  if (parser == NULL)
+    return XML_STATUS_ERROR;
   switch (ps_parsing) {
   case XML_SUSPENDED:
     if (resumable) {
@@ -1791,6 +2074,8 @@ XML_ResumeParser(XML_Parser parser)
 {
   enum XML_Status result = XML_STATUS_OK;
 
+  if (parser == NULL)
+    return XML_STATUS_ERROR;
   if (ps_parsing != XML_SUSPENDED) {
     errorCode = XML_ERROR_NOT_SUSPENDED;
     return XML_STATUS_ERROR;
@@ -1827,6 +2112,8 @@ XML_ResumeParser(XML_Parser parser)
 void XMLCALL
 XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
 {
+  if (parser == NULL)
+    return;
   assert(status != NULL);
   *status = parser->m_parsingStatus;
 }
@@ -1834,20 +2121,26 @@ XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
 enum XML_Error XMLCALL
 XML_GetErrorCode(XML_Parser parser)
 {
+  if (parser == NULL)
+    return XML_ERROR_INVALID_ARGUMENT;
   return errorCode;
 }
 
 XML_Index XMLCALL
 XML_GetCurrentByteIndex(XML_Parser parser)
 {
+  if (parser == NULL)
+    return -1;
   if (eventPtr)
-    return parseEndByteIndex - (parseEndPtr - eventPtr);
+    return (XML_Index)(parseEndByteIndex - (parseEndPtr - eventPtr));
   return -1;
 }
 
 int XMLCALL
 XML_GetCurrentByteCount(XML_Parser parser)
 {
+  if (parser == NULL)
+    return 0;
   if (eventEndPtr && eventPtr)
     return (int)(eventEndPtr - eventPtr);
   return 0;
@@ -1857,11 +2150,19 @@ const char * XMLCALL
 XML_GetInputContext(XML_Parser parser, int *offset, int *size)
 {
 #ifdef XML_CONTEXT_BYTES
+  if (parser == NULL)
+    return NULL;
   if (eventPtr && buffer) {
-    *offset = (int)(eventPtr - buffer);
-    *size   = (int)(bufferEnd - buffer);
+    if (offset != NULL)
+      *offset = (int)(eventPtr - buffer);
+    if (size != NULL)
+      *size   = (int)(bufferEnd - buffer);
     return buffer;
   }
+#else
+  (void)parser;
+  (void)offset;
+  (void)size;
 #endif /* defined XML_CONTEXT_BYTES */
   return (char *) 0;
 }
@@ -1869,6 +2170,8 @@ XML_GetInputContext(XML_Parser parser, int *offset, int *size)
 XML_Size XMLCALL
 XML_GetCurrentLineNumber(XML_Parser parser)
 {
+  if (parser == NULL)
+    return 0;
   if (eventPtr && eventPtr >= positionPtr) {
     XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
     positionPtr = eventPtr;
@@ -1879,6 +2182,8 @@ XML_GetCurrentLineNumber(XML_Parser parser)
 XML_Size XMLCALL
 XML_GetCurrentColumnNumber(XML_Parser parser)
 {
+  if (parser == NULL)
+    return 0;
   if (eventPtr && eventPtr >= positionPtr) {
     XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
     positionPtr = eventPtr;
@@ -1889,30 +2194,38 @@ XML_GetCurrentColumnNumber(XML_Parser parser)
 void XMLCALL
 XML_FreeContentModel(XML_Parser parser, XML_Content *model)
 {
-  FREE(model);
+  if (parser != NULL)
+    FREE(model);
 }
 
 void * XMLCALL
 XML_MemMalloc(XML_Parser parser, size_t size)
 {
+  if (parser == NULL)
+    return NULL;
   return MALLOC(size);
 }
 
 void * XMLCALL
 XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
 {
+  if (parser == NULL)
+    return NULL;
   return REALLOC(ptr, size);
 }
 
 void XMLCALL
 XML_MemFree(XML_Parser parser, void *ptr)
 {
-  FREE(ptr);
+  if (parser != NULL)
+    FREE(ptr);
 }
 
 void XMLCALL
 XML_DefaultCurrent(XML_Parser parser)
 {
+  if (parser == NULL)
+    return;
   if (defaultHandler) {
     if (openInternalEntities)
       reportDefault(parser,
@@ -2415,11 +2728,11 @@ doContent(XML_Parser parser,
           for (;;) {
             int bufSize;
             int convLen;
-            XmlConvert(enc,
+            const enum XML_Convert_Result convert_res = XmlConvert(enc,
                        &fromPtr, rawNameEnd,
                        (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
             convLen = (int)(toPtr - (XML_Char *)tag->buf);
-            if (fromPtr == rawNameEnd) {
+            if ((fromPtr >= rawNameEnd) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
               tag->name.strLen = convLen;
               break;
             }
@@ -2462,8 +2775,10 @@ doContent(XML_Parser parser,
           return XML_ERROR_NO_MEMORY;
         poolFinish(&tempPool);
         result = storeAtts(parser, enc, s, &name, &bindings);
-        if (result)
+        if (result != XML_ERROR_NONE) {
+          freeBindings(parser, bindings);
           return result;
+        }
         poolFinish(&tempPool);
         if (startElementHandler) {
           startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
@@ -2478,15 +2793,7 @@ doContent(XML_Parser parser,
         if (noElmHandlers && defaultHandler)
           reportDefault(parser, enc, s, next);
         poolClear(&tempPool);
-        while (bindings) {
-          BINDING *b = bindings;
-          if (endNamespaceDeclHandler)
-            endNamespaceDeclHandler(handlerArg, b->prefix->name);
-          bindings = bindings->nextTagBinding;
-          b->nextTagBinding = freeBindingList;
-          freeBindingList = b;
-          b->prefix->binding = b->prevPrefixBinding;
-        }
+        freeBindings(parser, bindings);
       }
       if (tagLevel == 0)
         return epilogProcessor(parser, next, end, nextPtr);
@@ -2640,11 +2947,11 @@ doContent(XML_Parser parser,
           if (MUST_CONVERT(enc, s)) {
             for (;;) {
               ICHAR *dataPtr = (ICHAR *)dataBuf;
-              XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
               *eventEndPP = s;
               charDataHandler(handlerArg, dataBuf,
                               (int)(dataPtr - (ICHAR *)dataBuf));
-              if (s == next)
+              if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
                 break;
               *eventPP = s;
             }
@@ -2684,6 +2991,29 @@ doContent(XML_Parser parser,
   /* not reached */
 }
 
+/* This function does not call free() on the allocated memory, merely
+ * moving it to the parser's freeBindingList where it can be freed or
+ * reused as appropriate.
+ */
+static void
+freeBindings(XML_Parser parser, BINDING *bindings)
+{
+  while (bindings) {
+    BINDING *b = bindings;
+
+    /* startNamespaceDeclHandler will have been called for this
+     * binding in addBindings(), so call the end handler now.
+     */
+    if (endNamespaceDeclHandler)
+        endNamespaceDeclHandler(handlerArg, b->prefix->name);
+
+    bindings = bindings->nextTagBinding;
+    b->nextTagBinding = freeBindingList;
+    freeBindingList = b;
+    b->prefix->binding = b->prevPrefixBinding;
+  }
+}
+
 /* Precondition: all arguments must be non-NULL;
    Purpose:
    - normalize attributes
@@ -2908,29 +3238,41 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
       if (s[-1] == 2) {  /* prefixed */
         ATTRIBUTE_ID *id;
         const BINDING *b;
-        unsigned long uriHash = hash_secret_salt;
+        unsigned long uriHash;
+        struct siphash sip_state;
+        struct sipkey sip_key;
+
+        copy_salt_to_sipkey(parser, &sip_key);
+        sip24_init(&sip_state, &sip_key);
+
         ((XML_Char *)s)[-1] = 0;  /* clear flag */
         id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
+        if (!id || !id->prefix)
+          return XML_ERROR_NO_MEMORY;
         b = id->prefix->binding;
         if (!b)
           return XML_ERROR_UNBOUND_PREFIX;
 
-        /* as we expand the name we also calculate its hash value */
         for (j = 0; j < b->uriLen; j++) {
           const XML_Char c = b->uri[j];
           if (!poolAppendChar(&tempPool, c))
             return XML_ERROR_NO_MEMORY;
-          uriHash = CHAR_HASH(uriHash, c);
         }
+
+        sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char));
+
         while (*s++ != XML_T(ASCII_COLON))
           ;
+
+        sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
+
         do {  /* copies null terminator */
-          const XML_Char c = *s;
           if (!poolAppendChar(&tempPool, *s))
             return XML_ERROR_NO_MEMORY;
-          uriHash = CHAR_HASH(uriHash, c);
         } while (*s++);
 
+        uriHash = (unsigned long)sip24_final(&sip_state);
+
         { /* Check hash table for duplicate of expanded name (uriName).
              Derived from code in lookup(parser, HASH_TABLE *table, ...).
           */
@@ -3248,11 +3590,11 @@ doCdataSection(XML_Parser parser,
           if (MUST_CONVERT(enc, s)) {
             for (;;) {
               ICHAR *dataPtr = (ICHAR *)dataBuf;
-              XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
               *eventEndPP = next;
               charDataHandler(handlerArg, dataBuf,
                               (int)(dataPtr - (ICHAR *)dataBuf));
-              if (s == next)
+              if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
                 break;
               *eventPP = s;
             }
@@ -3644,6 +3986,14 @@ entityValueInitProcessor(XML_Parser parser,
       *nextPtr = next;
       return XML_ERROR_NONE;
     }
+    /* 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
+       "internalEventEndPtr = NULL;
   textStart = (char *)entity->textPtr;
   textEnd = (char *)(entity->textPtr + entity->textLen);
+  /* Set a safe default value in case 'next' does not get set */
+  next = textStart;
 
 #ifdef XML_DTD
   if (entity->is_param) {
@@ -4865,6 +5217,8 @@ internalEntityProcessor(XML_Parser parser,
   entity = openEntity->entity;
   textStart = ((char *)entity->textPtr) + entity->processed;
   textEnd = (char *)(entity->textPtr + entity->textLen);
+  /* Set a safe default value in case 'next' does not get set */
+  next = textStart;
 
 #ifdef XML_DTD
   if (entity->is_param) {
@@ -4911,9 +5265,9 @@ internalEntityProcessor(XML_Parser parser,
 
 static enum XML_Error PTRCALL
 errorProcessor(XML_Parser parser,
-               const char *s,
-               const char *end,
-               const char **nextPtr)
+               const char *UNUSED_P(s),
+               const char *UNUSED_P(end),
+               const char **UNUSED_P(nextPtr))
 {
   return errorCode;
 }
@@ -5329,6 +5683,7 @@ reportDefault(XML_Parser parser, const ENCODING *enc,
               const char *s, const char *end)
 {
   if (MUST_CONVERT(enc, s)) {
+    enum XML_Convert_Result convert_res;
     const char **eventPP;
     const char **eventEndPP;
     if (enc == encoding) {
@@ -5341,11 +5696,11 @@ reportDefault(XML_Parser parser, const ENCODING *enc,
     }
     do {
       ICHAR *dataPtr = (ICHAR *)dataBuf;
-      XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+      convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
       *eventEndPP = s;
       defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
       *eventPP = s;
-    } while (s != end);
+    } while ((convert_res != XML_CONVERT_COMPLETED) && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
   }
   else
     defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
@@ -5475,6 +5830,8 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
             return NULL;
           id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
                                         sizeof(PREFIX));
+          if (!id->prefix)
+            return NULL;
           if (id->prefix->name == poolStart(&dtd->pool))
             poolFinish(&dtd->pool);
           else
@@ -5822,7 +6179,6 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_H
       newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
           ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
       if (!newE->defaultAtts) {
-        ms->free_fcn(newE);
         return 0;
       }
     }
@@ -5957,13 +6313,32 @@ keyeq(KEY s1, KEY s2)
   return XML_FALSE;
 }
 
+static size_t
+keylen(KEY s)
+{
+  size_t len = 0;
+  for (; *s; s++, len++);
+  return len;
+}
+
+static void
+copy_salt_to_sipkey(XML_Parser parser, struct sipkey * key)
+{
+  key->k[0] = 0;
+  key->k[1] = get_hash_secret_salt(parser);
+}
+
 static unsigned long FASTCALL
 hash(XML_Parser parser, KEY s)
 {
-  unsigned long h = hash_secret_salt;
-  while (*s)
-    h = CHAR_HASH(h, *s++);
-  return h;
+  struct siphash state;
+  struct sipkey key;
+  (void)sip_tobin;
+  (void)sip24_valid;
+  copy_salt_to_sipkey(parser, &key);
+  sip24_init(&state, &key);
+  sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
+  return (unsigned long)sip24_final(&state);
 }
 
 static NAMED *
@@ -6148,8 +6523,8 @@ poolAppend(STRING_POOL *pool, const ENCODING *enc,
   if (!pool->ptr && !poolGrow(pool))
     return NULL;
   for (;;) {
-    XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
-    if (ptr == end)
+    const enum XML_Convert_Result convert_res = XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+    if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
       break;
     if (!poolGrow(pool))
       return NULL;
@@ -6206,6 +6581,35 @@ poolStoreString(STRING_POOL *pool, const ENCODING *enc,
   return pool->start;
 }
 
+static size_t
+poolBytesToAllocateFor(int blockSize)
+{
+  /* Unprotected math would be:
+  ** return offsetof(BLOCK, s) + blockSize * sizeof(XML_Char);
+  **
+  ** Detect overflow, avoiding _signed_ overflow undefined behavior
+  ** For a + b * c we check b * c in isolation first, so that addition of a
+  ** on top has no chance of making us accept a small non-negative number
+  */
+  const size_t stretch = sizeof(XML_Char);  /* can be 4 bytes */
+
+  if (blockSize <= 0)
+    return 0;
+
+  if (blockSize > (int)(INT_MAX / stretch))
+    return 0;
+
+  {
+    const int stretchedBlockSize = blockSize * (int)stretch;
+    const int bytesToAllocate = (int)(
+        offsetof(BLOCK, s) + (unsigned)stretchedBlockSize);
+    if (bytesToAllocate < 0)
+      return 0;
+
+    return (size_t)bytesToAllocate;
+  }
+}
+
 static XML_Bool FASTCALL
 poolGrow(STRING_POOL *pool)
 {
@@ -6233,11 +6637,19 @@ poolGrow(STRING_POOL *pool)
     }
   }
   if (pool->blocks && pool->start == pool->blocks->s) {
-    int blockSize = (int)(pool->end - pool->start)*2;
-    BLOCK *temp = (BLOCK *)
-      pool->mem->realloc_fcn(pool->blocks,
-                             (offsetof(BLOCK, s)
-                              + blockSize * sizeof(XML_Char)));
+    BLOCK *temp;
+    int blockSize = (int)((unsigned)(pool->end - pool->start)*2U);
+    size_t bytesToAllocate;
+
+    if (blockSize < 0)
+      return XML_FALSE;
+
+    bytesToAllocate = poolBytesToAllocateFor(blockSize);
+    if (bytesToAllocate == 0)
+      return XML_FALSE;
+
+    temp = (BLOCK *)
+      pool->mem->realloc_fcn(pool->blocks, (unsigned)bytesToAllocate);
     if (temp == NULL)
       return XML_FALSE;
     pool->blocks = temp;
@@ -6249,12 +6661,26 @@ poolGrow(STRING_POOL *pool)
   else {
     BLOCK *tem;
     int blockSize = (int)(pool->end - pool->start);
+    size_t bytesToAllocate;
+
+    if (blockSize < 0)
+      return XML_FALSE;
+
     if (blockSize < INIT_BLOCK_SIZE)
       blockSize = INIT_BLOCK_SIZE;
-    else
+    else {
+      /* Detect overflow, avoiding _signed_ overflow undefined behavior */
+      if ((int)((unsigned)blockSize * 2U) < 0) {
+        return XML_FALSE;
+      }
       blockSize *= 2;
-    tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s)
-                                        + blockSize * sizeof(XML_Char));
+    }
+
+    bytesToAllocate = poolBytesToAllocateFor(blockSize);
+    if (bytesToAllocate == 0)
+      return XML_FALSE;
+
+    tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
     if (!tem)
       return XML_FALSE;
     tem->size = blockSize;
diff --git a/lib-src/expat/lib/xmlrole.c b/lib-src/expat/lib/xmlrole.c
index 44772e21d..a7c563027 100644
--- a/lib-src/expat/lib/xmlrole.c
+++ b/lib-src/expat/lib/xmlrole.c
@@ -4,19 +4,13 @@
 
 #include 
 
-#ifdef COMPILED_FROM_DSP
+#ifdef _WIN32
 #include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
 #else
 #ifdef HAVE_EXPAT_CONFIG_H
 #include 
 #endif
-#endif /* ndef COMPILED_FROM_DSP */
+#endif /* ndef _WIN32 */
 
 #include "expat_external.h"
 #include "internal.h"
@@ -195,9 +189,9 @@ prolog1(PROLOG_STATE *state,
 static int PTRCALL
 prolog2(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -216,9 +210,9 @@ prolog2(PROLOG_STATE *state,
 static int PTRCALL
 doctype0(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -264,9 +258,9 @@ doctype1(PROLOG_STATE *state,
 static int PTRCALL
 doctype2(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -281,9 +275,9 @@ doctype2(PROLOG_STATE *state,
 static int PTRCALL
 doctype3(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -298,9 +292,9 @@ doctype3(PROLOG_STATE *state,
 static int PTRCALL
 doctype4(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -318,9 +312,9 @@ doctype4(PROLOG_STATE *state,
 static int PTRCALL
 doctype5(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -437,9 +431,9 @@ externalSubset1(PROLOG_STATE *state,
 static int PTRCALL
 entity0(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -457,9 +451,9 @@ entity0(PROLOG_STATE *state,
 static int PTRCALL
 entity1(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -502,9 +496,9 @@ entity2(PROLOG_STATE *state,
 static int PTRCALL
 entity3(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -519,9 +513,9 @@ entity3(PROLOG_STATE *state,
 static int PTRCALL
 entity4(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -559,9 +553,9 @@ entity5(PROLOG_STATE *state,
 static int PTRCALL
 entity6(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -605,9 +599,9 @@ entity7(PROLOG_STATE *state,
 static int PTRCALL
 entity8(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -622,9 +616,9 @@ entity8(PROLOG_STATE *state,
 static int PTRCALL
 entity9(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -639,9 +633,9 @@ entity9(PROLOG_STATE *state,
 static int PTRCALL
 entity10(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -656,9 +650,9 @@ entity10(PROLOG_STATE *state,
 static int PTRCALL
 notation0(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -697,9 +691,9 @@ notation1(PROLOG_STATE *state,
 static int PTRCALL
 notation2(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -714,9 +708,9 @@ notation2(PROLOG_STATE *state,
 static int PTRCALL
 notation3(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -732,9 +726,9 @@ notation3(PROLOG_STATE *state,
 static int PTRCALL
 notation4(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -753,9 +747,9 @@ notation4(PROLOG_STATE *state,
 static int PTRCALL
 attlist0(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -771,9 +765,9 @@ attlist0(PROLOG_STATE *state,
 static int PTRCALL
 attlist1(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -833,9 +827,9 @@ attlist2(PROLOG_STATE *state,
 static int PTRCALL
 attlist3(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -852,9 +846,9 @@ attlist3(PROLOG_STATE *state,
 static int PTRCALL
 attlist4(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -872,9 +866,9 @@ attlist4(PROLOG_STATE *state,
 static int PTRCALL
 attlist5(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -889,9 +883,9 @@ attlist5(PROLOG_STATE *state,
 static int PTRCALL
 attlist6(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -906,9 +900,9 @@ attlist6(PROLOG_STATE *state,
 static int PTRCALL
 attlist7(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -967,9 +961,9 @@ attlist8(PROLOG_STATE *state,
 static int PTRCALL
 attlist9(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -984,9 +978,9 @@ attlist9(PROLOG_STATE *state,
 static int PTRCALL
 element0(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1072,9 +1066,9 @@ element2(PROLOG_STATE *state,
 static int PTRCALL
 element3(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1097,9 +1091,9 @@ element3(PROLOG_STATE *state,
 static int PTRCALL
 element4(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1115,9 +1109,9 @@ element4(PROLOG_STATE *state,
 static int PTRCALL
 element5(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1136,9 +1130,9 @@ element5(PROLOG_STATE *state,
 static int PTRCALL
 element6(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1166,9 +1160,9 @@ element6(PROLOG_STATE *state,
 static int PTRCALL
 element7(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1240,9 +1234,9 @@ condSect0(PROLOG_STATE *state,
 static int PTRCALL
 condSect1(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1258,9 +1252,9 @@ condSect1(PROLOG_STATE *state,
 static int PTRCALL
 condSect2(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1277,9 +1271,9 @@ condSect2(PROLOG_STATE *state,
 static int PTRCALL
 declClose(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1292,11 +1286,11 @@ declClose(PROLOG_STATE *state,
 }
 
 static int PTRCALL
-error(PROLOG_STATE *state,
-      int tok,
-      const char *ptr,
-      const char *end,
-      const ENCODING *enc)
+error(PROLOG_STATE *UNUSED_P(state),
+      int UNUSED_P(tok),
+      const char *UNUSED_P(ptr),
+      const char *UNUSED_P(end),
+      const ENCODING *UNUSED_P(enc))
 {
   return XML_ROLE_NONE;
 }
diff --git a/lib-src/expat/lib/xmltok.c b/lib-src/expat/lib/xmltok.c
index bf09dfc72..cdf0720dd 100644
--- a/lib-src/expat/lib/xmltok.c
+++ b/lib-src/expat/lib/xmltok.c
@@ -4,19 +4,13 @@
 
 #include 
 
-#ifdef COMPILED_FROM_DSP
+#ifdef _WIN32
 #include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
 #else
 #ifdef HAVE_EXPAT_CONFIG_H
 #include 
 #endif
-#endif /* ndef COMPILED_FROM_DSP */
+#endif /* ndef _WIN32 */
 
 #include "expat_external.h"
 #include "internal.h"
@@ -46,7 +40,7 @@
 #define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
 
 #define UCS2_GET_NAMING(pages, hi, lo) \
-   (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((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
@@ -56,7 +50,7 @@
     (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
                       + ((((byte)[0]) & 3) << 1) \
                       + ((((byte)[1]) >> 5) & 1)] \
-         & (1 << (((byte)[1]) & 0x1F)))
+         & (1u << (((byte)[1]) & 0x1F)))
 
 /* A 3 byte UTF-8 representation splits the characters 16 bits between
    the bottom 4, 6 and 6 bits of the bytes.  We need 8 bits to index
@@ -69,7 +63,7 @@
                        << 3) \
                       + ((((byte)[1]) & 3) << 1) \
                       + ((((byte)[2]) >> 5) & 1)] \
-         & (1 << (((byte)[2]) & 0x1F)))
+         & (1u << (((byte)[2]) & 0x1F)))
 
 #define UTF8_GET_NAMING(pages, p, n) \
   ((n) == 2 \
@@ -122,19 +116,19 @@
     ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
 
 static int PTRFASTCALL
-isNever(const ENCODING *enc, const char *p)
+isNever(const ENCODING *UNUSED_P(enc), const char *UNUSED_P(p))
 {
   return 0;
 }
 
 static int PTRFASTCALL
-utf8_isName2(const ENCODING *enc, const char *p)
+utf8_isName2(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isName3(const ENCODING *enc, const char *p)
+utf8_isName3(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
 }
@@ -142,13 +136,13 @@ utf8_isName3(const ENCODING *enc, const char *p)
 #define utf8_isName4 isNever
 
 static int PTRFASTCALL
-utf8_isNmstrt2(const ENCODING *enc, const char *p)
+utf8_isNmstrt2(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isNmstrt3(const ENCODING *enc, const char *p)
+utf8_isNmstrt3(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
 }
@@ -156,19 +150,19 @@ utf8_isNmstrt3(const ENCODING *enc, const char *p)
 #define utf8_isNmstrt4 isNever
 
 static int PTRFASTCALL
-utf8_isInvalid2(const ENCODING *enc, const char *p)
+utf8_isInvalid2(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_INVALID2((const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isInvalid3(const ENCODING *enc, const char *p)
+utf8_isInvalid3(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_INVALID3((const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isInvalid4(const ENCODING *enc, const char *p)
+utf8_isInvalid4(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_INVALID4((const unsigned char *)p);
 }
@@ -222,6 +216,17 @@ struct normal_encoding {
  E ## isInvalid3, \
  E ## isInvalid4
 
+#define NULL_VTABLE \
+ /* isName2 */ NULL, \
+ /* isName3 */ NULL, \
+ /* isName4 */ NULL, \
+ /* isNmstrt2 */ NULL, \
+ /* isNmstrt3 */ NULL, \
+ /* isNmstrt4 */ NULL, \
+ /* isInvalid2 */ NULL, \
+ /* isInvalid3 */ NULL, \
+ /* isInvalid4 */ NULL
+
 static int FASTCALL checkCharRefNumber(int);
 
 #include "xmltok_impl.h"
@@ -318,39 +323,89 @@ enum {  /* UTF8_cvalN is value of masked first byte of N byte sequence */
   UTF8_cval4 = 0xf0
 };
 
-static void PTRCALL
-utf8_toUtf8(const ENCODING *enc,
+void
+align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef)
+{
+  const char * fromLim = *fromLimRef;
+  size_t walked = 0;
+  for (; fromLim > from; fromLim--, walked++) {
+    const unsigned char prev = (unsigned char)fromLim[-1];
+    if ((prev & 0xf8u) == 0xf0u) { /* 4-byte character, lead by 0b11110xxx byte */
+      if (walked + 1 >= 4) {
+        fromLim += 4 - 1;
+        break;
+      } else {
+        walked = 0;
+      }
+    } else if ((prev & 0xf0u) == 0xe0u) { /* 3-byte character, lead by 0b1110xxxx byte */
+      if (walked + 1 >= 3) {
+        fromLim += 3 - 1;
+        break;
+      } else {
+        walked = 0;
+      }
+    } else if ((prev & 0xe0u) == 0xc0u) { /* 2-byte character, lead by 0b110xxxxx byte */
+      if (walked + 1 >= 2) {
+        fromLim += 2 - 1;
+        break;
+      } else {
+        walked = 0;
+      }
+    } else if ((prev & 0x80u) == 0x00u) { /* 1-byte character, matching 0b0xxxxxxx */
+      break;
+    }
+  }
+  *fromLimRef = fromLim;
+}
+
+static enum XML_Convert_Result PTRCALL
+utf8_toUtf8(const ENCODING *UNUSED_P(enc),
             const char **fromP, const char *fromLim,
             char **toP, const char *toLim)
 {
   char *to;
   const char *from;
-  if (fromLim - *fromP > toLim - *toP) {
-    /* Avoid copying partial characters. */
-    for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
-      if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
-        break;
-  }
-  for (to = *toP, from = *fromP; from != fromLim; from++, to++)
+  const char *fromLimInitial = fromLim;
+
+  /* Avoid copying partial characters. */
+  align_limit_to_full_utf8_characters(*fromP, &fromLim);
+
+  for (to = *toP, from = *fromP; (from < fromLim) && (to < toLim); from++, to++)
     *to = *from;
   *fromP = from;
   *toP = to;
+
+  if (fromLim < fromLimInitial)
+    return XML_CONVERT_INPUT_INCOMPLETE;
+  else if ((to == toLim) && (from < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
-static void PTRCALL
+static enum XML_Convert_Result PTRCALL
 utf8_toUtf16(const ENCODING *enc,
              const char **fromP, const char *fromLim,
              unsigned short **toP, const unsigned short *toLim)
 {
+  enum XML_Convert_Result res = XML_CONVERT_COMPLETED;
   unsigned short *to = *toP;
   const char *from = *fromP;
-  while (from != fromLim && to != toLim) {
+  while (from < fromLim && to < toLim) {
     switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
     case BT_LEAD2:
+      if (fromLim - from < 2) {
+        res = XML_CONVERT_INPUT_INCOMPLETE;
+        goto after;
+      }
       *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
       from += 2;
       break;
     case BT_LEAD3:
+      if (fromLim - from < 3) {
+        res = XML_CONVERT_INPUT_INCOMPLETE;
+        goto after;
+      }
       *to++ = (unsigned short)(((from[0] & 0xf) << 12)
                                | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
       from += 3;
@@ -358,8 +413,14 @@ utf8_toUtf16(const ENCODING *enc,
     case BT_LEAD4:
       {
         unsigned long n;
-        if (to + 1 == toLim)
+        if (toLim - to < 2) {
+          res = XML_CONVERT_OUTPUT_EXHAUSTED;
           goto after;
+        }
+        if (fromLim - from < 4) {
+          res = XML_CONVERT_INPUT_INCOMPLETE;
+          goto after;
+        }
         n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
             | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
         n -= 0x10000;
@@ -374,9 +435,12 @@ utf8_toUtf16(const ENCODING *enc,
       break;
     }
   }
+  if (from < fromLim)
+    res = XML_CONVERT_OUTPUT_EXHAUSTED;
 after:
   *fromP = from;
   *toP = to;
+  return res;
 }
 
 #ifdef XML_NS
@@ -425,38 +489,43 @@ static const struct normal_encoding internal_utf8_encoding = {
   STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
 };
 
-static void PTRCALL
-latin1_toUtf8(const ENCODING *enc,
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf8(const ENCODING *UNUSED_P(enc),
               const char **fromP, const char *fromLim,
               char **toP, const char *toLim)
 {
   for (;;) {
     unsigned char c;
     if (*fromP == fromLim)
-      break;
+      return XML_CONVERT_COMPLETED;
     c = (unsigned char)**fromP;
     if (c & 0x80) {
       if (toLim - *toP < 2)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       *(*toP)++ = (char)((c >> 6) | UTF8_cval2);
       *(*toP)++ = (char)((c & 0x3f) | 0x80);
       (*fromP)++;
     }
     else {
       if (*toP == toLim)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       *(*toP)++ = *(*fromP)++;
     }
   }
 }
 
-static void PTRCALL
-latin1_toUtf16(const ENCODING *enc,
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf16(const ENCODING *UNUSED_P(enc),
                const char **fromP, const char *fromLim,
                unsigned short **toP, const unsigned short *toLim)
 {
-  while (*fromP != fromLim && *toP != toLim)
+  while (*fromP < fromLim && *toP < toLim)
     *(*toP)++ = (unsigned char)*(*fromP)++;
+
+  if ((*toP == toLim) && (*fromP < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
 #ifdef XML_NS
@@ -467,7 +536,7 @@ static const struct normal_encoding latin1_encoding_ns = {
 #include "asciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
 #endif
@@ -480,16 +549,21 @@ static const struct normal_encoding latin1_encoding = {
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
-static void PTRCALL
-ascii_toUtf8(const ENCODING *enc,
+static enum XML_Convert_Result PTRCALL
+ascii_toUtf8(const ENCODING *UNUSED_P(enc),
              const char **fromP, const char *fromLim,
              char **toP, const char *toLim)
 {
-  while (*fromP != fromLim && *toP != toLim)
+  while (*fromP < fromLim && *toP < toLim)
     *(*toP)++ = *(*fromP)++;
+
+  if ((*toP == toLim) && (*fromP < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
 #ifdef XML_NS
@@ -500,7 +574,7 @@ static const struct normal_encoding ascii_encoding_ns = {
 #include "asciitab.h"
 /* BT_NONXML == 0 */
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
 #endif
@@ -513,7 +587,7 @@ static const struct normal_encoding ascii_encoding = {
 #undef BT_COLON
 /* BT_NONXML == 0 */
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
 static int PTRFASTCALL
@@ -536,13 +610,14 @@ unicode_byte_type(char hi, char lo)
 }
 
 #define DEFINE_UTF16_TO_UTF8(E) \
-static void  PTRCALL \
-E ## toUtf8(const ENCODING *enc, \
+static enum XML_Convert_Result  PTRCALL \
+E ## toUtf8(const ENCODING *UNUSED_P(enc), \
             const char **fromP, const char *fromLim, \
             char **toP, const char *toLim) \
 { \
-  const char *from; \
-  for (from = *fromP; from != fromLim; from += 2) { \
+  const char *from = *fromP; \
+  fromLim = from + (((fromLim - from) >> 1) << 1);  /* shrink to even */ \
+  for (; from < fromLim; from += 2) { \
     int plane; \
     unsigned char lo2; \
     unsigned char lo = GET_LO(from); \
@@ -552,7 +627,7 @@ E ## toUtf8(const ENCODING *enc, \
       if (lo < 0x80) { \
         if (*toP == toLim) { \
           *fromP = from; \
-          return; \
+          return XML_CONVERT_OUTPUT_EXHAUSTED; \
         } \
         *(*toP)++ = lo; \
         break; \
@@ -562,7 +637,7 @@ E ## toUtf8(const ENCODING *enc, \
     case 0x4: case 0x5: case 0x6: case 0x7: \
       if (toLim -  *toP < 2) { \
         *fromP = from; \
-        return; \
+        return XML_CONVERT_OUTPUT_EXHAUSTED; \
       } \
       *(*toP)++ = ((lo >> 6) | (hi << 2) |  UTF8_cval2); \
       *(*toP)++ = ((lo & 0x3f) | 0x80); \
@@ -570,7 +645,7 @@ E ## toUtf8(const ENCODING *enc, \
     default: \
       if (toLim -  *toP < 3)  { \
         *fromP = from; \
-        return; \
+        return XML_CONVERT_OUTPUT_EXHAUSTED; \
       } \
       /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
       *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
@@ -580,7 +655,11 @@ E ## toUtf8(const ENCODING *enc, \
     case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
       if (toLim -  *toP < 4) { \
         *fromP = from; \
-        return; \
+        return XML_CONVERT_OUTPUT_EXHAUSTED; \
+      } \
+      if (fromLim - from < 4) { \
+        *fromP = from; \
+        return XML_CONVERT_INPUT_INCOMPLETE; \
       } \
       plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
       *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
@@ -596,20 +675,32 @@ E ## toUtf8(const ENCODING *enc, \
     } \
   } \
   *fromP = from; \
+  if (from < fromLim) \
+    return XML_CONVERT_INPUT_INCOMPLETE; \
+  else \
+    return XML_CONVERT_COMPLETED; \
 }
 
 #define DEFINE_UTF16_TO_UTF16(E) \
-static void  PTRCALL \
-E ## toUtf16(const ENCODING *enc, \
+static enum XML_Convert_Result  PTRCALL \
+E ## toUtf16(const ENCODING *UNUSED_P(enc), \
              const char **fromP, const char *fromLim, \
              unsigned short **toP, const unsigned short *toLim) \
 { \
+  enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
+  fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1);  /* shrink to even */ \
   /* Avoid copying first half only of surrogate */ \
   if (fromLim - *fromP > ((toLim - *toP) << 1) \
-      && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
+      && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
     fromLim -= 2; \
-  for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
+    res = XML_CONVERT_INPUT_INCOMPLETE; \
+  } \
+  for (; *fromP < fromLim && *toP < toLim; *fromP += 2) \
     *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+  if ((*toP == toLim) && (*fromP < fromLim)) \
+    return XML_CONVERT_OUTPUT_EXHAUSTED; \
+  else \
+    return res; \
 }
 
 #define SET2(ptr, ch) \
@@ -726,7 +817,7 @@ static const struct normal_encoding little2_encoding_ns = {
 #include "asciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #endif
@@ -745,7 +836,7 @@ static const struct normal_encoding little2_encoding = {
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #if BYTEORDER != 4321
@@ -758,7 +849,7 @@ static const struct normal_encoding internal_little2_encoding_ns = {
 #include "iasciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #endif
@@ -771,7 +862,7 @@ static const struct normal_encoding internal_little2_encoding = {
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #endif
@@ -867,7 +958,7 @@ static const struct normal_encoding big2_encoding_ns = {
 #include "asciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #endif
@@ -886,7 +977,7 @@ static const struct normal_encoding big2_encoding = {
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #if BYTEORDER != 1234
@@ -899,7 +990,7 @@ static const struct normal_encoding internal_big2_encoding_ns = {
 #include "iasciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #endif
@@ -912,7 +1003,7 @@ static const struct normal_encoding internal_big2_encoding = {
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #endif
@@ -938,7 +1029,7 @@ streqci(const char *s1, const char *s2)
 }
 
 static void PTRCALL
-initUpdatePosition(const ENCODING *enc, const char *ptr,
+initUpdatePosition(const ENCODING *UNUSED_P(enc), const char *ptr,
                    const char *end, POSITION *pos)
 {
   normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
@@ -1288,7 +1379,7 @@ unknown_isInvalid(const ENCODING *enc, const char *p)
   return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
 }
 
-static void PTRCALL
+static enum XML_Convert_Result PTRCALL
 unknown_toUtf8(const ENCODING *enc,
                const char **fromP, const char *fromLim,
                char **toP, const char *toLim)
@@ -1299,21 +1390,21 @@ unknown_toUtf8(const ENCODING *enc,
     const char *utf8;
     int n;
     if (*fromP == fromLim)
-      break;
+      return XML_CONVERT_COMPLETED;
     utf8 = uenc->utf8[(unsigned char)**fromP];
     n = *utf8++;
     if (n == 0) {
       int c = uenc->convert(uenc->userData, *fromP);
       n = XmlUtf8Encode(c, buf);
       if (n > toLim - *toP)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       utf8 = buf;
       *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
                  - (BT_LEAD2 - 2));
     }
     else {
       if (n > toLim - *toP)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       (*fromP)++;
     }
     do {
@@ -1322,13 +1413,13 @@ unknown_toUtf8(const ENCODING *enc,
   }
 }
 
-static void PTRCALL
+static enum XML_Convert_Result PTRCALL
 unknown_toUtf16(const ENCODING *enc,
                 const char **fromP, const char *fromLim,
                 unsigned short **toP, const unsigned short *toLim)
 {
   const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
-  while (*fromP != fromLim && *toP != toLim) {
+  while (*fromP < fromLim && *toP < toLim) {
     unsigned short c = uenc->utf16[(unsigned char)**fromP];
     if (c == 0) {
       c = (unsigned short)
@@ -1340,6 +1431,11 @@ unknown_toUtf16(const ENCODING *enc,
       (*fromP)++;
     *(*toP)++ = c;
   }
+
+  if ((*toP == toLim) && (*fromP < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
 ENCODING *
@@ -1503,7 +1599,7 @@ initScan(const ENCODING * const *encodingTable,
 {
   const ENCODING **encPtr;
 
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   encPtr = enc->encPtr;
   if (ptr + 1 == end) {
diff --git a/lib-src/expat/lib/xmltok.h b/lib-src/expat/lib/xmltok.h
index ca867aa6b..752007e8b 100644
--- a/lib-src/expat/lib/xmltok.h
+++ b/lib-src/expat/lib/xmltok.h
@@ -130,6 +130,12 @@ typedef int (PTRCALL *SCANNER)(const ENCODING *,
                                const char *,
                                const char **);
 
+enum XML_Convert_Result {
+  XML_CONVERT_COMPLETED = 0,
+  XML_CONVERT_INPUT_INCOMPLETE = 1,
+  XML_CONVERT_OUTPUT_EXHAUSTED = 2  /* and therefore potentially input remaining as well */
+};
+
 struct encoding {
   SCANNER scanners[XML_N_STATES];
   SCANNER literalScanners[XML_N_LITERAL_TYPES];
@@ -158,12 +164,12 @@ struct encoding {
                             const char *ptr,
                             const char *end,
                             const char **badPtr);
-  void (PTRCALL *utf8Convert)(const ENCODING *enc,
+  enum XML_Convert_Result (PTRCALL *utf8Convert)(const ENCODING *enc,
                               const char **fromP,
                               const char *fromLim,
                               char **toP,
                               const char *toLim);
-  void (PTRCALL *utf16Convert)(const ENCODING *enc,
+  enum XML_Convert_Result (PTRCALL *utf16Convert)(const ENCODING *enc,
                                const char **fromP,
                                const char *fromLim,
                                unsigned short **toP,
diff --git a/lib-src/expat/lib/xmltok_impl.c b/lib-src/expat/lib/xmltok_impl.c
index 9c2895b87..5f779c057 100644
--- a/lib-src/expat/lib/xmltok_impl.c
+++ b/lib-src/expat/lib/xmltok_impl.c
@@ -87,27 +87,45 @@
 #define PREFIX(ident) ident
 #endif
 
+
+#define HAS_CHARS(enc, ptr, end, count) \
+    (end - ptr >= count * MINBPC(enc))
+
+#define HAS_CHAR(enc, ptr, end) \
+    HAS_CHARS(enc, ptr, end, 1)
+
+#define REQUIRE_CHARS(enc, ptr, end, count) \
+    { \
+      if (! HAS_CHARS(enc, ptr, end, count)) { \
+        return XML_TOK_PARTIAL; \
+      } \
+    }
+
+#define REQUIRE_CHAR(enc, ptr, end) \
+    REQUIRE_CHARS(enc, ptr, end, 1)
+
+
 /* ptr points to character following " */
       switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
       case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
@@ -175,7 +191,7 @@ PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
 }
 
 static int PTRCALL
-PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr,
+PREFIX(checkPiTarget)(const ENCODING *UNUSED_P(enc), const char *ptr,
                       const char *end, int *tokPtr)
 {
   int upper = 0;
@@ -225,15 +241,14 @@ PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
 {
   int tok;
   const char *target = ptr;
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   default:
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_S: case BT_CR: case BT_LF:
@@ -242,13 +257,12 @@ PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
         return XML_TOK_INVALID;
       }
       ptr += MINBPC(enc);
-      while (ptr != end) {
+      while (HAS_CHAR(enc, ptr, end)) {
         switch (BYTE_TYPE(enc, ptr)) {
         INVALID_CASES(ptr, nextTokPtr)
         case BT_QUEST:
           ptr += MINBPC(enc);
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
             *nextTokPtr = ptr + MINBPC(enc);
             return tok;
@@ -266,8 +280,7 @@ PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
         return XML_TOK_INVALID;
       }
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
         *nextTokPtr = ptr + MINBPC(enc);
         return tok;
@@ -282,15 +295,14 @@ PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
 }
 
 static int PTRCALL
-PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr,
+PREFIX(scanCdataSection)(const ENCODING *UNUSED_P(enc), const char *ptr,
                          const char *end, const char **nextTokPtr)
 {
   static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
                                      ASCII_T, ASCII_A, ASCII_LSQB };
   int i;
   /* CDATA[ */
-  if (end - ptr < 6 * MINBPC(enc))
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHARS(enc, ptr, end, 6);
   for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
     if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
       *nextTokPtr = ptr;
@@ -305,7 +317,7 @@ static int PTRCALL
 PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
                         const char *end, const char **nextTokPtr)
 {
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   if (MINBPC(enc) > 1) {
     size_t n = end - ptr;
@@ -319,13 +331,11 @@ PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
   switch (BYTE_TYPE(enc, ptr)) {
   case BT_RSQB:
     ptr += MINBPC(enc);
-    if (ptr == end)
-      return XML_TOK_PARTIAL;
+    REQUIRE_CHAR(enc, ptr, end);
     if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
       break;
     ptr += MINBPC(enc);
-    if (ptr == end)
-      return XML_TOK_PARTIAL;
+    REQUIRE_CHAR(enc, ptr, end);
     if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
       ptr -= MINBPC(enc);
       break;
@@ -334,8 +344,7 @@ PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
     return XML_TOK_CDATA_SECT_CLOSE;
   case BT_CR:
     ptr += MINBPC(enc);
-    if (ptr == end)
-      return XML_TOK_PARTIAL;
+    REQUIRE_CHAR(enc, ptr, end);
     if (BYTE_TYPE(enc, ptr) == BT_LF)
       ptr += MINBPC(enc);
     *nextTokPtr = ptr;
@@ -348,7 +357,7 @@ PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
     ptr += MINBPC(enc);
     break;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: \
@@ -383,19 +392,18 @@ static int PTRCALL
 PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
                    const char *end, const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   default:
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_S: case BT_CR: case BT_LF:
-      for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+      for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
         switch (BYTE_TYPE(enc, ptr)) {
         case BT_S: case BT_CR: case BT_LF:
           break;
@@ -432,7 +440,7 @@ static int PTRCALL
 PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
                        const char *end, const char **nextTokPtr)
 {
-  if (ptr != end) {
+  if (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_DIGIT:
     case BT_HEX:
@@ -441,7 +449,7 @@ PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
       *nextTokPtr = ptr;
       return XML_TOK_INVALID;
     }
-    for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+    for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_DIGIT:
       case BT_HEX:
@@ -464,7 +472,7 @@ static int PTRCALL
 PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
                     const char *end, const char **nextTokPtr)
 {
-  if (ptr != end) {
+  if (HAS_CHAR(enc, ptr, end)) {
     if (CHAR_MATCHES(enc, ptr, ASCII_x))
       return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
     switch (BYTE_TYPE(enc, ptr)) {
@@ -474,7 +482,7 @@ PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
       *nextTokPtr = ptr;
       return XML_TOK_INVALID;
     }
-    for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+    for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_DIGIT:
         break;
@@ -496,8 +504,7 @@ static int PTRCALL
 PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
                 const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   case BT_NUM:
@@ -506,7 +513,7 @@ PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_SEMI:
@@ -529,7 +536,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
 #ifdef XML_NS
   int hadColon = 0;
 #endif
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
 #ifdef XML_NS
@@ -540,8 +547,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
       }
       hadColon = 1;
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       switch (BYTE_TYPE(enc, ptr)) {
       CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
       default:
@@ -555,8 +561,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
         int t;
 
         ptr += MINBPC(enc);
-        if (ptr == end)
-          return XML_TOK_PARTIAL;
+        REQUIRE_CHAR(enc, ptr, end);
         t = BYTE_TYPE(enc, ptr);
         if (t == BT_EQUALS)
           break;
@@ -579,8 +584,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
 #endif
         for (;;) {
           ptr += MINBPC(enc);
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           open = BYTE_TYPE(enc, ptr);
           if (open == BT_QUOT || open == BT_APOS)
             break;
@@ -598,8 +602,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
         /* in attribute value */
         for (;;) {
           int t;
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           t = BYTE_TYPE(enc, ptr);
           if (t == open)
             break;
@@ -624,8 +627,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
           }
         }
         ptr += MINBPC(enc);
-        if (ptr == end)
-          return XML_TOK_PARTIAL;
+        REQUIRE_CHAR(enc, ptr, end);
         switch (BYTE_TYPE(enc, ptr)) {
         case BT_S:
         case BT_CR:
@@ -642,8 +644,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
         /* ptr points to closing quote */
         for (;;) {
           ptr += MINBPC(enc);
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           switch (BYTE_TYPE(enc, ptr)) {
           CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
           case BT_S: case BT_CR: case BT_LF:
@@ -655,8 +656,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
           case BT_SOL:
           sol:
             ptr += MINBPC(enc);
-            if (ptr == end)
-              return XML_TOK_PARTIAL;
+            REQUIRE_CHAR(enc, ptr, end);
             if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
               *nextTokPtr = ptr;
               return XML_TOK_INVALID;
@@ -688,13 +688,12 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
 #ifdef XML_NS
   int hadColon;
 #endif
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   case BT_EXCL:
-    if ((ptr += MINBPC(enc)) == end)
-      return XML_TOK_PARTIAL;
+    ptr += MINBPC(enc);
+    REQUIRE_CHAR(enc, ptr, end);
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_MINUS:
       return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -716,7 +715,7 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
   hadColon = 0;
 #endif
   /* we have a start-tag */
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
 #ifdef XML_NS
@@ -727,8 +726,7 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
       }
       hadColon = 1;
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       switch (BYTE_TYPE(enc, ptr)) {
       CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
       default:
@@ -740,7 +738,7 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
     case BT_S: case BT_CR: case BT_LF:
       {
         ptr += MINBPC(enc);
-        while (ptr != end) {
+        while (HAS_CHAR(enc, ptr, end)) {
           switch (BYTE_TYPE(enc, ptr)) {
           CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
           case BT_GT:
@@ -765,8 +763,7 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
     case BT_SOL:
     sol:
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
         *nextTokPtr = ptr;
         return XML_TOK_INVALID;
@@ -785,7 +782,7 @@ static int PTRCALL
 PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
                    const char **nextTokPtr)
 {
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   if (MINBPC(enc) > 1) {
     size_t n = end - ptr;
@@ -803,7 +800,7 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
     return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
   case BT_CR:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return XML_TOK_TRAILING_CR;
     if (BYTE_TYPE(enc, ptr) == BT_LF)
       ptr += MINBPC(enc);
@@ -814,12 +811,12 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
     return XML_TOK_DATA_NEWLINE;
   case BT_RSQB:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return XML_TOK_TRAILING_RSQB;
     if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
       break;
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return XML_TOK_TRAILING_RSQB;
     if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
       ptr -= MINBPC(enc);
@@ -832,7 +829,7 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
     ptr += MINBPC(enc);
     break;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: \
@@ -845,12 +842,12 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
     LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
 #undef LEAD_CASE
     case BT_RSQB:
-      if (ptr + MINBPC(enc) != end) {
+      if (HAS_CHARS(enc, ptr, end, 2)) {
          if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
            ptr += MINBPC(enc);
            break;
          }
-         if (ptr + 2*MINBPC(enc) != end) {
+         if (HAS_CHARS(enc, ptr, end, 3)) {
            if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
              ptr += MINBPC(enc);
              break;
@@ -884,8 +881,7 @@ static int PTRCALL
 PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
                     const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
@@ -895,7 +891,7 @@ PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_SEMI:
@@ -913,15 +909,14 @@ static int PTRCALL
 PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
                       const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   default:
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_CR: case BT_LF: case BT_S:
@@ -941,7 +936,7 @@ PREFIX(scanLit)(int open, const ENCODING *enc,
                 const char *ptr, const char *end,
                 const char **nextTokPtr)
 {
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     int t = BYTE_TYPE(enc, ptr);
     switch (t) {
     INVALID_CASES(ptr, nextTokPtr)
@@ -950,7 +945,7 @@ PREFIX(scanLit)(int open, const ENCODING *enc,
       ptr += MINBPC(enc);
       if (t != open)
         break;
-      if (ptr == end)
+      if (! HAS_CHAR(enc, ptr, end))
         return -XML_TOK_LITERAL;
       *nextTokPtr = ptr;
       switch (BYTE_TYPE(enc, ptr)) {
@@ -973,7 +968,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
                   const char **nextTokPtr)
 {
   int tok;
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   if (MINBPC(enc) > 1) {
     size_t n = end - ptr;
@@ -992,8 +987,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
   case BT_LT:
     {
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_EXCL:
         return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -1021,7 +1015,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
   case BT_S: case BT_LF:
     for (;;) {
       ptr += MINBPC(enc);
-      if (ptr == end)
+      if (! HAS_CHAR(enc, ptr, end))
         break;
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_S: case BT_LF:
@@ -1048,11 +1042,10 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
     return XML_TOK_OPEN_BRACKET;
   case BT_RSQB:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return -XML_TOK_CLOSE_BRACKET;
     if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
-      if (ptr + MINBPC(enc) == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHARS(enc, ptr, end, 2);
       if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
         *nextTokPtr = ptr + 2*MINBPC(enc);
         return XML_TOK_COND_SECT_CLOSE;
@@ -1065,7 +1058,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
     return XML_TOK_OPEN_PAREN;
   case BT_RPAR:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return -XML_TOK_CLOSE_PAREN;
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_AST:
@@ -1141,7 +1134,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_GT: case BT_RPAR: case BT_COMMA:
@@ -1154,8 +1147,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
       ptr += MINBPC(enc);
       switch (tok) {
       case XML_TOK_NAME:
-        if (ptr == end)
-          return XML_TOK_PARTIAL;
+        REQUIRE_CHAR(enc, ptr, end);
         tok = XML_TOK_PREFIXED_NAME;
         switch (BYTE_TYPE(enc, ptr)) {
         CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
@@ -1204,10 +1196,12 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
                           const char *end, const char **nextTokPtr)
 {
   const char *start;
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
+  else if (! HAS_CHAR(enc, ptr, end))
+    return XML_TOK_PARTIAL;
   start = ptr;
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: ptr += n; break;
@@ -1232,7 +1226,7 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
     case BT_CR:
       if (ptr == start) {
         ptr += MINBPC(enc);
-        if (ptr == end)
+        if (! HAS_CHAR(enc, ptr, end))
           return XML_TOK_TRAILING_CR;
         if (BYTE_TYPE(enc, ptr) == BT_LF)
           ptr += MINBPC(enc);
@@ -1262,10 +1256,12 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
                        const char *end, const char **nextTokPtr)
 {
   const char *start;
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
+  else if (! HAS_CHAR(enc, ptr, end))
+    return XML_TOK_PARTIAL;
   start = ptr;
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: ptr += n; break;
@@ -1294,7 +1290,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
     case BT_CR:
       if (ptr == start) {
         ptr += MINBPC(enc);
-        if (ptr == end)
+        if (! HAS_CHAR(enc, ptr, end))
           return XML_TOK_TRAILING_CR;
         if (BYTE_TYPE(enc, ptr) == BT_LF)
           ptr += MINBPC(enc);
@@ -1326,15 +1322,15 @@ PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
       end = ptr + n;
     }
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     INVALID_CASES(ptr, nextTokPtr)
     case BT_LT:
-      if ((ptr += MINBPC(enc)) == end)
-        return XML_TOK_PARTIAL;
+      ptr += MINBPC(enc);
+      REQUIRE_CHAR(enc, ptr, end);
       if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
-        if ((ptr += MINBPC(enc)) == end)
-          return XML_TOK_PARTIAL;
+        ptr += MINBPC(enc);
+        REQUIRE_CHAR(enc, ptr, end);
         if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
           ++level;
           ptr += MINBPC(enc);
@@ -1342,11 +1338,11 @@ PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
       }
       break;
     case BT_RSQB:
-      if ((ptr += MINBPC(enc)) == end)
-        return XML_TOK_PARTIAL;
+      ptr += MINBPC(enc);
+      REQUIRE_CHAR(enc, ptr, end);
       if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
-        if ((ptr += MINBPC(enc)) == end)
-          return XML_TOK_PARTIAL;
+        ptr += MINBPC(enc);
+        REQUIRE_CHAR(enc, ptr, end);
         if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
           ptr += MINBPC(enc);
           if (level == 0) {
@@ -1373,7 +1369,7 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
 {
   ptr += MINBPC(enc);
   end -= MINBPC(enc);
-  for (; ptr != end; ptr += MINBPC(enc)) {
+  for (; HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_DIGIT:
     case BT_HEX:
@@ -1521,7 +1517,7 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
 }
 
 static int PTRFASTCALL
-PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
+PREFIX(charRefNumber)(const ENCODING *UNUSED_P(enc), const char *ptr)
 {
   int result = 0;
   /* skip &# */
@@ -1565,7 +1561,7 @@ PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
 }
 
 static int PTRCALL
-PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
+PREFIX(predefinedEntityName)(const ENCODING *UNUSED_P(enc), const char *ptr,
                              const char *end)
 {
   switch ((end - ptr)/MINBPC(enc)) {
@@ -1683,11 +1679,11 @@ PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
 }
 
 static int PTRCALL
-PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
+PREFIX(nameMatchesAscii)(const ENCODING *UNUSED_P(enc), const char *ptr1,
                          const char *end1, const char *ptr2)
 {
   for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
-    if (ptr1 == end1)
+    if (end1 - ptr1 < MINBPC(enc))
       return 0;
     if (!CHAR_MATCHES(enc, ptr1, *ptr2))
       return 0;
@@ -1744,7 +1740,7 @@ PREFIX(updatePosition)(const ENCODING *enc,
                        const char *end,
                        POSITION *pos)
 {
-  while (ptr < end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: \
@@ -1760,7 +1756,7 @@ PREFIX(updatePosition)(const ENCODING *enc,
     case BT_CR:
       pos->lineNumber++;
       ptr += MINBPC(enc);
-      if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
+      if (HAS_CHAR(enc, ptr, end) && BYTE_TYPE(enc, ptr) == BT_LF)
         ptr += MINBPC(enc);
       pos->columnNumber = (XML_Size)-1;
       break;
diff --git a/lib-src/expat/tests/benchmark/README.txt b/lib-src/expat/tests/benchmark/README.txt
index 7f9cca037..86414d581 100644
--- a/lib-src/expat/tests/benchmark/README.txt
+++ b/lib-src/expat/tests/benchmark/README.txt
@@ -13,4 +13,4 @@ The command line arguments are:
 Returns:
 
   The time (in seconds) it takes to parse the test file,
-  averaged over the number of iterations.
\ No newline at end of file
+  averaged over the number of iterations.@
diff --git a/lib-src/expat/tests/benchmark/benchmark.c b/lib-src/expat/tests/benchmark/benchmark.c
index 0f0fd18c1..efa2858a3 100644
--- a/lib-src/expat/tests/benchmark/benchmark.c
+++ b/lib-src/expat/tests/benchmark/benchmark.c
@@ -4,10 +4,6 @@
 #include 
 #include "expat.h"
 
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include 
-#endif
-
 #ifdef XML_LARGE_SIZE
 #define XML_FMT_INT_MOD "ll"
 #else
diff --git a/lib-src/expat/tests/chardata.c b/lib-src/expat/tests/chardata.c
index 5fb0299d8..012499bb8 100644
--- a/lib-src/expat/tests/chardata.c
+++ b/lib-src/expat/tests/chardata.c
@@ -7,11 +7,7 @@
 #ifdef HAVE_EXPAT_CONFIG_H
 #include 
 #endif
-#ifdef HAVE_CHECK_H
-#include 
-#else
 #include "minicheck.h"
-#endif
 
 #include 
 #include 
@@ -51,7 +47,7 @@ CharData_AppendString(CharData *storage, const char *s)
     if ((len + storage->count) > maxchars) {
         len = (maxchars - storage->count);
     }
-    if (len + storage->count < sizeof(storage->data)) {
+    if (len + storage->count < (int)sizeof(storage->data)) {
         memcpy(storage->data + storage->count, s, len);
         storage->count += len;
     }
@@ -72,7 +68,7 @@ CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len)
     if ((len + storage->count) > maxchars) {
         len = (maxchars - storage->count);
     }
-    if (len + storage->count < sizeof(storage->data)) {
+    if (len + storage->count < (int)sizeof(storage->data)) {
         memcpy(storage->data + storage->count, s,
                len * sizeof(storage->data[0]));
         storage->count += len;
diff --git a/lib-src/expat/tests/minicheck.c b/lib-src/expat/tests/minicheck.c
index d2f4295ff..9003d3b7f 100644
--- a/lib-src/expat/tests/minicheck.c
+++ b/lib-src/expat/tests/minicheck.c
@@ -10,10 +10,11 @@
 #include 
 #include 
 
+#include "internal.h"  /* for UNUSED_P only */
 #include "minicheck.h"
 
 Suite *
-suite_create(char *name)
+suite_create(const char *name)
 {
     Suite *suite = (Suite *) calloc(1, sizeof(Suite));
     if (suite != NULL) {
@@ -23,7 +24,7 @@ suite_create(char *name)
 }
 
 TCase *
-tcase_create(char *name)
+tcase_create(const char *name)
 {
     TCase *tc = (TCase *) calloc(1, sizeof(TCase));
     if (tc != NULL) {
@@ -62,10 +63,7 @@ tcase_add_test(TCase *tc, tcase_test_function test)
         size_t new_size = sizeof(tcase_test_function) * nalloc;
         tcase_test_function *new_tests = realloc(tc->tests, new_size);
         assert(new_tests != NULL);
-        if (new_tests != tc->tests) {
-            free(tc->tests);
-            tc->tests = new_tests;
-        }
+        tc->tests = new_tests;
         tc->allocated = nalloc;
     }
     tc->tests[tc->ntests] = test;
@@ -156,7 +154,7 @@ srunner_run_all(SRunner *runner, int verbosity)
 }
 
 void
-_fail_unless(int condition, const char *file, int line, char *msg)
+_fail_unless(int UNUSED_P(condition), const char *UNUSED_P(file), int UNUSED_P(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
diff --git a/lib-src/expat/tests/minicheck.h b/lib-src/expat/tests/minicheck.h
index c917c0269..319c981dd 100644
--- a/lib-src/expat/tests/minicheck.h
+++ b/lib-src/expat/tests/minicheck.h
@@ -26,6 +26,12 @@ extern "C" {
 #define __func__ __FUNCTION__
 #endif
 
+/* ISO C90 does not support '__func__' predefined identifier */
+#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901)) || \
+    (defined(__GNUC__) && !defined(__STDC_VERSION__))
+# define __func__ "(unknown)"
+#endif
+
 #define START_TEST(testname) static void testname(void) { \
     _check_set_test_info(__func__, __FILE__, __LINE__);   \
     {
@@ -48,12 +54,12 @@ struct SRunner {
 };
 
 struct Suite {
-    char *name;
+    const char *name;
     TCase *tests;
 };
 
 struct TCase {
-    char *name;
+    const char *name;
     tcase_setup_function setup;
     tcase_teardown_function teardown;
     tcase_test_function *tests;
@@ -72,9 +78,9 @@ void _check_set_test_info(char const *function,
  * Prototypes for the actual implementation.
  */
 
-void _fail_unless(int condition, const char *file, int line, char *msg);
-Suite *suite_create(char *name);
-TCase *tcase_create(char *name);
+void _fail_unless(int condition, 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,
diff --git a/lib-src/expat/tests/runtests.c b/lib-src/expat/tests/runtests.c
index 614d6b248..a689ffad8 100644
--- a/lib-src/expat/tests/runtests.c
+++ b/lib-src/expat/tests/runtests.c
@@ -13,14 +13,19 @@
 #include 
 #include 
 #include 
+#include   /* ptrdiff_t */
+#include 
+#ifndef __cplusplus
+# include 
+#endif
+#include 
 
 #include "expat.h"
 #include "chardata.h"
+#include "internal.h"  /* for UNUSED_P only */
 #include "minicheck.h"
-
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include 
-#endif
+#include "memcheck.h"
+#include "siphash.h"
 
 #ifdef XML_LARGE_SIZE
 #define XML_FMT_INT_MOD "ll"
@@ -28,7 +33,7 @@
 #define XML_FMT_INT_MOD "l"
 #endif
 
-static XML_Parser parser;
+static XML_Parser parser = NULL;
 
 
 static void
@@ -42,8 +47,10 @@ basic_setup(void)
 static void
 basic_teardown(void)
 {
-    if (parser != NULL)
+    if (parser != NULL) {
         XML_ParserFree(parser);
+        parser = NULL;
+    }
 }
 
 /* Generate a failure using the parser state to create an error message;
@@ -66,13 +73,34 @@ _xml_failure(XML_Parser parser, const char *file, int 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(char *text, enum XML_Error errorCode, char *errorMessage,
-                char *file, int lineno)
+_expect_failure(const char *text, enum XML_Error errorCode, const char *errorMessage,
+                const char *file, int lineno)
 {
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, 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);
@@ -89,63 +117,94 @@ _expect_failure(char *text, enum XML_Error errorCode, char *errorMessage,
 */
 
 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)
+dummy_start_doctype_handler(void           *UNUSED_P(userData),
+                            const XML_Char *UNUSED_P(doctypeName),
+                            const XML_Char *UNUSED_P(sysid),
+                            const XML_Char *UNUSED_P(pubid),
+                            int            UNUSED_P(has_internal_subset))
 {}
 
 static void XMLCALL
-dummy_end_doctype_handler(void *userData)
+dummy_end_doctype_handler(void *UNUSED_P(userData))
 {}
 
 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)
+dummy_entity_decl_handler(void           *UNUSED_P(userData),
+                          const XML_Char *UNUSED_P(entityName),
+                          int            UNUSED_P(is_parameter_entity),
+                          const XML_Char *UNUSED_P(value),
+                          int            UNUSED_P(value_length),
+                          const XML_Char *UNUSED_P(base),
+                          const XML_Char *UNUSED_P(systemId),
+                          const XML_Char *UNUSED_P(publicId),
+                          const XML_Char *UNUSED_P(notationName))
 {}
 
 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)
+dummy_notation_decl_handler(void *UNUSED_P(userData),
+                            const XML_Char *UNUSED_P(notationName),
+                            const XML_Char *UNUSED_P(base),
+                            const XML_Char *UNUSED_P(systemId),
+                            const XML_Char *UNUSED_P(publicId))
 {}
 
 static void XMLCALL
-dummy_element_decl_handler(void *userData,
-                           const XML_Char *name,
-                           XML_Content *model)
+dummy_element_decl_handler(void *UNUSED_P(userData),
+                           const XML_Char *UNUSED_P(name),
+                           XML_Content *UNUSED_P(model))
 {}
 
 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)
+dummy_attlist_decl_handler(void           *UNUSED_P(userData),
+                           const XML_Char *UNUSED_P(elname),
+                           const XML_Char *UNUSED_P(attname),
+                           const XML_Char *UNUSED_P(att_type),
+                           const XML_Char *UNUSED_P(dflt),
+                           int            UNUSED_P(isrequired))
 {}
 
 static void XMLCALL
-dummy_comment_handler(void *userData, const XML_Char *data)
+dummy_comment_handler(void *UNUSED_P(userData), const XML_Char *UNUSED_P(data))
 {}
 
 static void XMLCALL
-dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data)
+dummy_pi_handler(void *UNUSED_P(userData), const XML_Char *UNUSED_P(target), const XML_Char *UNUSED_P(data))
 {}
 
 static void XMLCALL
-dummy_start_element(void *userData,
-                    const XML_Char *name, const XML_Char **atts)
+dummy_start_element(void *UNUSED_P(userData),
+                    const XML_Char *UNUSED_P(name), const XML_Char **UNUSED_P(atts))
+{}
+
+static void XMLCALL
+dummy_start_cdata_handler(void *UNUSED_P(userData))
+{}
+
+static void XMLCALL
+dummy_end_cdata_handler(void *UNUSED_P(userData))
+{}
+
+static void XMLCALL
+dummy_start_namespace_decl_handler(void *UNUSED_P(userData),
+                                   const XML_Char *UNUSED_P(prefix),
+                                   const XML_Char *UNUSED_P(uri))
+{}
+
+static void XMLCALL
+dummy_end_namespace_decl_handler(void *UNUSED_P(userData),
+                                 const XML_Char *UNUSED_P(prefix))
+{}
+
+/* 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 *UNUSED_P(userData),
+                                   const XML_Char *UNUSED_P(entityName),
+                                   const XML_Char *UNUSED_P(base),
+                                   const XML_Char *UNUSED_P(systemId),
+                                   const XML_Char *UNUSED_P(publicId),
+                                   const XML_Char *UNUSED_P(notationName))
 {}
 
 
@@ -158,7 +217,7 @@ START_TEST(test_nul_byte)
     char text[] = "\0";
 
     /* test that a NUL byte (in US-ASCII data) is an error */
-    if (XML_Parse(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_OK)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_OK)
         fail("Parser did not report error on NUL-byte.");
     if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
         xml_failure(parser);
@@ -175,12 +234,51 @@ START_TEST(test_u0000_char)
 }
 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 = 0xa129ca6149be45e5U;
+    struct siphash state;
+    struct sipkey key;
+    (void)sip_tobin;
+
+    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. */
-    char *text = "\357\273\277";
+    const char *text = "\357\273\277";
 
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -189,7 +287,7 @@ START_TEST(test_bom_utf16_be)
 {
     char text[] = "\376\377\0<\0e\0/\0>";
 
-    if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -198,7 +296,7 @@ START_TEST(test_bom_utf16_le)
 {
     char text[] = "\377\376<\0e\0/\0>\0";
 
-    if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -210,7 +308,7 @@ accumulate_characters(void *userData, const XML_Char *s, int len)
 }
 
 static void XMLCALL
-accumulate_attribute(void *userData, const XML_Char *name,
+accumulate_attribute(void *userData, const XML_Char *UNUSED_P(name),
                      const XML_Char **atts)
 {
     CharData *storage = (CharData *)userData;
@@ -222,7 +320,7 @@ accumulate_attribute(void *userData, const XML_Char *name,
 
 
 static void
-_run_character_check(XML_Char *text, XML_Char *expected,
+_run_character_check(const XML_Char *text, const XML_Char *expected,
                      const char *file, int line)
 {
     CharData storage;
@@ -230,7 +328,7 @@ _run_character_check(XML_Char *text, XML_Char *expected,
     CharData_Init(&storage);
     XML_SetUserData(parser, &storage);
     XML_SetCharacterDataHandler(parser, accumulate_characters);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         _xml_failure(parser, file, line);
     CharData_CheckXMLChars(&storage, expected);
 }
@@ -239,7 +337,7 @@ _run_character_check(XML_Char *text, XML_Char *expected,
         _run_character_check(text, expected, __FILE__, __LINE__)
 
 static void
-_run_attribute_check(XML_Char *text, XML_Char *expected,
+_run_attribute_check(const XML_Char *text, const XML_Char *expected,
                      const char *file, int line)
 {
     CharData storage;
@@ -247,7 +345,7 @@ _run_attribute_check(XML_Char *text, XML_Char *expected,
     CharData_Init(&storage);
     XML_SetUserData(parser, &storage);
     XML_SetStartElementHandler(parser, accumulate_attribute);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         _xml_failure(parser, file, line);
     CharData_CheckXMLChars(&storage, expected);
 }
@@ -258,7 +356,7 @@ _run_attribute_check(XML_Char *text, XML_Char *expected,
 /* Regression test for SF bug #491986. */
 START_TEST(test_danish_latin1)
 {
-    char *text =
+    const char *text =
         "\n"
         "J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5";
     run_character_check(text,
@@ -270,7 +368,7 @@ END_TEST
 /* Regression test for SF bug #514281. */
 START_TEST(test_french_charref_hexidecimal)
 {
-    char *text =
+    const char *text =
         "\n"
         "éèàçêÈ";
     run_character_check(text,
@@ -280,7 +378,7 @@ END_TEST
 
 START_TEST(test_french_charref_decimal)
 {
-    char *text =
+    const char *text =
         "\n"
         "éèàçêÈ";
     run_character_check(text,
@@ -290,7 +388,7 @@ END_TEST
 
 START_TEST(test_french_latin1)
 {
-    char *text =
+    const char *text =
         "\n"
         "\xE9\xE8\xE0\xE7\xEa\xC8";
     run_character_check(text,
@@ -300,7 +398,7 @@ END_TEST
 
 START_TEST(test_french_utf8)
 {
-    char *text =
+    const char *text =
         "\n"
         "\xC3\xA9";
     run_character_check(text, "\xC3\xA9");
@@ -314,7 +412,7 @@ END_TEST
 */
 START_TEST(test_utf8_false_rejection)
 {
-    char *text = "\xEF\xBA\xBF";
+    const char *text = "\xEF\xBA\xBF";
     run_character_check(text, "\xEF\xBA\xBF");
 }
 END_TEST
@@ -331,7 +429,7 @@ START_TEST(test_illegal_utf8)
 
     for (i = 128; i <= 255; ++i) {
         sprintf(text, "%ccd", i);
-        if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) {
+        if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) {
             sprintf(text,
                     "expected token error for '%c' (ordinal %d) in UTF-8 text",
                     i, i);
@@ -345,6 +443,68 @@ START_TEST(test_illegal_utf8)
 }
 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;
+
+        align_limit_to_full_utf8_characters(cases[i].input, &fromLim);
+
+        actualMovementInChars = (fromLim - fromLimInitially);
+        if (actualMovementInChars != cases[i].expectedMovementInChars) {
+            size_t j = 0;
+            success = false;
+            printf("[-] UTF-8 case %2lu: Expected movement by %2ld chars"
+                    ", actually moved by %2ld chars: \"",
+                    i + 1, cases[i].expectedMovementInChars, 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)
 {
     /* 
@@ -358,7 +518,7 @@ START_TEST(test_utf16)
         "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'"
         "\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/"
         "\000d\000o\000c\000>";
-    if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -373,12 +533,12 @@ START_TEST(test_utf16_le_epilog_newline)
 
     if (first_chunk_bytes >= sizeof(text) - 1)
         fail("bad value of first_chunk_bytes");
-    if (  XML_Parse(parser, text, first_chunk_bytes, XML_FALSE)
+    if (  _XML_Parse_SINGLE_BYTES(parser, text, first_chunk_bytes, XML_FALSE)
           == XML_STATUS_ERROR)
         xml_failure(parser);
     else {
         enum XML_Status rc;
-        rc = XML_Parse(parser, text + first_chunk_bytes,
+        rc = _XML_Parse_SINGLE_BYTES(parser, text + first_chunk_bytes,
                        sizeof(text) - first_chunk_bytes - 1, XML_TRUE);
         if (rc == XML_STATUS_ERROR)
             xml_failure(parser);
@@ -389,11 +549,11 @@ END_TEST
 /* Regression test for SF bug #481609, #774028. */
 START_TEST(test_latin1_umlauts)
 {
-    char *text =
+    const char *text =
         "\n"
         "\xE4 \xF6 \xFC ä ö ü ä ö ü >";
-    char *utf8 =
+    const char *utf8 =
         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
         "\xC3\xA4 \xC3\xB6 \xC3\xBC >";
@@ -406,13 +566,13 @@ END_TEST
 /* Regression test #1 for SF bug #653180. */
 START_TEST(test_line_number_after_parse)
 {  
-    char *text =
+    const char *text =
         "\n"
         "\n"
         "\n";
     XML_Size lineno;
 
-    if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
         xml_failure(parser);
     lineno = XML_GetCurrentLineNumber(parser);
     if (lineno != 4) {
@@ -427,10 +587,10 @@ END_TEST
 /* Regression test #2 for SF bug #653180. */
 START_TEST(test_column_number_after_parse)
 {
-    char *text = "";
+    const char *text = "";
     XML_Size colno;
 
-    if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
         xml_failure(parser);
     colno = XML_GetCurrentColumnNumber(parser);
     if (colno != 11) {
@@ -444,7 +604,7 @@ END_TEST
 
 static void XMLCALL
 start_element_event_handler2(void *userData, const XML_Char *name,
-			     const XML_Char **attr)
+			     const XML_Char **UNUSED_P(attr))
 {
     CharData *storage = (CharData *) userData;
     char buffer[100];
@@ -474,7 +634,7 @@ end_element_event_handler2(void *userData, const XML_Char *name)
 /* Regression test #3 for SF bug #653180. */
 START_TEST(test_line_and_column_numbers_inside_handlers)
 {
-    char *text =
+    const char *text =
         "\n"        /* Unix end-of-line */
         "  \r\n"    /* Windows end-of-line */
         "    \r"   /* Mac OS end-of-line */
@@ -483,7 +643,7 @@ START_TEST(test_line_and_column_numbers_inside_handlers)
         "    \n"
         "  \n"
         "";
-    char *expected =
+    const char *expected =
         " at col:0 line:1\n"
         " at col:2 line:2\n"
         " at col:4 line:3\n"
@@ -500,7 +660,7 @@ START_TEST(test_line_and_column_numbers_inside_handlers)
     XML_SetUserData(parser, &storage);
     XML_SetStartElementHandler(parser, start_element_event_handler2);
     XML_SetEndElementHandler(parser, end_element_event_handler2);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 
     CharData_CheckString(&storage, expected); 
@@ -510,12 +670,12 @@ END_TEST
 /* Regression test #4 for SF bug #653180. */
 START_TEST(test_line_number_after_error)
 {
-    char *text =
+    const char *text =
         "\n"
         "  \n"
         "  ";  /* missing  */
     XML_Size lineno;
-    if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
         fail("Expected a parse error");
 
     lineno = XML_GetCurrentLineNumber(parser);
@@ -530,12 +690,12 @@ END_TEST
 /* Regression test #5 for SF bug #653180. */
 START_TEST(test_column_number_after_error)
 {
-    char *text =
+    const char *text =
         "\n"
         "  \n"
         "  ";  /* missing  */
     XML_Size colno;
-    if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
         fail("Expected a parse error");
 
     colno = XML_GetCurrentColumnNumber(parser);
@@ -556,7 +716,7 @@ START_TEST(test_really_long_lines)
        really cheesy approach to building the input buffer, because
        this avoids writing bugs in buffer-filling code.
     */
-    char *text =
+    const char *text =
         ""
         /* 64 chars */
         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
@@ -578,7 +738,7 @@ START_TEST(test_really_long_lines)
         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
         "";
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -598,14 +758,14 @@ end_element_event_handler(void *userData, const XML_Char *name)
 
 START_TEST(test_end_element_events)
 {
-    char *text = "";
-    char *expected = "/c/b/f/d/a";
+    const char *text = "";
+    const char *expected = "/c/b/f/d/a";
     CharData storage;
 
     CharData_Init(&storage);
     XML_SetUserData(parser, &storage);
     XML_SetEndElementHandler(parser, end_element_event_handler);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
     CharData_CheckString(&storage, expected);
 }
@@ -679,8 +839,8 @@ testhelper_is_whitespace_normalized(void)
 }
 
 static void XMLCALL
-check_attr_contains_normalized_whitespace(void *userData,
-                                          const XML_Char *name,
+check_attr_contains_normalized_whitespace(void *UNUSED_P(userData),
+                                          const XML_Char *UNUSED_P(name),
                                           const XML_Char **atts)
 {
     int i;
@@ -702,7 +862,7 @@ check_attr_contains_normalized_whitespace(void *userData,
 
 START_TEST(test_attr_whitespace_normalization)
 {
-    char *text =
+    const char *text =
         "\n"
         "]>\n"
         "";
 
     XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
 
+/* Test unrecognised encoding handler */
+static void dummy_release(void *UNUSED_P(data))
+{
+}
+
+static int XMLCALL
+UnrecognisedEncodingHandler(void *UNUSED_P(data),
+                            const XML_Char *UNUSED_P(encoding),
+                            XML_Encoding *info)
+{
+    info->data = NULL;
+    info->convert = NULL;
+    info->release = dummy_release;
+    return XML_STATUS_ERROR;
+}
+
+START_TEST(test_unrecognised_encoding_internal_entity)
+{
+    const char *text =
+        "\n"
+        "]>\n"
+        "";
+
+    XML_SetUnknownEncodingHandler(parser,
+                                  UnrecognisedEncodingHandler,
+                                  NULL);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, 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_set_encoding(XML_Parser parser,
                                     const XML_Char *context,
-                                    const XML_Char *base,
-                                    const XML_Char *systemId,
-                                    const XML_Char *publicId)
+                                    const XML_Char *UNUSED_P(base),
+                                    const XML_Char *UNUSED_P(systemId),
+                                    const XML_Char *UNUSED_P(publicId))
 {
     /* This text says it's an unsupported encoding, but it's really
        UTF-8, which we tell Expat using XML_SetEncoding().
     */
-    char *text =
+    const char *text =
         ""
         "\xC3\xA9";
     XML_Parser extparser;
@@ -788,7 +979,7 @@ external_entity_loader_set_encoding(XML_Parser parser,
         fail("Could not create external entity parser.");
     if (!XML_SetEncoding(extparser, "utf-8"))
         fail("XML_SetEncoding() ignored for external entity");
-    if (  XML_Parse(extparser, text, strlen(text), XML_TRUE)
+    if (  _XML_Parse_SINGLE_BYTES(extparser, text, strlen(text), XML_TRUE)
           == XML_STATUS_ERROR) {
         xml_failure(parser);
         return 0;
@@ -798,7 +989,7 @@ external_entity_loader_set_encoding(XML_Parser parser,
 
 START_TEST(test_ext_entity_set_encoding)
 {
-    char *text =
+    const char *text =
         "\n"
         "]>\n"
@@ -814,11 +1005,11 @@ END_TEST
    read an external subset.  This was fixed in Expat 1.95.5.
 */
 START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
-    char *text =
+    const char *text =
         "\n"
         "&entity;";
 
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -837,7 +1028,7 @@ END_TEST
    read an external subset, but have been declared standalone.
 */
 START_TEST(test_wfc_undeclared_entity_standalone) {
-    char *text =
+    const char *text =
         "\n"
         "\n"
         "&entity;";
@@ -851,9 +1042,9 @@ END_TEST
 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)
+                       const XML_Char *UNUSED_P(base),
+                       const XML_Char *UNUSED_P(systemId),
+                       const XML_Char *UNUSED_P(publicId))
 {
     char *text = (char *)XML_GetUserData(parser);
     XML_Parser extparser;
@@ -861,7 +1052,7 @@ external_entity_loader(XML_Parser parser,
     extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
     if (extparser == NULL)
         fail("Could not create external entity parser.");
-    if (  XML_Parse(extparser, text, strlen(text), XML_TRUE)
+    if (  _XML_Parse_SINGLE_BYTES(extparser, text, strlen(text), XML_TRUE)
           == XML_STATUS_ERROR) {
         xml_failure(parser);
         return XML_STATUS_ERROR;
@@ -873,11 +1064,11 @@ external_entity_loader(XML_Parser parser,
    an external subset, and standalone is true.
 */
 START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
-    char *text =
+    const char *text =
         "\n"
         "\n"
         "&entity;";
-    char *foo_text =
+    char foo_text[] =
         "";
 
     XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
@@ -893,24 +1084,74 @@ END_TEST
    an external subset, and standalone is false.
 */
 START_TEST(test_wfc_undeclared_entity_with_external_subset) {
-    char *text =
+    const char *text =
         "\n"
         "\n"
         "&entity;";
-    char *foo_text =
+    char foo_text[] =
         "";
 
     XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
     XML_SetUserData(parser, foo_text);
     XML_SetExternalEntityRefHandler(parser, external_entity_loader);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+END_TEST
+
+/* Test that an error is reported if our NotStandalone handler fails */
+static int XMLCALL
+reject_not_standalone_handler(void *UNUSED_P(userData))
+{
+    return XML_STATUS_ERROR;
+}
+
+START_TEST(test_not_standalone_handler_reject)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "&entity;";
+    char foo_text[] =
+        "";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetUserData(parser, foo_text);
+    XML_SetExternalEntityRefHandler(parser, external_entity_loader);
+    XML_SetNotStandaloneHandler(parser, reject_not_standalone_handler);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+        fail("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 *UNUSED_P(userData))
+{
+    return XML_STATUS_OK;
+}
+
+START_TEST(test_not_standalone_handler_accept)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "&entity;";
+    char foo_text[] =
+        "";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetUserData(parser, foo_text);
+    XML_SetExternalEntityRefHandler(parser, external_entity_loader);
+    XML_SetNotStandaloneHandler(parser, accept_not_standalone_handler);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
 
 START_TEST(test_wfc_no_recursive_entity_refs)
 {
-    char *text =
+    const char *text =
         "\n"
         "]>\n"
@@ -925,7 +1166,7 @@ END_TEST
 /* Regression test for SF bug #483514. */
 START_TEST(test_dtd_default_handling)
 {
-    char *text =
+    const char *text =
         "\n"
         "\n"
@@ -936,15 +1177,16 @@ START_TEST(test_dtd_default_handling)
         "]>";
 
     XML_SetDefaultHandler(parser, accumulate_characters);
-    XML_SetDoctypeDeclHandler(parser,
-                              dummy_start_doctype_handler,
-                              dummy_end_doctype_handler);
+    XML_SetStartDoctypeDeclHandler(parser, dummy_start_doctype_handler);
+    XML_SetEndDoctypeDeclHandler(parser, dummy_end_doctype_handler);
     XML_SetEntityDeclHandler(parser, dummy_entity_decl_handler);
     XML_SetNotationDeclHandler(parser, dummy_notation_decl_handler);
     XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
     XML_SetAttlistDeclHandler(parser, dummy_attlist_decl_handler);
     XML_SetProcessingInstructionHandler(parser, dummy_pi_handler);
     XML_SetCommentHandler(parser, dummy_comment_handler);
+    XML_SetStartCdataSectionHandler(parser, dummy_start_cdata_handler);
+    XML_SetEndCdataSectionHandler(parser, dummy_end_cdata_handler);
     run_character_check(text, "\n\n\n\n\n\n\n");
 }
 END_TEST
@@ -957,12 +1199,12 @@ END_TEST
 */
 START_TEST(test_empty_ns_without_namespaces)
 {
-    char *text =
+    const char *text =
         "\n"
         "  \n"
         "";
 
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -973,19 +1215,19 @@ END_TEST
 */
 START_TEST(test_ns_in_attribute_default_without_namespaces)
 {
-    char *text =
+    const char *text =
         "\n"
         "      ]>\n"
         "";
 
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
 
-static char *long_character_data_text =
+static const char *long_character_data_text =
     ""
     "012345678901234567890123456789012345678901234567890123456789"
     "012345678901234567890123456789012345678901234567890123456789"
@@ -1012,8 +1254,8 @@ static char *long_character_data_text =
 static XML_Bool resumable = XML_FALSE;
 
 static void
-clearing_aborting_character_handler(void *userData,
-                                    const XML_Char *s, int len)
+clearing_aborting_character_handler(void *UNUSED_P(userData),
+                                    const XML_Char *UNUSED_P(s), int UNUSED_P(len))
 {
     XML_StopParser(parser, resumable);
     XML_SetCharacterDataHandler(parser, NULL);
@@ -1029,11 +1271,11 @@ START_TEST(test_stop_parser_between_char_data_calls)
        handler must stop the parser and clear the character data
        handler.
     */
-    char *text = long_character_data_text;
+    const char *text = long_character_data_text;
 
     XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
     resumable = XML_FALSE;
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
         xml_failure(parser);
     if (XML_GetErrorCode(parser) != XML_ERROR_ABORTED)
         xml_failure(parser);
@@ -1050,14 +1292,1103 @@ START_TEST(test_suspend_parser_between_char_data_calls)
        handler must stop the parser and clear the character data
        handler.
     */
-    char *text = long_character_data_text;
+    const char *text = long_character_data_text;
 
     XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
     resumable = XML_TRUE;
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_SUSPENDED)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_SUSPENDED)
         xml_failure(parser);
     if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
         xml_failure(parser);
+    /* Try parsing directly */
+    if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+        fail("Attempt to continue parse while suspended not faulted");
+    if (XML_GetErrorCode(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 *UNUSED_P(userData),
+                              const XML_Char *UNUSED_P(s),
+                              int UNUSED_P(len))
+{
+    XML_StopParser(parser, resumable);
+    XML_SetCharacterDataHandler(parser, NULL);
+    if (!resumable) {
+        /* Check that aborting an aborted parser is faulted */
+        if (XML_StopParser(parser, XML_FALSE) != XML_STATUS_ERROR)
+            fail("Aborting aborted parser not faulted");
+        if (XML_GetErrorCode(parser) != XML_ERROR_FINISHED)
+            xml_failure(parser);
+    } else if (abortable) {
+        /* Check that aborting a suspended parser works */
+        if (XML_StopParser(parser, XML_FALSE) == XML_STATUS_ERROR)
+            xml_failure(parser);
+    } else {
+        /* Check that suspending a suspended parser works */
+        if (XML_StopParser(parser, XML_TRUE) != XML_STATUS_ERROR)
+            fail("Suspending suspended parser not faulted");
+        if (XML_GetErrorCode(parser) != XML_ERROR_SUSPENDED)
+            xml_failure(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(parser, parser_stop_character_handler);
+    resumable = XML_FALSE;
+    abortable = XML_FALSE;
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) != XML_STATUS_ERROR)
+        fail("Failed to double-stop parser");
+
+    XML_ParserReset(parser, NULL);
+    XML_SetCharacterDataHandler(parser, parser_stop_character_handler);
+    resumable = XML_TRUE;
+    abortable = XML_FALSE;
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) != XML_STATUS_SUSPENDED)
+        fail("Failed to double-suspend parser");
+
+    XML_ParserReset(parser, NULL);
+    XML_SetCharacterDataHandler(parser, parser_stop_character_handler);
+    resumable = XML_TRUE;
+    abortable = XML_TRUE;
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) != XML_STATUS_ERROR)
+        fail("Failed to suspend-abort parser");
+}
+END_TEST
+
+
+START_TEST(test_good_cdata_ascii)
+{
+    const char *text = "Hello, world!]]>";
+    const char *expected = "Hello, world!";
+
+    CharData storage;
+    CharData_Init(&storage);
+    XML_SetUserData(parser, &storage);
+    XML_SetCharacterDataHandler(parser, accumulate_characters);
+
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_good_cdata_utf16)
+{
+    /* Test data is:
+     *   
+     *   
+     */
+    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 char *expected = "hello";
+
+    CharData storage;
+    CharData_Init(&storage);
+    XML_SetUserData(parser, &storage);
+    XML_SetCharacterDataHandler(parser, accumulate_characters);
+
+    if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_bad_cdata)
+{
+    struct CaseData {
+        const char *text;
+        enum XML_Error expectedError;
+    };
+
+    struct CaseData cases[] = {
+        {"<", XML_ERROR_UNCLOSED_TOKEN},
+        {"", XML_ERROR_INVALID_TOKEN},
+        {"", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
+        {"", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
+        {"", XML_ERROR_INVALID_TOKEN},
+        {"", XML_ERROR_INVALID_TOKEN},
+        {"", XML_ERROR_INVALID_TOKEN},
+        {"", XML_ERROR_INVALID_TOKEN},
+
+        {"", XML_ERROR_UNCLOSED_CDATA_SECTION},
+        {"", XML_ERROR_UNCLOSED_CDATA_SECTION},
+        {"", 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(
+                parser, cases[i].text, strlen(cases[i].text), XML_TRUE);
+        const enum XML_Error actualError = XML_GetErrorCode(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(parser, NULL);
+    }
+}
+END_TEST
+
+/* Test memory allocation functions */
+START_TEST(test_memory_allocation)
+{
+    char *buffer = (char *)XML_MemMalloc(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(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(parser, buffer);
+    }
+}
+END_TEST
+
+static void XMLCALL
+record_default_handler(void *userData,
+                       const XML_Char *UNUSED_P(s),
+                       int UNUSED_P(len))
+{
+    CharData_AppendString((CharData *)userData, "D");
+}
+
+static void XMLCALL
+record_cdata_handler(void *userData,
+                     const XML_Char *UNUSED_P(s),
+                     int UNUSED_P(len))
+{
+    CharData_AppendString((CharData *)userData, "C");
+    XML_DefaultCurrent(parser);
+}
+
+static void XMLCALL
+record_cdata_nodefault_handler(void *userData,
+                     const XML_Char *UNUSED_P(s),
+                     int UNUSED_P(len))
+{
+    CharData_AppendString((CharData *)userData, "c");
+}
+
+/* Test XML_DefaultCurrent() passes handling on correctly */
+START_TEST(test_default_current)
+{
+    const char *text = "hello";
+    const char *entity_text =
+        "\n"
+        "]>\n"
+        "&entity;";
+    CharData storage;
+
+    XML_SetDefaultHandler(parser, record_default_handler);
+    XML_SetCharacterDataHandler(parser, record_cdata_handler);
+    CharData_Init(&storage);
+    XML_SetUserData(parser, &storage);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    CharData_CheckString(&storage, "DCDCDCDCDCDD");
+
+    /* Again, without the defaulting */
+    XML_ParserReset(parser, NULL);
+    XML_SetDefaultHandler(parser, record_default_handler);
+    XML_SetCharacterDataHandler(parser, record_cdata_nodefault_handler);
+    CharData_Init(&storage);
+    XML_SetUserData(parser, &storage);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    CharData_CheckString(&storage, "DcccccD");
+
+    /* Now with an internal entity to complicate matters */
+    XML_ParserReset(parser, NULL);
+    XML_SetDefaultHandler(parser, record_default_handler);
+    XML_SetCharacterDataHandler(parser, record_cdata_handler);
+    CharData_Init(&storage);
+    XML_SetUserData(parser, &storage);
+    if (_XML_Parse_SINGLE_BYTES(parser, entity_text, strlen(entity_text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    /* The default handler suppresses the entity */
+    CharData_CheckString(&storage, "DDDDDDDDDDDDDDDDDDD");
+
+    /* This time, allow the entity through */
+    XML_ParserReset(parser, NULL);
+    XML_SetDefaultHandlerExpand(parser, record_default_handler);
+    XML_SetCharacterDataHandler(parser, record_cdata_handler);
+    CharData_Init(&storage);
+    XML_SetUserData(parser, &storage);
+    if (_XML_Parse_SINGLE_BYTES(parser, entity_text, strlen(entity_text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    CharData_CheckString(&storage, "DDDDDDDDDDDDDDDDDCDD");
+
+    /* Finally, without passing the cdata to the default handler */
+    XML_ParserReset(parser, NULL);
+    XML_SetDefaultHandlerExpand(parser, record_default_handler);
+    XML_SetCharacterDataHandler(parser, record_cdata_nodefault_handler);
+    CharData_Init(&storage);
+    XML_SetUserData(parser, &storage);
+    if (_XML_Parse_SINGLE_BYTES(parser, entity_text, strlen(entity_text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    CharData_CheckString(&storage, "DDDDDDDDDDDDDDDDDcD");
+}
+END_TEST
+
+/* Test DTD element parsing code paths */
+START_TEST(test_dtd_elements)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "]>\n"
+        "Wombats are go";
+
+    XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+END_TEST
+
+/* Test foreign DTD handling */
+START_TEST(test_set_foreign_dtd)
+{
+    const char *text1 =
+        "\n";
+    const char *text2 =
+        "&entity;";
+    char dtd_text[] = "";
+
+    /* Check hash salt is passed through too */
+    XML_SetHashSalt(parser, 0x12345678);
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetUserData(parser, dtd_text);
+    XML_SetExternalEntityRefHandler(parser, external_entity_loader);
+    if (XML_UseForeignDTD(parser, XML_TRUE) != XML_ERROR_NONE)
+        fail("Could not set foreign DTD");
+    if (_XML_Parse_SINGLE_BYTES(parser, text1, strlen(text1),
+                                XML_FALSE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+
+    /* Ensure that trying to set the DTD after parsing has started
+     * is faulted, even if it's the same setting.
+     */
+    if (XML_UseForeignDTD(parser, XML_TRUE) == XML_ERROR_NONE)
+        fail("Failed to reject late foreign DTD setting");
+    /* Ditto for the hash salt */
+    if (XML_SetHashSalt(parser, 0x23456789))
+        fail("Failed to reject late hash salt change");
+
+    /* Now finish the parse */
+    if (_XML_Parse_SINGLE_BYTES(parser, text2, strlen(text2),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+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 = "/local/file/name.xml";
+
+    old_base = XML_GetBase(parser);
+    if (XML_SetBase(parser, new_base) != XML_STATUS_OK)
+        fail("Unable to set base");
+    if (strcmp(XML_GetBase(parser), new_base) != 0)
+        fail("Base setting not correct");
+    if (XML_SetBase(parser, NULL) != XML_STATUS_OK)
+        fail("Unable to NULL base");
+    if (XML_GetBase(parser) != NULL)
+        fail("Base setting not nulled");
+    XML_SetBase(parser, old_base);
+}
+END_TEST
+
+/* Test attribute counts, indexing, etc */
+typedef struct attrInfo {
+    const char *name;
+    const char *value;
+} AttrInfo;
+
+typedef struct elementInfo {
+    const char *name;
+    int attr_count;
+    const 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 (!strcmp(name, info->name))
+            break;
+        info++;
+    }
+    if (info->name == NULL)
+        fail("Element not recognised");
+    /* Note attribute count is doubled */
+    count = XML_GetSpecifiedAttributeCount(parser);
+    if (info->attr_count * 2 != count) {
+        fail("Not got expected attribute count");
+        return;
+    }
+    id = XML_GetIdAttributeIndex(parser);
+    if (id == -1 && info->id_name != NULL) {
+        fail("ID not present");
+        return;
+    }
+    if (id != -1 && strcmp(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 (!strcmp(atts[0], attr->name))
+                break;
+            attr++;
+        }
+        if (attr->name == NULL) {
+            fail("Attribute not recognised");
+            return;
+        }
+        if (strcmp(atts[1], attr->value)) {
+            fail("Attribute has wrong value");
+            return;
+        }
+        atts += 2;
+    }
+}
+
+START_TEST(test_attributes)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "]>"
+        ""
+        ""
+        "";
+    AttrInfo doc_info[] = {
+        { "a",  "1" },
+        { "b",  "2" },
+        { "id", "one" },
+        { NULL, NULL }
+    };
+    AttrInfo tag_info[] = {
+        { "c",  "3" },
+        { NULL, NULL }
+    };
+    ElementInfo info[] = {
+        { "doc", 3, "id", NULL },
+        { "tag", 1, NULL, NULL },
+        { NULL, 0, NULL, NULL }
+    };
+    info[0].attributes = doc_info;
+    info[1].attributes = tag_info;
+
+    XML_SetStartElementHandler(parser, counting_start_element_handler);
+    XML_SetUserData(parser, info);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(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 =
+        "\n"
+        "\n"
+        "]>\n"
+        "&entity;";
+    XML_ParsingStatus status;
+
+    resumable = XML_TRUE;
+    XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    XML_GetParsingStatus(parser, &status);
+    if (status.parsing != XML_SUSPENDED)
+        fail("Parsing status not SUSPENDED");
+    XML_ParserReset(parser, NULL);
+    XML_GetParsingStatus(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 = "Hello\n"
+        "\n"
+        "&entity;";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetExternalEntityRefHandler(parser, external_entity_resetter);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+END_TEST
+
+
+/* Test suspending a subordinate parser */
+
+static void XMLCALL
+entity_suspending_decl_handler(void *userData,
+                               const XML_Char *UNUSED_P(name),
+                               XML_Content *model)
+{
+    XML_Parser ext_parser = (XML_Parser)userData;
+
+    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(parser, model);
+}
+
+static int XMLCALL
+external_entity_suspender(XML_Parser parser,
+                          const XML_Char *context,
+                          const XML_Char *UNUSED_P(base),
+                          const XML_Char *UNUSED_P(systemId),
+                          const XML_Char *UNUSED_P(publicId))
+{
+    const char *text = "";
+    XML_Parser ext_parser;
+
+    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, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR) {
+        xml_failure(ext_parser);
+        return XML_STATUS_ERROR;
+    }
+    return XML_STATUS_OK;
+}
+
+START_TEST(test_subordinate_suspend)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "&entity;";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetExternalEntityRefHandler(parser, external_entity_suspender);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+END_TEST
+
+
+/* Test setting an explicit encoding */
+START_TEST(test_explicit_encoding)
+{
+    const char *text1 = "Hello ";
+    const char *text2 = " World";
+
+    /* First say we are UTF-8 */
+    if (XML_SetEncoding(parser, "utf-8") != XML_STATUS_OK)
+        fail("Failed to set explicit encoding");
+    if (_XML_Parse_SINGLE_BYTES(parser, text1, strlen(text1),
+                                XML_FALSE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    /* Try to switch encodings mid-parse */
+    if (XML_SetEncoding(parser, "us-ascii") != XML_STATUS_ERROR)
+        fail("Allowed encoding change");
+    if (_XML_Parse_SINGLE_BYTES(parser, text2, strlen(text2),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    /* Try now the parse is over */
+    if (XML_SetEncoding(parser, NULL) != XML_STATUS_OK)
+        fail("Failed to unset encoding");
+}
+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 *UNUSED_P(version),
+                 const XML_Char *UNUSED_P(encoding),
+                 int standalone)
+{
+    if (userData != handler_data)
+        fail("User data (xml decl) not correctly set");
+    if (standalone != -1)
+        fail("Standalone not show as not present");
+    xdecl_count++;
+}
+
+static void XMLCALL
+param_check_skip_handler(void *userData,
+                         const XML_Char *UNUSED_P(entityName),
+                         int 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 *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 *UNUSED_P(base),
+                              const XML_Char *UNUSED_P(systemId),
+                              const XML_Char *UNUSED_P(publicId))
+{
+    const char *text =
+        "\n"
+        "";
+    XML_Parser ext_parser;
+
+    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, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR) {
+        xml_failure(parser);
+        return XML_STATUS_ERROR;
+    }
+    handler_data = parser;
+    return XML_STATUS_OK;
+}
+
+START_TEST(test_user_parameters)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "\n"
+        "&entity;";
+    const char *epilog =
+        "\n"
+        "";
+
+    comment_count = 0;
+    skip_count = 0;
+    xdecl_count = 0;
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetXmlDeclHandler(parser, xml_decl_handler);
+    XML_SetExternalEntityRefHandler(parser, external_entity_param_checker);
+    XML_SetCommentHandler(parser, data_check_comment_handler);
+    XML_SetSkippedEntityHandler(parser, param_check_skip_handler);
+    XML_UseParserAsHandlerArg(parser);
+    XML_SetUserData(parser, (void *)1);
+    handler_data = parser;
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_FALSE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    if (comment_count != 2)
+        fail("Comment handler not invoked enough times");
+    /* Ensure we can't change policy mid-parse */
+    if (XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_NEVER))
+        fail("Changed param entity parsing policy while parsing");
+    if (_XML_Parse_SINGLE_BYTES(parser, epilog, strlen(epilog),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(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.
+ */
+static int XMLCALL
+external_entity_ref_param_checker(XML_Parser parser,
+                                  const XML_Char *UNUSED_P(context),
+                                  const XML_Char *UNUSED_P(base),
+                                  const XML_Char *UNUSED_P(systemId),
+                                  const XML_Char *UNUSED_P(publicId))
+{
+    if ((void *)parser != handler_data)
+        fail("External entity ref handler parameter not correct");
+    return XML_STATUS_OK;
+}
+
+START_TEST(test_ext_entity_ref_parameter)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "&entity;";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetExternalEntityRefHandler(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(parser, (void *)text);
+    handler_data = (void *)text;
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+
+    /* Now try again with unset args */
+    XML_ParserReset(parser, NULL);
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetExternalEntityRefHandler(parser,
+                                    external_entity_ref_param_checker);
+    XML_SetExternalEntityRefHandlerArg(parser, NULL);
+    handler_data = (void *)parser;
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+END_TEST
+
+/* Test the parsing of an empty string */
+START_TEST(test_empty_parse)
+{
+    const char *text = "";
+    const char *partial = "";
+
+    if (XML_Parse(parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR)
+        fail("Parsing empty string faulted");
+    if (XML_Parse(parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
+        fail("Parsing final empty string not faulted");
+    if (XML_GetErrorCode(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(parser, NULL);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_FALSE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    if (XML_Parse(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(parser, NULL);
+    if (_XML_Parse_SINGLE_BYTES(parser, partial, strlen(partial),
+                                XML_FALSE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    if (XML_Parse(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 */
+START_TEST(test_get_buffer_1)
+{
+    const char *text =
+        "\n\n" 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 *UNUSED_P(base),
+                      const XML_Char *systemId,
+                      const XML_Char *UNUSED_P(publicId))
+{
+    const char *text1 =
+        "\n"
+        "\n"
+        "\n"
+        "%e1;\n";
+    const char *text2 =
+        "\n"
+        "\n";
+    XML_Parser ext_parser;
+
+    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 (!strcmp(systemId, "004-1.ent")) {
+        if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, 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 (!strcmp(systemId, "004-2.ent")) {
+        if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, 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");
+    }
+
+    return XML_STATUS_ERROR;
+}
+
+START_TEST(test_invalid_tag_in_dtd)
+{
+    const char *text =
+        "\n"
+        "\n";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetExternalEntityRefHandler(parser, external_entity_param);
+    expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+                   "Invalid tag IN DTD external param not rejected");
 }
 END_TEST
 
@@ -1085,6 +2416,8 @@ namespace_teardown(void)
    provided as the userData argument; the first is the expected
    element name, and the second is the expected attribute name.
 */
+static int triplet_count = 0;
+
 static void XMLCALL
 triplet_start_checker(void *userData, const XML_Char *name,
                       const XML_Char **atts)
@@ -1099,6 +2432,7 @@ triplet_start_checker(void *userData, const XML_Char *name,
         sprintf(buffer, "unexpected attribute string: '%s'", atts[0]);
         fail(buffer);
     }
+    triplet_count++;
 }
 
 /* Check that the element name passed to the end-element handler matches
@@ -1114,22 +2448,39 @@ triplet_end_checker(void *userData, const XML_Char *name)
         sprintf(buffer, "unexpected end string: '%s'", name);
         fail(buffer);
     }
+    triplet_count++;
 }
 
 START_TEST(test_return_ns_triplet)
 {
-    char *text =
+    const char *text =
         "";
-    char *elemstr[] = {
+        "       xmlns:bar='http://expat.sf.net/'>";
+    const char *epilog = "";
+    const char *elemstr[] = {
         "http://expat.sf.net/ e foo",
         "http://expat.sf.net/ a bar"
     };
     XML_SetReturnNSTriplet(parser, XML_TRUE);
     XML_SetUserData(parser, elemstr);
-    XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    XML_SetElementHandler(parser, triplet_start_checker,
+                          triplet_end_checker);
+    XML_SetNamespaceDeclHandler(parser,
+                                dummy_start_namespace_decl_handler,
+                                dummy_end_namespace_decl_handler);
+    triplet_count = 0;
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_FALSE) == XML_STATUS_ERROR)
         xml_failure(parser);
+    if (triplet_count != 1)
+        fail("triplet_start_checker not invoked");
+    /* Check that unsetting "return triplets" fails while still parsing */
+    XML_SetReturnNSTriplet(parser, XML_FALSE);
+    if (_XML_Parse_SINGLE_BYTES(parser, epilog, strlen(epilog),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+    if (triplet_count != 2)
+        fail("triplet_end_checker not invoked");
 }
 END_TEST
 
@@ -1158,14 +2509,14 @@ overwrite_end_checker(void *userData, const XML_Char *name)
 }
 
 static void
-run_ns_tagname_overwrite_test(char *text, char *result)
+run_ns_tagname_overwrite_test(const char *text, const char *result)
 {
     CharData storage;
     CharData_Init(&storage);
     XML_SetUserData(parser, &storage);
     XML_SetElementHandler(parser,
                           overwrite_start_checker, overwrite_end_checker);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
     CharData_CheckString(&storage, result);
 }
@@ -1173,12 +2524,12 @@ run_ns_tagname_overwrite_test(char *text, char *result)
 /* Regression test for SF bug #566334. */
 START_TEST(test_ns_tagname_overwrite)
 {
-    char *text =
+    const char *text =
         "\n"
         "  \n"
         "  \n"
         "";
-    char *result =
+    const char *result =
         "start http://xml.libexpat.org/ e\n"
         "start http://xml.libexpat.org/ f\n"
         "attribute http://xml.libexpat.org/ attr\n"
@@ -1194,12 +2545,12 @@ END_TEST
 /* Regression test for SF bug #566334. */
 START_TEST(test_ns_tagname_overwrite_triplet)
 {
-    char *text =
+    const char *text =
         "\n"
         "  \n"
         "  \n"
         "";
-    char *result =
+    const char *result =
         "start http://xml.libexpat.org/ e n\n"
         "start http://xml.libexpat.org/ f n\n"
         "attribute http://xml.libexpat.org/ attr n\n"
@@ -1216,8 +2567,8 @@ END_TEST
 
 /* Regression test for SF bug #620343. */
 static void XMLCALL
-start_element_fail(void *userData,
-                   const XML_Char *name, const XML_Char **atts)
+start_element_fail(void *UNUSED_P(userData),
+                   const XML_Char *UNUSED_P(name), const XML_Char **UNUSED_P(atts))
 {
     /* We should never get here. */
     fail("should never reach start_element_fail()");
@@ -1225,8 +2576,8 @@ start_element_fail(void *userData,
 
 static void XMLCALL
 start_ns_clearing_start_element(void *userData,
-                                const XML_Char *prefix,
-                                const XML_Char *uri)
+                                const XML_Char *UNUSED_P(prefix),
+                                const XML_Char *UNUSED_P(uri))
 {
     XML_SetStartElementHandler((XML_Parser) userData, NULL);
 }
@@ -1237,12 +2588,13 @@ START_TEST(test_start_ns_clears_start_element)
        syntax doesn't cause the problematic path through Expat to be
        taken.
     */
-    char *text = "";
+    const char *text = "";
 
     XML_SetStartElementHandler(parser, start_element_fail);
     XML_SetStartNamespaceDeclHandler(parser, start_ns_clearing_start_element);
+    XML_SetEndNamespaceDeclHandler(parser, dummy_end_namespace_decl_handler);
     XML_UseParserAsHandlerArg(parser);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -1251,12 +2603,12 @@ END_TEST
 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) 
+                        const XML_Char *UNUSED_P(base),
+                        const XML_Char *UNUSED_P(systemId),
+                        const XML_Char *UNUSED_P(publicId))
 {
     intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
-    char *text;
+    const char *text;
     XML_Parser p2;
 
     if (callno == 1)
@@ -1269,7 +2621,7 @@ external_entity_handler(XML_Parser parser,
 
     XML_SetUserData(parser, (void *) callno);
     p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
-    if (XML_Parse(p2, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) {
+    if (_XML_Parse_SINGLE_BYTES(p2, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) {
         xml_failure(p2);
         return 0;
     }
@@ -1279,7 +2631,7 @@ external_entity_handler(XML_Parser parser,
 
 START_TEST(test_default_ns_from_ext_subset_and_ext_ge)
 {
-    char *text =
+    const char *text =
         "\n"
         "\n"
@@ -1293,7 +2645,7 @@ START_TEST(test_default_ns_from_ext_subset_and_ext_ge)
     /* We actually need to set this handler to tickle this bug. */
     XML_SetStartElementHandler(parser, dummy_start_element);
     XML_SetUserData(parser, NULL);
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -1301,7 +2653,7 @@ END_TEST
 /* Regression test #1 for SF bug #673791. */
 START_TEST(test_ns_prefix_with_empty_uri_1)
 {
-    char *text =
+    const char *text =
         "\n"
         "  \n"
         "";
@@ -1316,7 +2668,7 @@ END_TEST
 /* Regression test #2 for SF bug #673791. */
 START_TEST(test_ns_prefix_with_empty_uri_2)
 {
-    char *text =
+    const char *text =
         "\n"
         "";
 
@@ -1329,7 +2681,7 @@ END_TEST
 /* Regression test #3 for SF bug #673791. */
 START_TEST(test_ns_prefix_with_empty_uri_3)
 {
-    char *text =
+    const char *text =
         "\n"
         "  \n"
         "  \n"
         "  \n"
         "";
-    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
         xml_failure(parser);
 }
 END_TEST
@@ -1381,7 +2733,7 @@ END_TEST
 /* Regression test for SF bug #692964: two prefixes for one namespace. */
 START_TEST(test_ns_duplicate_attrs_diff_prefixes)
 {
-    char *text =
+    const char *text =
         "";
@@ -1394,7 +2746,7 @@ END_TEST
 /* Regression test for SF bug #695401: unbound prefix. */
 START_TEST(test_ns_unbound_prefix_on_attribute)
 {
-    char *text = "";
+    const char *text = "";
     expect_failure(text,
                    XML_ERROR_UNBOUND_PREFIX,
                    "did not report unbound prefix on attribute");
@@ -1404,28 +2756,727 @@ END_TEST
 /* Regression test for SF bug #695401: unbound prefix. */
 START_TEST(test_ns_unbound_prefix_on_element)
 {
-    char *text = "";
+    const char *text = "";
     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(parser, &status);
+    if (status.parsing != XML_INITIALIZED)
+        fail("parsing status doesn't start INITIALIZED");
+    test_return_ns_triplet();
+    XML_GetParsingStatus(parser, &status);
+    if (status.parsing != XML_FINISHED)
+        fail("parsing status doesn't end FINISHED");
+    XML_ParserReset(parser, NULL);
+    XML_GetParsingStatus(parser, &status);
+    if (status.parsing != XML_INITIALIZED)
+        fail("parsing status doesn't reset to INITIALIZED");
+}
+END_TEST
+
+/* Control variable; the number of times duff_allocator() will successfully allocate */
+static unsigned int allocation_count = 0;
+
+/* Crocked allocator for allocation failure tests */
+static void *duff_allocator(size_t size)
+{
+    if (allocation_count == 0)
+        return NULL;
+    allocation_count--;
+    return malloc(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;
+
+    /* Something this simple shouldn't need more than 10 allocations */
+    for (i = 0; i < 10; i++)
+    {
+        allocation_count = i;
+        parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
+        if (parser != NULL)
+            break;
+    }
+    if (i == 0)
+        fail("Parser unexpectedly ignored failing allocator");
+    else if (i == 10)
+        fail("Parser not created with allocation count 10");
+}
+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;
+
+    /* Try several levels of allocation */
+    for (i = 0; i < 10; i++) {
+        allocation_count = i;
+        parser = XML_ParserCreate_MM("us-ascii", &memsuite, NULL);
+        if (parser != NULL)
+            break;
+    }
+    if (i == 0)
+        fail("Parser ignored failing allocator");
+    else if (i == 10)
+        fail("Parser not created with allocation count 10");
+}
+END_TEST
+
+/* Test the effects of allocation failure in simple namespace parsing.
+ * Based on test_ns_default_with_empty_uri()
+ */
+START_TEST(test_misc_alloc_ns)
+{
+    XML_Memory_Handling_Suite memsuite = { duff_allocator, realloc, free };
+    const char *text =
+        "\n"
+        "  \n"
+        "";
+    unsigned int i;
+    int repeated = 0;
+    XML_Char ns_sep[2] = { ' ', '\0' };
+
+    allocation_count = 10000;
+    parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep);
+    if (parser == NULL) {
+        fail("Parser not created");
+    } else {
+        for (i = 0; i < 10; i++) {
+            /* Repeat some tests with the same allocation count to
+             * catch cached allocations not freed by XML_ParserReset()
+             */
+            if (repeated < 2 && i == 3) {
+                i--;
+                repeated++;
+            }
+            if (repeated == 2 && i == 5) {
+                i = 3;
+                repeated++;
+            }
+            allocation_count = i;
+            if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+                break;
+            XML_ParserReset(parser, NULL);
+        }
+        if (i == 0)
+            fail("Parsing worked despite failing allocations");
+        else if (i == 10)
+            fail("Parsing failed even at allocation count 10");
+    }
+}
+END_TEST
+
+/* Test XML_ParseBuffer interface with namespace and a dicky allocator */
+START_TEST(test_misc_alloc_ns_parse_buffer)
+{
+    XML_Memory_Handling_Suite memsuite = { duff_allocator, realloc, free };
+    XML_Char ns_sep[2] = { ' ', '\0' };
+    const char *text = "Hello";
+    void *buffer;
+
+    /* Make sure the basic parser is allocated */
+    allocation_count = 10000;
+    parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep);
+    if (parser == NULL)
+        fail("Parser not created");
+
+    /* Try a parse before the start of the world */
+    /* (Exercises new code path) */
+    allocation_count = 0;
+    if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_ERROR)
+        fail("Pre-init XML_ParseBuffer not faulted");
+    if (XML_GetErrorCode(parser) != XML_ERROR_NO_MEMORY)
+        fail("Pre-init XML_ParseBuffer faulted for wrong reason");
+
+    /* Now with actual memory allocation */
+    allocation_count = 10000;
+    if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_OK)
+        xml_failure(parser);
+
+    /* Check that resuming an unsuspended parser is faulted */
+    if (XML_ResumeParser(parser) != XML_STATUS_ERROR)
+        fail("Resuming unsuspended parser not faulted");
+    if (XML_GetErrorCode(parser) != XML_ERROR_NOT_SUSPENDED)
+        xml_failure(parser);
+
+    /* Get the parser into suspended state */
+    XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
+    resumable = XML_TRUE;
+    buffer = XML_GetBuffer(parser, strlen(text));
+    if (buffer == NULL)
+        fail("Could not acquire parse buffer");
+    memcpy(buffer, text, strlen(text));
+    if (XML_ParseBuffer(parser, strlen(text),
+                        XML_TRUE) != XML_STATUS_SUSPENDED)
+        xml_failure(parser);
+    if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
+        xml_failure(parser);
+    if (XML_ParseBuffer(parser, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+        fail("Suspended XML_ParseBuffer not faulted");
+    if (XML_GetErrorCode(parser) != XML_ERROR_SUSPENDED)
+        xml_failure(parser);
+    if (XML_GetBuffer(parser, strlen(text)) != NULL)
+        fail("Suspended XML_GetBuffer not faulted");
+
+    /* Get it going again and complete the world */
+    XML_SetCharacterDataHandler(parser, NULL);
+    if (XML_ResumeParser(parser) != XML_STATUS_OK)
+        xml_failure(parser);
+    if (XML_ParseBuffer(parser, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+        fail("Post-finishing XML_ParseBuffer not faulted");
+    if (XML_GetErrorCode(parser) != XML_ERROR_FINISHED)
+        xml_failure(parser);
+    if (XML_GetBuffer(parser, strlen(text)) != NULL)
+        fail("Post-finishing XML_GetBuffer not faulted");
+}
+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 */
+START_TEST(test_misc_version)
+{
+    XML_Expat_Version version_struct = XML_ExpatVersionInfo();
+    const XML_LChar *version_text = XML_ExpatVersion();
+    long value;
+    const char *p;
+    char *endp;
+
+    if (version_text == NULL)
+        fail("Could not obtain version text");
+    for (p = version_text; *p != '\0'; p++)
+        if (isdigit(*p))
+            break;
+    if (*p == '\0')
+        fail("No numbers in version text");
+    value = strtoul(p, &endp, 10);
+    if (*endp != '.')
+        fail("Major version conversion from text failed");
+    if (value != version_struct.major)
+        fail("Major version mismatch");
+    p = endp + 1;
+    value = strtoul(p, &endp, 10);
+    if (*endp != '.')
+        fail("Minor version conversion from text failed");
+    if (value != version_struct.minor)
+        fail("Minor version mismatch");
+    p = endp + 1;
+    value = strtoul(p, &endp, 10);
+    if (*endp != '\0')
+        fail("Micro version conversion from text failed");
+    if (value != version_struct.micro)
+        fail("Micro version mismatch");
+}
+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 = "";
+    XML_Memory_Handling_Suite memsuite = {
+        tracking_malloc,
+        tracking_realloc,
+        tracking_free
+    };
+
+    parser = XML_ParserCreate_MM("UTF-8", &memsuite, "\n");
+    expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
+                   "Unbound prefixes not found");
+    XML_ParserFree(parser);
+    /* Prevent the teardown trying to double free */
+    parser = NULL;
+
+    if (!tracking_report())
+        fail("Memory leak found");
+}
+END_TEST
+
+
+static void
+alloc_setup(void)
+{
+    XML_Memory_Handling_Suite memsuite = { duff_allocator, realloc, free };
+
+    /* Ensure the parser creation will go through */
+    allocation_count = 10000;
+    parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
+    if (parser == NULL)
+        fail("Parser not created");
+}
+
+static void
+alloc_teardown(void)
+{
+    basic_teardown();
+}
+
+static int XMLCALL
+external_entity_duff_loader(XML_Parser parser,
+                            const XML_Char *context,
+                            const XML_Char *UNUSED_P(base),
+                            const XML_Char *UNUSED_P(systemId),
+                            const XML_Char *UNUSED_P(publicId))
+{
+    XML_Parser new_parser;
+    unsigned int i;
+
+    /* Try a few different allocation levels */
+    for (i = 0; i < 10; 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 == 10)
+        fail("Extern parser not created with allocation count 10");
+
+    /* Make sure other random allocation doesn't now fail */
+    allocation_count = 10000;
+
+    /* 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 =
+        "\n"
+        "\n"
+        "&entity;";
+    char foo_text[] =
+        "";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetUserData(parser, foo_text);
+    XML_SetExternalEntityRefHandler(parser,
+                                    external_entity_duff_loader);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR) {
+        fail("External parser allocator returned success incorrectly");
+    }
+}
+END_TEST
+
+static int XMLCALL
+external_entity_null_loader(XML_Parser UNUSED_P(parser),
+                            const XML_Char *UNUSED_P(context),
+                            const XML_Char *UNUSED_P(base),
+                            const XML_Char *UNUSED_P(systemId),
+                            const XML_Char *UNUSED_P(publicId))
+{
+    return XML_STATUS_OK;
+}
+
+/* More external parser memory allocation testing */
+START_TEST(test_alloc_run_external_parser)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "&entity;";
+    char foo_text[] =
+        "";
+    unsigned int i;
+
+    for (i = 0; i < 10; i++) {
+        XML_SetParamEntityParsing(parser,
+                                  XML_PARAM_ENTITY_PARSING_ALWAYS);
+        XML_SetUserData(parser, foo_text);
+        XML_SetExternalEntityRefHandler(parser,
+                                        external_entity_null_loader);
+        allocation_count = i;
+        if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+            break;
+        /* Re-use the parser */
+        XML_ParserReset(parser, NULL);
+    }
+    if (i == 0)
+        fail("Parsing ignored failing allocator");
+    else if (i == 10)
+        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 *UNUSED_P(base),
+                            const XML_Char *UNUSED_P(systemId),
+                            const XML_Char *UNUSED_P(publicId))
+{
+    intptr_t callno = (intptr_t)XML_GetUserData(parser);
+    const char *text;
+    XML_Parser new_parser;
+    int i;
+
+    if (callno == 0) {
+        /* First time through, check how many calls to malloc occur */
+        text = ("\n"
+                "\n"
+                "\n");
+        allocation_count = 10000;
+        new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+        if (new_parser == NULL) {
+            fail("Unable to allocate first external parser");
+            return 0;
+        }
+        /* Stash the number of calls in the user data */
+        XML_SetUserData(parser, (void *)(intptr_t)(10000 - allocation_count));
+    } else {
+        text = (""
+                "");
+        /* Try at varying levels to exercise more code paths */
+        for (i = 0; i < 20; 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 0;
+        }
+        else if (i == 20) {
+            fail("Second external parser not created");
+            return 0;
+        }
+    }
+
+    allocation_count = 10000;
+    if (_XML_Parse_SINGLE_BYTES(new_parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) {
+        xml_failure(new_parser);
+        return 0;
+    }
+    XML_ParserFree(new_parser);
+    return 1;
+}
+
+/* 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 =
+        "\n"
+        "\n"
+        "]>\n"
+        "\n"
+        "&en;\n"
+        "";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetExternalEntityRefHandler(parser,
+                                    external_entity_dbl_handler);
+    XML_SetUserData(parser, NULL);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+END_TEST
+
+
+static int XMLCALL
+external_entity_dbl_handler_2(XML_Parser parser,
+                              const XML_Char *context,
+                              const XML_Char *UNUSED_P(base),
+                              const XML_Char *UNUSED_P(systemId),
+                              const XML_Char *UNUSED_P(publicId))
+{
+    intptr_t callno = (intptr_t)XML_GetUserData(parser);
+    const char *text;
+    XML_Parser new_parser;
+    int i;
+
+    if (callno == 0) {
+        /* Try different allocation levels for whole exercise */
+        text = ("\n"
+                "\n"
+                "\n");
+        XML_SetUserData(parser, (void *)(intptr_t)1);
+        for (i = 0; i < 20; i++) {
+            allocation_count = i;
+            new_parser = XML_ExternalEntityParserCreate(parser,
+                                                        context,
+                                                        NULL);
+            if (new_parser == NULL)
+                continue;
+            if (_XML_Parse_SINGLE_BYTES(new_parser, text, strlen(text),
+                                        XML_TRUE) != XML_STATUS_ERROR)
+                break;
+            XML_ParserFree(new_parser);
+        }
+
+        /* Ensure future allocations will be well */
+        allocation_count = 10000;
+        if (i == 0) {
+            fail("first external parser unexpectedly created");
+            XML_ParserFree(new_parser);
+            return 0;
+        }
+        else if (i == 20) {
+            fail("first external parser not allocated with count 20");
+            return 0;
+        }
+    } else {
+        /* Just run through once */
+        text = (""
+                "");
+        allocation_count = 10000;
+        new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+        if (new_parser == NULL) {
+            fail("Unable to create second external parser");
+            return 0;
+        }
+        if (_XML_Parse_SINGLE_BYTES(new_parser, text, strlen(text),
+                                    XML_TRUE) == XML_STATUS_ERROR) {
+            xml_failure(new_parser);
+            XML_ParserFree(new_parser);
+            return 0;
+        }
+    }
+    XML_ParserFree(new_parser);
+    return 1;
+}
+
+/* Test more external entity allocation failure paths */
+START_TEST(test_alloc_external_entity)
+{
+    const char *text =
+        "\n"
+        "\n"
+        "]>\n"
+        "\n"
+        "&en;\n"
+        "";
+
+    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+    XML_SetExternalEntityRefHandler(parser,
+                                    external_entity_dbl_handler_2);
+    XML_SetUserData(parser, NULL);
+    if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                XML_TRUE) == XML_STATUS_ERROR)
+        xml_failure(parser);
+}
+END_TEST
+
+
+static int XMLCALL
+unknown_released_encoding_handler(void *UNUSED_P(data),
+                                  const XML_Char *encoding,
+                                  XML_Encoding *info)
+{
+    if (!strcmp(encoding, "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 =
+        "\n"
+        "]>\n"
+        "";
+    unsigned int i;
+    int repeated = 0;
+
+    for (i = 0; i < 10; i++) {
+        /* Again, repeat some counts to account for caching */
+        if (repeated < 2 && i == 2) {
+            i--;
+            repeated++;
+        }
+        XML_SetUnknownEncodingHandler(parser,
+                                      unknown_released_encoding_handler,
+                                      NULL);
+        allocation_count = i;
+        if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
+            break;
+        XML_ParserReset(parser, NULL);
+    }
+    if (i == 0)
+        fail("Internal entity worked despite failing allocations");
+    else if (i == 10)
+        fail("Internal entity failed at allocation count 10");
+}
+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 =
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "]>";
+    const char *expected = "\n\n\n\n\n\n\n";
+    CharData storage;
+    int i;
+    int repeat = 0;
+
+    for (i = 0; i < 10; i++) {
+        /* Repeat some counts to catch cached allocations */
+        if ((repeat < 4 && i == 2) ||
+            (repeat == 4 && i == 3)) {
+            i--;
+            repeat++;
+        }
+        allocation_count = i;
+        XML_SetDefaultHandler(parser, accumulate_characters);
+        XML_SetDoctypeDeclHandler(parser,
+                                  dummy_start_doctype_handler,
+                                  dummy_end_doctype_handler);
+        XML_SetEntityDeclHandler(parser, dummy_entity_decl_handler);
+        XML_SetNotationDeclHandler(parser, dummy_notation_decl_handler);
+        XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
+        XML_SetAttlistDeclHandler(parser, dummy_attlist_decl_handler);
+        XML_SetProcessingInstructionHandler(parser, dummy_pi_handler);
+        XML_SetCommentHandler(parser, dummy_comment_handler);
+        XML_SetCdataSectionHandler(parser,
+                                   dummy_start_cdata_handler,
+                                   dummy_end_cdata_handler);
+        XML_SetUnparsedEntityDeclHandler(
+            parser,
+            dummy_unparsed_entity_decl_handler);
+        CharData_Init(&storage);
+        XML_SetUserData(parser, &storage);
+        XML_SetCharacterDataHandler(parser, accumulate_characters);
+        if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text),
+                                    XML_TRUE) != XML_STATUS_ERROR)
+            break;
+        XML_ParserReset(parser, NULL);
+    }
+    if (i == 0) {
+        fail("Default DTD parsed despite allocation failures");
+    } else if (i == 10) {
+        fail("Default DTD not parsed with alloc count 10");
+    } else {
+        CharData_CheckXMLChars(&storage, expected);
+    }
+}
+END_TEST
+
+/* Test robustness of XML_SetEncoding() with a failing allocator */
+START_TEST(test_alloc_explicit_encoding)
+{
+    int i;
+
+    for (i = 0; i < 5; i++) {
+        allocation_count = i;
+        if (XML_SetEncoding(parser, "us-ascii") == XML_STATUS_OK)
+            break;
+    }
+    if (i == 0)
+        fail("Encoding set despite failing allocator");
+    else if (i == 5)
+        fail("Encoding not set at allocation count 5");
+}
+END_TEST
+
+/* Test robustness of XML_SetBase against a failing allocator */
+START_TEST(test_alloc_set_base)
+{
+    const XML_Char *new_base = "/local/file/name.xml";
+    int i;
+
+    for (i = 0; i < 5; i++) {
+        allocation_count = i;
+        if (XML_SetBase(parser, new_base) == XML_STATUS_OK)
+            break;
+    }
+    if (i == 0)
+        fail("Base set despite failing allocator");
+    else if (i == 5)
+        fail("Base not set with allocation count 5");
+}
+END_TEST
+
+
 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");
 
     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_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_latin1_umlauts);
@@ -1447,11 +3498,14 @@ make_suite(void)
     tcase_add_test(tc_basic, test_attr_whitespace_normalization);
     tcase_add_test(tc_basic, test_xmldecl_misplaced);
     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_wfc_no_recursive_entity_refs);
@@ -1461,6 +3515,31 @@ make_suite(void)
     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_bad_cdata);
+    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_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_subordinate_reset);
+    tcase_add_test(tc_basic, test_subordinate_suspend);
+    tcase_add_test(tc_basic, test_explicit_encoding);
+    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_invalid_tag_in_dtd);
 
     suite_add_tcase(s, tc_namespace);
     tcase_add_checked_fixture(tc_namespace,
@@ -1478,6 +3557,29 @@ make_suite(void)
     tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
     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);
+
+    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_alloc_ns);
+    tcase_add_test(tc_misc, test_misc_null_parser);
+    tcase_add_test(tc_misc, test_misc_alloc_ns_parse_buffer);
+    tcase_add_test(tc_misc, test_misc_error_string);
+    tcase_add_test(tc_misc, test_misc_version);
+    tcase_add_test(tc_misc, test_misc_attribute_leak);
+
+    suite_add_tcase(s, tc_alloc);
+    tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
+    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_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);
 
     return s;
 }
diff --git a/lib-src/expat/tests/xmltest.sh b/lib-src/expat/tests/xmltest.sh
index 793a5cc28..e50093285 100755
--- a/lib-src/expat/tests/xmltest.sh
+++ b/lib-src/expat/tests/xmltest.sh
@@ -1,4 +1,4 @@
-#! /bin/sh
+#! /usr/bin/env bash
 
 #   EXPAT TEST SCRIPT FOR W3C XML TEST SUITE
 
@@ -20,12 +20,14 @@
 # produced by xmlwf conforms to an older definition of canonical XML
 # and does not generate notation declarations.
 
+shopt -s nullglob
+
 MYDIR="`dirname \"$0\"`"
 cd "$MYDIR"
 MYDIR="`pwd`"
-XMLWF="`dirname \"$MYDIR\"`/xmlwf/xmlwf"
+XMLWF="${1:-`dirname \"$MYDIR\"`/xmlwf/xmlwf}"
 # XMLWF=/usr/local/bin/xmlwf
-TS="$MYDIR/XML-Test-Suite"
+TS="$MYDIR"
 # OUTPUT must terminate with the directory separator.
 OUTPUT="$TS/out/"
 # OUTPUT=/home/tmp/xml-testsuite-out/
@@ -96,11 +98,12 @@ for xmldir in ibm/valid/P* \
               sun/invalid ; do
   cd "$TS/xmlconf/$xmldir"
   mkdir -p "$OUTPUT$xmldir"
-  for xmlfile in *.xml ; do
+  for xmlfile in $(ls -1 *.xml | sort -d) ; do
+      [[ -f "$xmlfile" ]] || continue
       RunXmlwfWF "$xmlfile" "$xmldir/"
       UpdateStatus $?
   done
-  rm outfile
+  rm -f outfile
 done
 
 cd "$TS/xmlconf/oasis"
diff --git a/lib-src/expat/win32/MANIFEST.txt b/lib-src/expat/win32/MANIFEST.txt
index b7cd39543..22b61d198 100644
--- a/lib-src/expat/win32/MANIFEST.txt
+++ b/lib-src/expat/win32/MANIFEST.txt
@@ -22,6 +22,4 @@ directory you specified to the installer.
                       formedness checker, and a couple of small sample
                       applications.
 
-  \Source\bcb5\  Project files for Borland C++ Builder 5 and BCC 5.5.
-
 
diff --git a/lib-src/expat/win32/README.txt b/lib-src/expat/win32/README.txt
index e3702ae62..462c49b75 100644
--- a/lib-src/expat/win32/README.txt
+++ b/lib-src/expat/win32/README.txt
@@ -1,21 +1,16 @@
 
-Expat can be built on Windows in three ways: 
-  using MS Visual C++ (6.0 or .NET), Borland C++ Builder 5 or Cygwin.
+Expat can be built on Windows in two ways:
+  using MS Visual Studio .NET or Cygwin.
 
 * Cygwin:
   This follows the Unix build procedures.
 
-* C++ Builder 5:
-  Possible with make files in the BCB5 subdirectory.
-  Details can be found in the ReadMe file located there.
-
-* MS Visual C++ 6:
-  Based on the workspace file expat.dsw. The related project
-  files (.dsp) are located in the lib subdirectory.
-
-* MS Visual Studio .NET 2002, 2003, 2005, 2008, 2010:
-  The VC++ 6 workspace file (expat.dsw) and project files (.dsp)
-  can be opened and imported in VS.NET without problems.
+* MS Visual Studio 2013, 2015 and 2017:
+  A solution file for Visual Studio 2013 is provided: expat.sln.
+  The associated project files (*.vcxproj) reside in the appropriate
+  project directories. This solution file can be opened in VS 2015 or VS 2017
+  and should be upgraded automatically if VS 2013 is not also installed.
+  Note: Tests have their own solution files.
 
 * All MS C/C++ compilers:
   The output for all projects will be generated in the win32\bin
diff --git a/lib-src/expat/win32/expat.iss b/lib-src/expat/win32/expat.iss
index de5b6efdd..2943d3e13 100644
--- a/lib-src/expat/win32/expat.iss
+++ b/lib-src/expat/win32/expat.iss
@@ -7,17 +7,17 @@
 [Setup]
 AppName=Expat
 AppId=expat
-AppVersion=2.1.0
-AppVerName=Expat 2.1.0
-AppCopyright=Copyright © 1998-2012 Thai Open Source Software Center, Clark Cooper, and the Expat maintainers
+AppVersion=2.2.1
+AppVerName=Expat 2.2.1
+AppCopyright=Copyright � 1998-2017 Thai Open Source Software Center, Clark Cooper, and the Expat maintainers
 AppPublisher=The Expat Developers
 AppPublisherURL=http://www.libexpat.org/
 AppSupportURL=http://www.libexpat.org/
 AppUpdatesURL=http://www.libexpat.org/
-UninstallDisplayName=Expat XML Parser 2.1.0
-VersionInfoVersion=2.1.0
+UninstallDisplayName=Expat XML Parser 2.2.1
+VersionInfoVersion=2.2.1
 
-DefaultDirName={pf}\Expat 2.1.0
+DefaultDirName={pf}\Expat 2.2.1
 UninstallFilesDir={app}\Uninstall
 
 Compression=lzma
@@ -32,6 +32,7 @@ DisableReadyPage=yes
 [Files]
 Flags: ignoreversion; Source: win32\bin\Release\xmlwf.exe;  DestDir: "{app}\Bin"
 Flags: ignoreversion; Source: win32\MANIFEST.txt;           DestDir: "{app}"
+Flags: ignoreversion; Source: AUTHORS;                      DestDir: "{app}"; DestName: AUTHORS.txt
 Flags: ignoreversion; Source: Changes;                      DestDir: "{app}"; DestName: Changes.txt
 Flags: ignoreversion; Source: COPYING;                      DestDir: "{app}"; DestName: COPYING.txt
 Flags: ignoreversion; Source: README;                       DestDir: "{app}"; DestName: README.txt
@@ -40,29 +41,31 @@ Flags: ignoreversion; Source: doc\*.css;                    DestDir: "{app}\Doc"
 Flags: ignoreversion; Source: doc\*.png;                    DestDir: "{app}\Doc"
 Flags: ignoreversion; Source: win32\bin\Release\*.dll;      DestDir: "{app}\Bin"
 Flags: ignoreversion; Source: win32\bin\Release\*.lib;      DestDir: "{app}\Bin"
-Flags: ignoreversion; Source: expat.dsw;                    DestDir: "{app}\Source"
+Flags: ignoreversion; Source: expat.sln;                    DestDir: "{app}\Source"
 Flags: ignoreversion; Source: win32\README.txt;             DestDir: "{app}\Source"
-Flags: ignoreversion; Source: bcb5\*.bp*;                   DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.mak;                   DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.def;                   DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.txt;                   DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.bat;                   DestDir: "{app}\Source\bcb5"
 Flags: ignoreversion; Source: lib\*.c;                      DestDir: "{app}\Source\lib"
 Flags: ignoreversion; Source: lib\*.h;                      DestDir: "{app}\Source\lib"
 Flags: ignoreversion; Source: lib\*.def;                    DestDir: "{app}\Source\lib"
-Flags: ignoreversion; Source: lib\*.dsp;                    DestDir: "{app}\Source\lib"
+Flags: ignoreversion; Source: lib\*.vcxproj;                DestDir: "{app}\Source\lib"
+Flags: ignoreversion; Source: lib\*.vcxproj.filters;        DestDir: "{app}\Source\lib"
 Flags: ignoreversion; Source: examples\*.c;                 DestDir: "{app}\Source\examples"
-Flags: ignoreversion; Source: examples\*.dsp;               DestDir: "{app}\Source\examples"
+Flags: ignoreversion; Source: examples\*.vcxproj;           DestDir: "{app}\Source\examples"
+Flags: ignoreversion; Source: examples\*.vcxproj.filters;   DestDir: "{app}\Source\examples"
 Flags: ignoreversion; Source: tests\*.c;                    DestDir: "{app}\Source\tests"
 Flags: ignoreversion; Source: tests\*.cpp;                  DestDir: "{app}\Source\tests"
 Flags: ignoreversion; Source: tests\*.h;                    DestDir: "{app}\Source\tests"
+Flags: ignoreversion; Source: tests\*.sln;                  DestDir: "{app}\Source\tests"
+Flags: ignoreversion; Source: tests\*.vcxproj;              DestDir: "{app}\Source\tests"
+Flags: ignoreversion; Source: tests\*.vcxproj.filters;      DestDir: "{app}\Source\tests"
 Flags: ignoreversion; Source: tests\README.txt;             DestDir: "{app}\Source\tests"
 Flags: ignoreversion; Source: tests\benchmark\*.c;          DestDir: "{app}\Source\tests\benchmark"
-Flags: ignoreversion; Source: tests\benchmark\*.ds*;        DestDir: "{app}\Source\tests\benchmark"
+Flags: ignoreversion; Source: tests\benchmark\*.sln;        DestDir: "{app}\Source\tests\benchmark"
+Flags: ignoreversion; Source: tests\benchmark\*.vcxproj;    DestDir: "{app}\Source\tests\benchmark"
 Flags: ignoreversion; Source: tests\benchmark\README.txt;   DestDir: "{app}\Source\tests\benchmark"
 Flags: ignoreversion; Source: xmlwf\*.c*;                   DestDir: "{app}\Source\xmlwf"
 Flags: ignoreversion; Source: xmlwf\*.h;                    DestDir: "{app}\Source\xmlwf"
-Flags: ignoreversion; Source: xmlwf\*.dsp;                  DestDir: "{app}\Source\xmlwf"
+Flags: ignoreversion; Source: xmlwf\*.vcxproj;              DestDir: "{app}\Source\xmlwf"
+Flags: ignoreversion; Source: xmlwf\*.vcxproj.filters;      DestDir: "{app}\Source\xmlwf"
 
 [Messages]
 WelcomeLabel1=Welcome to the Expat XML Parser Setup Wizard
diff --git a/lib-src/expat/xmlwf/codepage.c b/lib-src/expat/xmlwf/codepage.c
index 57e48ff2d..7d78f21e6 100755
--- a/lib-src/expat/xmlwf/codepage.c
+++ b/lib-src/expat/xmlwf/codepage.c
@@ -3,8 +3,9 @@
 */
 
 #include "codepage.h"
+#include "internal.h"  /* for UNUSED_P only */
 
-#if (defined(WIN32) || (defined(__WATCOMC__) && defined(__NT__)))
+#if defined(_WIN32)
 #define STRICT 1
 #define WIN32_LEAN_AND_MEAN 1
 
@@ -51,18 +52,18 @@ codepageConvert(int cp, const char *p)
   return -1;
 }
 
-#else /* not WIN32 */
+#else /* not _WIN32 */
 
 int
-codepageMap(int cp, int *map)
+codepageMap(int UNUSED_P(cp), int *UNUSED_P(map))
 {
   return 0;
 }
 
 int
-codepageConvert(int cp, const char *p)
+codepageConvert(int UNUSED_P(cp), const char *UNUSED_P(p))
 {
   return -1;
 }
 
-#endif /* not WIN32 */
+#endif /* not _WIN32 */
diff --git a/lib-src/expat/xmlwf/filemap.h b/lib-src/expat/xmlwf/filemap.h
index 814edec25..db83d1a03 100755
--- a/lib-src/expat/xmlwf/filemap.h
+++ b/lib-src/expat/xmlwf/filemap.h
@@ -2,8 +2,20 @@
    See the file COPYING for copying permission.
 */
 
+#include   /* INT_MAX */
 #include 
 
+
+/* The following limit (for XML_Parse's int len) derives from
+ * this loop in xmparse.c:
+ *
+ *    do {
+ *      bufferSize = (int) (2U * (unsigned) bufferSize);
+ *    } while (bufferSize < neededSize && bufferSize > 0);
+ */
+#define XML_MAX_CHUNK_LEN  (INT_MAX / 2 + 1)
+
+
 #ifdef XML_UNICODE
 int filemap(const wchar_t *name,
             void (*processor)(const void *, size_t,
diff --git a/lib-src/expat/xmlwf/readfilemap.c b/lib-src/expat/xmlwf/readfilemap.c
index bd32b9341..023998ef6 100755
--- a/lib-src/expat/xmlwf/readfilemap.c
+++ b/lib-src/expat/xmlwf/readfilemap.c
@@ -8,16 +8,9 @@
 #include 
 #include 
 
-#ifdef __WATCOMC__
-#ifndef __LINUX__
-#include 
-#else
-#include 
-#endif
-#endif
-
-#ifdef __BEOS__
-#include 
+/* Functions close(2) and read(2) */
+#if !defined(_WIN32) && !defined(_WIN64)
+# include 
 #endif
 
 #ifndef S_ISREG
@@ -66,6 +59,11 @@ filemap(const char *name,
     close(fd);
     return 0;
   }
+  if (sb.st_size > XML_MAX_CHUNK_LEN) {
+    close(fd);
+    return 2;  /* Cannot be passed to XML_Parse in one go */
+  }
+
   nbytes = sb.st_size;
   /* malloc will return NULL with nbytes == 0, handle files with size 0 */
   if (nbytes == 0) {
diff --git a/lib-src/expat/xmlwf/unixfilemap.c b/lib-src/expat/xmlwf/unixfilemap.c
index 93adce32e..8783134c6 100755
--- a/lib-src/expat/xmlwf/unixfilemap.c
+++ b/lib-src/expat/xmlwf/unixfilemap.c
@@ -42,6 +42,10 @@ filemap(const char *name,
     fprintf(stderr, "%s: not a regular file\n", name);
     return 0;
   }
+  if (sb.st_size > XML_MAX_CHUNK_LEN) {
+    close(fd);
+    return 2;  /* Cannot be passed to XML_Parse in one go */
+  }
 
   nbytes = sb.st_size;
   /* mmap fails for zero length files */
@@ -51,7 +55,7 @@ filemap(const char *name,
     close(fd);
     return 1;
   }
-  p = (void *)mmap((caddr_t)0, (size_t)nbytes, PROT_READ,
+  p = (void *)mmap((void *)0, (size_t)nbytes, PROT_READ,
                    MAP_FILE|MAP_PRIVATE, fd, (off_t)0);
   if (p == (void *)-1) {
     perror(name);
@@ -59,7 +63,7 @@ filemap(const char *name,
     return 0;
   }
   processor(p, nbytes, name, arg);
-  munmap((caddr_t)p, nbytes);
+  munmap((void *)p, nbytes);
   close(fd);
   return 1;
 }
diff --git a/lib-src/expat/xmlwf/win32filemap.c b/lib-src/expat/xmlwf/win32filemap.c
index 41dc35b61..6be459622 100755
--- a/lib-src/expat/xmlwf/win32filemap.c
+++ b/lib-src/expat/xmlwf/win32filemap.c
@@ -42,11 +42,12 @@ filemap(const TCHAR *name,
   size = GetFileSize(f, &sizeHi);
   if (size == (DWORD)-1) {
     win32perror(name);
+    CloseHandle(f);
     return 0;
   }
-  if (sizeHi) {
-    _ftprintf(stderr, _T("%s: bigger than 2Gb\n"), name);
-    return 0;
+  if (sizeHi || (size > XML_MAX_CHUNK_LEN)) {
+    CloseHandle(f);
+    return 2;  /* Cannot be passed to XML_Parse in one go */
   }
   /* CreateFileMapping barfs on zero length files */
   if (size == 0) {
diff --git a/lib-src/expat/xmlwf/xmlfile.c b/lib-src/expat/xmlwf/xmlfile.c
index 99eeeaaef..6473c6e19 100755
--- a/lib-src/expat/xmlwf/xmlfile.c
+++ b/lib-src/expat/xmlwf/xmlfile.c
@@ -8,31 +8,22 @@
 #include 
 #include 
 
-#ifdef COMPILED_FROM_DSP
+#ifdef _WIN32
 #include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
 #elif defined(HAVE_EXPAT_CONFIG_H)
 #include 
-#endif /* ndef COMPILED_FROM_DSP */
+#endif /* ndef _WIN32 */
 
 #include "expat.h"
+#include "internal.h"  /* for UNUSED_P only */
 #include "xmlfile.h"
 #include "xmltchar.h"
 #include "filemap.h"
 
-#if (defined(_MSC_VER) || (defined(__WATCOMC__) && !defined(__LINUX__)))
+#if defined(_MSC_VER)
 #include 
 #endif
 
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include 
-#endif
-
 #ifdef HAVE_UNISTD_H
 #include 
 #endif
@@ -57,6 +48,9 @@ typedef struct {
   int *retPtr;
 } PROCESS_ARGS;
 
+static int
+processStream(const XML_Char *filename, XML_Parser parser);
+
 static void
 reportError(XML_Parser parser, const XML_Char *filename)
 {
@@ -87,7 +81,7 @@ processFile(const void *data, size_t size,
     *retPtr = 1;
 }
 
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
 
 static int
 isAsciiLetter(XML_Char c)
@@ -95,7 +89,7 @@ isAsciiLetter(XML_Char c)
   return (T('a') <= c && c <= T('z')) || (T('A') <= c && c <= T('Z'));
 }
 
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
 static const XML_Char *
 resolveSystemId(const XML_Char *base, const XML_Char *systemId,
@@ -105,7 +99,7 @@ resolveSystemId(const XML_Char *base, const XML_Char *systemId,
   *toFree = 0;
   if (!base
       || *systemId == T('/')
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
       || *systemId == T('\\')
       || (isAsciiLetter(systemId[0]) && systemId[1] == T(':'))
 #endif
@@ -119,7 +113,7 @@ resolveSystemId(const XML_Char *base, const XML_Char *systemId,
   s = *toFree;
   if (tcsrchr(s, T('/')))
     s = tcsrchr(s, T('/')) + 1;
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
   if (tcsrchr(s, T('\\')))
     s = tcsrchr(s, T('\\')) + 1;
 #endif
@@ -132,19 +126,29 @@ externalEntityRefFilemap(XML_Parser parser,
                          const XML_Char *context,
                          const XML_Char *base,
                          const XML_Char *systemId,
-                         const XML_Char *publicId)
+                         const XML_Char *UNUSED_P(publicId))
 {
   int result;
   XML_Char *s;
   const XML_Char *filename;
   XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
+  int filemapRes;
   PROCESS_ARGS args;
   args.retPtr = &result;
   args.parser = entParser;
   filename = resolveSystemId(base, systemId, &s);
   XML_SetBase(entParser, filename);
-  if (!filemap(filename, processFile, &args))
+  filemapRes = filemap(filename, processFile, &args);
+  switch (filemapRes) {
+  case 0:
     result = 0;
+    break;
+  case 2:
+    ftprintf(stderr, T("%s: file too large for memory-mapping")
+        T(", switching to streaming\n"), filename);
+    result = processStream(filename, entParser);
+    break;
+  }
   free(s);
   XML_ParserFree(entParser);
   return result;
@@ -200,7 +204,7 @@ externalEntityRefStream(XML_Parser parser,
                         const XML_Char *context,
                         const XML_Char *base,
                         const XML_Char *systemId,
-                        const XML_Char *publicId)
+                        const XML_Char *UNUSED_P(publicId))
 {
   XML_Char *s;
   const XML_Char *filename;
@@ -232,11 +236,21 @@ XML_ProcessFile(XML_Parser parser,
                                       ? externalEntityRefFilemap
                                       : externalEntityRefStream);
   if (flags & XML_MAP_FILE) {
+    int filemapRes;
     PROCESS_ARGS args;
     args.retPtr = &result;
     args.parser = parser;
-    if (!filemap(filename, processFile, &args))
+    filemapRes = filemap(filename, processFile, &args);
+    switch (filemapRes) {
+    case 0:
       result = 0;
+      break;
+    case 2:
+      ftprintf(stderr, T("%s: file too large for memory-mapping")
+          T(", switching to streaming\n"), filename);
+      result = processStream(filename, parser);
+      break;
+    }
   }
   else
     result = processStream(filename, parser);
diff --git a/lib-src/expat/xmlwf/xmlwf.c b/lib-src/expat/xmlwf/xmlwf.c
index 4fc77da94..7581c0780 100755
--- a/lib-src/expat/xmlwf/xmlwf.c
+++ b/lib-src/expat/xmlwf/xmlwf.c
@@ -9,6 +9,7 @@
 
 #include "expat.h"
 #include "codepage.h"
+#include "internal.h"  /* for UNUSED_P only */
 #include "xmlfile.h"
 #include "xmltchar.h"
 
@@ -16,10 +17,6 @@
 #include 
 #endif
 
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include 
-#endif
-
 /* This ensures proper sorting. */
 
 #define NSSEP T('\001')
@@ -248,49 +245,49 @@ processingInstruction(void *userData, const XML_Char *target,
 #endif /* not W3C14N */
 
 static void XMLCALL
-defaultCharacterData(void *userData, const XML_Char *s, int len)
+defaultCharacterData(void *userData, const XML_Char *UNUSED_P(s), int UNUSED_P(len))
 {
   XML_DefaultCurrent((XML_Parser) userData);
 }
 
 static void XMLCALL
-defaultStartElement(void *userData, const XML_Char *name,
-                    const XML_Char **atts)
+defaultStartElement(void *userData, const XML_Char *UNUSED_P(name),
+                    const XML_Char **UNUSED_P(atts))
 {
   XML_DefaultCurrent((XML_Parser) userData);
 }
 
 static void XMLCALL
-defaultEndElement(void *userData, const XML_Char *name)
+defaultEndElement(void *userData, const XML_Char *UNUSED_P(name))
 {
   XML_DefaultCurrent((XML_Parser) userData);
 }
 
 static void XMLCALL
-defaultProcessingInstruction(void *userData, const XML_Char *target,
-                             const XML_Char *data)
+defaultProcessingInstruction(void *userData, const XML_Char *UNUSED_P(target),
+                             const XML_Char *UNUSED_P(data))
 {
   XML_DefaultCurrent((XML_Parser) userData);
 }
 
 static void XMLCALL
-nopCharacterData(void *userData, const XML_Char *s, int len)
+nopCharacterData(void *UNUSED_P(userData), const XML_Char *UNUSED_P(s), int UNUSED_P(len))
 {
 }
 
 static void XMLCALL
-nopStartElement(void *userData, const XML_Char *name, const XML_Char **atts)
+nopStartElement(void *UNUSED_P(userData), const XML_Char *UNUSED_P(name), const XML_Char **UNUSED_P(atts))
 {
 }
 
 static void XMLCALL
-nopEndElement(void *userData, const XML_Char *name)
+nopEndElement(void *UNUSED_P(userData), const XML_Char *UNUSED_P(name))
 {
 }
 
 static void XMLCALL
-nopProcessingInstruction(void *userData, const XML_Char *target,
-                         const XML_Char *data)
+nopProcessingInstruction(void *UNUSED_P(userData), const XML_Char *UNUSED_P(target),
+                         const XML_Char *UNUSED_P(data))
 {
 }
 
@@ -434,9 +431,9 @@ metaCharacterData(void *userData, const XML_Char *s, int len)
 static void XMLCALL
 metaStartDoctypeDecl(void *userData,
                      const XML_Char *doctypeName,
-                     const XML_Char *sysid,
-                     const XML_Char *pubid,
-                     int has_internal_subset)
+                     const XML_Char *UNUSED_P(sysid),
+                     const XML_Char *UNUSED_P(pubid),
+                     int UNUSED_P(has_internal_subset))
 {
   XML_Parser parser = (XML_Parser) userData;
   FILE *fp = (FILE *)XML_GetUserData(parser);
@@ -458,7 +455,7 @@ metaEndDoctypeDecl(void *userData)
 static void XMLCALL
 metaNotationDecl(void *userData,
                  const XML_Char *notationName,
-                 const XML_Char *base,
+                 const XML_Char *UNUSED_P(base),
                  const XML_Char *systemId,
                  const XML_Char *publicId)
 {
@@ -480,10 +477,10 @@ metaNotationDecl(void *userData,
 static void XMLCALL
 metaEntityDecl(void *userData,
                const XML_Char *entityName,
-               int  is_param,
+               int  UNUSED_P(is_param),
                const XML_Char *value,
                int  value_length,
-               const XML_Char *base,
+               const XML_Char *UNUSED_P(base),
                const XML_Char *systemId,
                const XML_Char *publicId,
                const XML_Char *notationName)
@@ -558,7 +555,7 @@ unknownEncodingConvert(void *data, const char *p)
 }
 
 static int XMLCALL
-unknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info)
+unknownEncoding(void *UNUSED_P(userData), const XML_Char *name, XML_Encoding *info)
 {
   int cp;
   static const XML_Char prefixL[] = T("windows-");
@@ -594,7 +591,7 @@ unknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info)
 }
 
 static int XMLCALL
-notStandalone(void *userData)
+notStandalone(void *UNUSED_P(userData))
 {
   return 0;
 }
@@ -607,7 +604,7 @@ showVersion(XML_Char *prog)
   const XML_Feature *features = XML_GetFeatureList();
   while ((ch = *s) != 0) {
     if (ch == '/'
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
         || ch == '\\'
 #endif
         )
@@ -634,8 +631,7 @@ static void
 usage(const XML_Char *prog, int rc)
 {
   ftprintf(stderr,
-           T("usage: %s [-n] [-p] [-r] [-s] [-w] [-x] [-d output-dir] "
-             "[-e encoding] file ...\n"), prog);
+           T("usage: %s [-s] [-n] [-p] [-x] [-e encoding] [-w] [-d output-dir] [-c] [-m] [-r] [-t] [file ...]\n"), prog);
   exit(rc);
 }
 
@@ -760,6 +756,12 @@ tmain(int argc, XML_Char **argv)
       parser = XML_ParserCreateNS(encoding, NSSEP);
     else
       parser = XML_ParserCreate(encoding);
+
+    if (! parser) {
+      tperror("Could not instantiate parser");
+      exit(1);
+    }
+
     if (requireStandalone)
       XML_SetNotStandaloneHandler(parser, notStandalone);
     XML_SetParamEntityParsing(parser, paramEntityParsing);
@@ -779,7 +781,7 @@ tmain(int argc, XML_Char **argv)
         const XML_Char * lastDelim = tcsrchr(file, delim[0]);
         if (lastDelim)
           file = lastDelim + 1;
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
         else {
           const XML_Char * winDelim = T("\\");
           lastDelim = tcsrchr(file, winDelim[0]);